Hide Table of Contents
View Geoprocessing - Point in polygon search sample in sandbox
Geoprocessing - Point in polygon search

Description

You can use the geometry service to determine spatial relationships between two sets of geometries. The query task can also calculate spatial relationships, but the geometry service exposes more relationship types and can be used with geometries that do not come from ArcGIS Server.

For example, this sample finds pizza restaurants from Yahoo! Local within a 3 minute drive of a point that you click. The pizza restaurants are not part of a map service. They are just graphics on the map whose locations come from Yahoo! The drive time polygon is not part of a map service either. It is returned as the result of a geoprocessing service.

Both the pizza restaurants and the drive time polygon are passed to the GeometryService.relation() method. Notice that one of the parameters for this method is the relationship type. In this sample we're looking for restaurants within the drive time polygon. In other words, they satisfy the relationship type esri.tasks.GeometryService.SPATIAL_REL_WITHIN.

You can specify a callback function to which an array of results will be sent. The array contains references to pairs of geometries that satisfied the relationship type. Each item in the array has a graphic1 and graphic2 property, referring to the order in which the graphics were passed to the relation function.

The following lines of code highlights the pizza restaurant that fell inside the drive time polygon.

var relatedGraphic = relations[i].graphic1;dojo.forEach(relations, function(relation) {baseGraphics[relation.geometry1Index].setSymbol(sybmol);});

Note: Another simple way to check whether a point lies within a polygon is to use the Polygon.contains() method.

Code

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>Geometry Service: Relation</title>

    <link rel="stylesheet" href="https://js.arcgis.com/3.20/esri/css/esri.css">

    <style>
      html, body, #mapDiv {
        height: 100%;
        margin: 0;
        padding: 0;
        width: 100%;
      }
      #info {
        bottom: 20px;
        color: #444;
        height: auto;
        font-family: arial;
        left: 20px;
        margin: 5px;
        padding: 10px;
        position: absolute;
        text-align: left;
        width: 200px;
        z-index: 40;
      }
      .label {
        display: inline-block;
        width: 4em;
      }
    </style>

    <script src="https://js.arcgis.com/3.20/"></script>
    <script>
      var map;

      require([
        "dojo/dom", "dojo/_base/array", "dojo/promise/all", "dojo/json",

        "esri/map", "esri/domUtils", "esri/graphic", "esri/graphicsUtils",
        "esri/geometry/Point", "esri/tasks/GeometryService", "esri/tasks/Geoprocessor",
        "esri/tasks/FeatureSet", "esri/tasks/RelationParameters",
        "esri/Color", "esri/symbols/SimpleLineSymbol",
        "esri/symbols/SimpleMarkerSymbol", "esri/symbols/SimpleFillSymbol",
        "esri/config", "esri/request", "dojo/domReady!"
      ], function(
        dom, array, all, JSON,

        Map, domUtils, Graphic, graphicsUtils,
        Point, GeometryService, Geoprocessor,
        FeatureSet, RelationParameters, 
        Color, SimpleLineSymbol, 
        SimpleMarkerSymbol, SimpleFillSymbol, 
        esriConfig, esriRequest
      ) {

        var geoprocessor, geometryService, geometries, baseGraphics;

        map = new esri.Map("mapDiv", {
          basemap: "topo",
          center: [-117.185, 34.052],
          zoom: 13
        });
        map.on("click", mapClicked);

        geometryService = new GeometryService("https://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Geometry/GeometryServer");
        geoprocessor = new Geoprocessor("https://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Network/ESRI_DriveTime_US/GPServer/CreateDriveTimePolygons");
        geoprocessor.setOutSpatialReference({
          wkid: 4326
        });

        esriConfig.defaults.io.corsEnabledServers.push("sampleserver6.arcgisonline.com");

        function mapClicked(evt) {
          geometries = [];
          map.graphics.clear();

          // add a simple marker graphic at the location where the user clicked on the map.
          var pointSymbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CROSS, 22,
            new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([0, 128, 0]), 4));

          var clickPointGraphic = new Graphic(evt.mapPoint, pointSymbol);
          map.graphics.add(clickPointGraphic);

          // use promise/all to monitor when place search and drive time calculation finish
          all({
            poiSearch: executeLocalSearch(clickPointGraphic),
            driveTimes: getDriveTimePolygon(clickPointGraphic)
          }).then(relateGeometries);
        }

        function executeLocalSearch(graphic) {
          // find (up to) 20 pizza restaurants within a the map's current extent
          var params = {
            text: "pizza",
            location: JSON.stringify(graphic.geometry.toJson()),
            bbox: JSON.stringify(map.extent.toJson()),
            maxLocations: 20,
            f: "json"
          };

          return esriRequest({
            url: "//geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find",
            content: params,
            callbackParamName: "callback"
          });
        }

        function showLocations(response) {
          // create a symbol (Red Square) for pizza restaurants
          var pointSymbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_SQUARE, 6,
            new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([0, 0, 0]), 1),
            new Color([255, 0, 0]));

          // add the pizza restaurants to the map
          var results = response.locations;
          baseGraphics = array.map(results, function(r) {
            var graphic = new Graphic(r.feature);
            graphic.setSymbol(pointSymbol);
            return map.graphics.add(graphic);
          });
        }

        function getDriveTimePolygon(graphic) {
          // the graphic representing the selected location is passed onto the GP Task
          var featureSet = new FeatureSet();
          featureSet.features = [graphic];

          var params = {
            "Input_Location": featureSet,
            "Drive_Times": 3
          };
          return geoprocessor.execute(params);
        }

        function showDriveTime(results, messages) {
          var feature = results[0].value.features[0];

          // add the drive time polygon to the map
          var polySymbolRed = new SimpleFillSymbol(
            SimpleLineSymbol.STYLE_SOLID,
            new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
              new Color([0, 0, 0, 1]), 1),
            new Color([255, 0, 0, 0.2]));
          feature.setSymbol(polySymbolRed);
          map.graphics.add(feature);
        }

        function relateGeometries(results) {
          // check that both requests completed successfully
          if ( !results.poiSearch || !results.driveTimes ) {
            alert("Unable to compute point in polygon.");
          }
          showDriveTime(results.driveTimes);
          showLocations(results.poiSearch);
          console.log("baseGraphics", baseGraphics);
          var relationParams = new RelationParameters();
          relationParams.geometries1 = graphicsUtils.getGeometries(baseGraphics);
          relationParams.geometries2 = graphicsUtils.getGeometries(results.driveTimes[0].value.features);
          relationParams.relation = RelationParameters.SPATIAL_REL_WITHIN;

          geometryService.relation(relationParams).then(addRelateResultsToMap);
          // alternatively, could use polygon.contains instead of using the geometry service
        }

        function addRelateResultsToMap(relations) {
          console.log("add relate results", relations);
          // create a Green Square symbol
          var symbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_SQUARE, 8,
            new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,
              new Color([0, 0, 0]), 1),
            new Color([0, 255, 0]));
          // highlight the pizza places that satisfy the spatial relation (WITHIN) against the 3-minute drive time polygon
          array.forEach(relations, function(relation) {
            baseGraphics[relation.geometry1Index].setSymbol(symbol).getDojoShape().moveToFront();
          });
        }
      });
    </script>

  </head>

  <body class="claro">
    <div id="mapDiv"></div>
    <div id="info" class="esriSimpleSlider">
      Click on the map to show Pizza restaurants that are within 3 minute drive time.
    </div>
  </body>
</html>