I'm trying to limit the Quick Report app so that points can only be collected if they are within a certain geographic area.
I have defined my limiting polygon within the mapView:
ServiceFeatureTable { id: countyBoundary url: "https://hangis.hanoverva.gov/arcgis/rest/services/county_boundary/MapServer" }
I added a geometry check within the nextPage function so it will not allow the user to proceed if the point is not within the polygon:
function nextPage(){
positionSource.active = false;
app.theNewPoint = mapView.currentViewpointCenter.center;
var withinCounty = GeometryEngine.within(app.theNewPoint, countyBoundary)
console.log("withinCounty", withinCounty)
if(withinCounty === true) {
next("");
}
else {
invalidGeometryAlertBox.text = qsTr("Invalid geometry. Point not within Hanover County.")
invalidGeometryAlertBox.visible = true;
}
}
The problem is I keep getting false for withinCounty, even when the point is within the county boundary.
Solved! Go to Solution.
Hi Kristen,
There are couple of issues here
1) You need to end the url with "/0" for the ServiceFeatureTable where 0 represents the layer id
ServiceFeatureTable {
id: countyBoundary
url: "https://hangis.hanoverva.gov/arcgis/rest/services/county_boundary/MapServer/0"
}
2) GeometryEngine compares two geometries for the within operation . The countyBoundary is a layerid but you need a feature geometry within the first layer of the countyBoundary.
There are two ways to get this resolved
Faster approach (but not perfect) - Use the extent of the layer. Since your layer has only one feature you could do that. Remember extent is a rectangular envelope surrounding the actual feature geometry
GeometryEngine.within(app.theNewPoint, countyBoundary.extent)
Second approach (should give perfect results) - Is to get the first feature of the layer. From the feature you get the geometry which you should use for the GeometryEngine. In order to get the first feature you need to perform query (set where clause as "1=1" ). The result will have the Featureset and from that you can get the first feature. For more help on how to get the feature please see our FeatureLayer query sample . If you still need help with this please create a support issue and they will be able to help you further.
Thanks,
Nakul
Hi Kristen,
There are couple of issues here
1) You need to end the url with "/0" for the ServiceFeatureTable where 0 represents the layer id
ServiceFeatureTable {
id: countyBoundary
url: "https://hangis.hanoverva.gov/arcgis/rest/services/county_boundary/MapServer/0"
}
2) GeometryEngine compares two geometries for the within operation . The countyBoundary is a layerid but you need a feature geometry within the first layer of the countyBoundary.
There are two ways to get this resolved
Faster approach (but not perfect) - Use the extent of the layer. Since your layer has only one feature you could do that. Remember extent is a rectangular envelope surrounding the actual feature geometry
GeometryEngine.within(app.theNewPoint, countyBoundary.extent)
Second approach (should give perfect results) - Is to get the first feature of the layer. From the feature you get the geometry which you should use for the GeometryEngine. In order to get the first feature you need to perform query (set where clause as "1=1" ). The result will have the Featureset and from that you can get the first feature. For more help on how to get the feature please see our FeatureLayer query sample . If you still need help with this please create a support issue and they will be able to help you further.
Thanks,
Nakul
Thank you Nakul! I got it working, here is my code in case it helps others. Any suggestions for code cleanup are welcome.
I put my ServiceFeatureTable and QueryParameter objects right outside of the map view.
//Feature service for spatial query
ServiceFeatureTable {
id: countyBoundary
url: "https://hangis.hanoverva.gov/arcgis/rest/services/county_boundary/MapServer/0"
onQueryFeaturesStatusChanged: {
if (queryFeaturesStatus === Enums.TaskStatusCompleted) {
if (!queryFeaturesResult.iterator.hasNext) {
errorMsgDialog.visible = true;
return;
}
//Create array for features
var features = []
// get the features
while (queryFeaturesResult.iterator.hasNext) {
features.push(queryFeaturesResult.iterator.next());
}
//Since there is only one feature get the feature at the first index & retrieve geometry property
var countyGeometry = features[0].geometry
console.log("countyGeometry", countyGeometry)
//Get the current map point
var newPoint = mapView.currentViewpointCenter.center
console.log("newPoint", newPoint)
//Check to see if currrent point is within county boundary
var withinCounty = GeometryEngine.within(newPoint, countyGeometry)
console.log("withinCounty", withinCounty)
//If the point is within the county boundary, run nextPage function
if(withinCounty === true) {
nextPage();
}
//If not show alert box and do not continue to next page
else {
invalidGeometryAlertBox.text = qsTr("Invalid entry.");
invalidGeometryAlertBox.informativeText = qsTr("User must be within county boundary.")+"\n";
invalidGeometryAlertBox.visible = true;
}
}
}
}
//Parameters for query
QueryParameters {
id: queryParameters
//Query the first feature in the feature service
whereClause: "1=1"
//Whether feature geometries are returned in the result
returnGeometry: true
}
Then I edited the Next button, so it runs the query instead of going straight to the next page:
onClicked: {
if(app.captureType=="point") {
//Run query to do geometry check
countyBoundary.queryFeatures(queryParameters);
} else {
invalidGeometryAlertBox.text = qsTr("Invalid geometry. Continue?");
invalidGeometryAlertBox.informativeText = qsTr("You can always save as draft and edit later.")+"\n";
invalidGeometryAlertBox.visible = true;
}
}