Geo-fencing in Quick Report App

925
2
Jump to solution
08-14-2017 03:00 PM
KE
by
Occasional Contributor

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.

1 Solution

Accepted Solutions
nakulmanocha
Esri Regular Contributor

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

View solution in original post

2 Replies
nakulmanocha
Esri Regular Contributor

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

KE
by
Occasional Contributor

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;
                        }
                    }‍‍‍‍‍‍‍‍‍‍‍