Search code examples
javascriptopenlayers-5

Open Layers 5 containsXY not working. Check if a coordinate is in Polygon


I'm trying to check if a point is within a Polygon. This is my function:

import { containsXY } from 'ol/extent';

isInside(polygon, longitude, latitude) {
    polygon = JSON.parse(polygon); // Polygon is originally = JSON.stringify([[long1, lat1],[long2, lat2], ...])

    let poli = new Polygon(polygon);

    // Try 1: Not working
    console.log("Result --> ", containsXY(poli, latitude, longitude));
    console.log("Result --> ", containsXY(poli, longitude, latitude));
    console.log("Result --> ", containsXY(poli.getExtent(), latitude, longitude));
    console.log("Result --> ", containsXY(poli.getExtent(), longitude, latitude));

    // Try 2: Not working
    let coordinate = this.to3857([longitude, latitude]);
    console.log("Result --> ", containsXY(poli, coordinate[0],  coordinate[1]));
    console.log("Result --> ", containsXY(poli, coordinate[1], coordinate[0]));
    console.log("Result --> ", containsXY(poli.getExtent(), coordinate[0], coordinate[1]));
    console.log("Result --> ", containsXY(poli.getExtent(), coordinate[1], coordinate[0]));

    // Try 3: Not working
    coordinate = this.to4326([longitude, latitude]);
    console.log("Result --> ", containsXY(poli, coordinate[0], coordinate[1]));
    console.log("Result --> ", containsXY(poli, coordinate[1], coordinate[0]));
    console.log("Result --> ", containsXY(poli.getExtent(), coordinate[0], coordinate[1]));
    console.log("Result --> ", containsXY(poli.getExtent(), coordinate[1], coordinate[0]));
}

All results are false. How could I check if a coordinate is in Polygon? Nothing worked for me with OpenLayers API.

Thanks in advance


Solution

  • To determine if a Point geometry is in the Polygon's bounds/extent use:

    ol.extent.containsXY(polygon.getExtent(), coordinate[0], coordinate[1])
    

    updated isInside function:

    function isInside(polygon, longitude, latitude) {
      let coordinate = ol.proj.fromLonLat([longitude, latitude]);
      console.log("Result (in bounds) --> ", ol.extent.containsXY(polygon.getExtent(), coordinate[0], coordinate[1]));
    }
    

    To determine if a Point geometry is inside the Polygon's (which is different from being inside the Polygon's bounds/extent) use (from the related question: Check if a point is inside polygon in OpenLayers 3):

    polygon.intersectsCoordinate(coordinate);
    

    updated isInside function:

    function isInside(polygon, longitude, latitude) {
        let coordinate = ol.proj.fromLonLat([longitude, latitude]);
        console.log("Result (in polygon) --> ", polygon.intersectsCoordinate(coordinate));
    }                    
    

    example

    screenshot of marker inside polygon bounds but outside of polygon

    screenshot of marker inside polygon itself

    code snippet:

    function isInside(polygon, longitude, latitude, text) {
      let coordinate = ol.proj.fromLonLat([longitude, latitude]);
      console.log("Result for " + text + " (in bounds) --> ", ol.extent.containsXY(polygon.getExtent(), coordinate[0], coordinate[1]));
      console.log("Result for " + text + " (in polygon) --> ", polygon.intersectsCoordinate(coordinate));
    }
    
    window.onload = function() {
      isInside(polygon, 106.8060388, -6.5971469, "black marker");
      isInside(polygon, 105.998544, -7.0553, "blue marker");
    }
    
    var map = new ol.Map({
      layers: [
        new ol.layer.Tile({ // TileLayer({
          source: new ol.source.OSM()
        })
      ],
      target: 'map',
      view: new ol.View({
        center: ol.proj.fromLonLat([106.044189, -6.840865]),
        zoom: 7
      })
    });
    
    // modified from https://stackoverflow.com/questions/27210362/open-layers-3-how-to-draw-a-polygon-programmatically
    var jsonData = [{
        lat: -5.896423,
        lng: 106.044189
      },
      {
        lat: -6.840865,
        lng: 105.192749
      },
      //{lat: -6.147714, lng: 106.972534},
      {
        lat: -6.813594,
        lng: 106.016724
      },
      {
        lat: -6.988102,
        lng: 106.516601
      },
      {
        lat: -7.36416,
        lng: 106.406738
      },
      {
        lat: -7.511228,
        lng: 107.450439
      },
      {
        lat: -6.093095,
        lng: 106.989014
      }
    ]
    // A ring must be closed, that is its last coordinate
    // should be the same as its first coordinate.
    var ring = [];
    for (var i = 0; i < jsonData.length; i++) {
      ring.push([jsonData[i].lng, jsonData[i].lat]);
    }
    // A polygon is an array of rings, the first ring is
    // the exterior ring, the others are the interior rings.
    // In your case there is one ring only.
    var polygon = new ol.geom.Polygon([ring]);
    polygon.transform('EPSG:4326', 'EPSG:3857');
    
    // Create feature with polygon.
    var feature = new ol.Feature(polygon);
    feature.set('name', 'polygon');
    
    // Create vector source and the feature to it.
    var vectorSource = new ol.source.Vector();
    vectorSource.addFeature(feature);
    
    // Create vector layer attached to the vector source.
    var vectorLayer = new ol.layer.Vector({
      source: vectorSource
    });
    
    // Add the vector layer to the map.
    map.addLayer(vectorLayer);
    
    var geoMarker = new ol.Feature({
      type: 'geoMarker',
      name: 'insidePolygon',
      geometry: new ol.geom.Point(ol.proj.fromLonLat([106.8060388, -6.5971469]))
    });
    geoMarker.setStyle(new ol.style.Style({
      image: new ol.style.Circle({ //CircleStyle({
        radius: 7,
        snapToPixel: false,
        fill: new ol.style.Fill({
          color: 'black'
        }),
        stroke: new ol.style.Stroke({
          color: 'black',
          width: 2
        })
      })
    }));
    
    vectorSource.addFeature(geoMarker);
    var geoMarker1 = new ol.Feature({
      type: 'geoMarker',
      name: 'outsidePolygon',
      geometry: new ol.geom.Point(ol.proj.fromLonLat([105.998544, -7.0553]))
    });
    geoMarker1.setStyle(new ol.style.Style({
      image: new ol.style.Circle({ //CircleStyle({
        radius: 7,
        snapToPixel: false,
        fill: new ol.style.Fill({
          color: 'blue'
        }),
        stroke: new ol.style.Stroke({
          color: 'blue',
          width: 2
        })
      })
    }));
    
    vectorSource.addFeature(geoMarker1);
    
    var tooltip = document.getElementById('tooltip');
    var overlay = new ol.Overlay({
      element: tooltip,
      offset: [10, 0],
      positioning: 'bottom-left'
    });
    map.addOverlay(overlay);
    
    function displayTooltip(evt) {
      var pixel = evt.pixel;
      var feature = map.forEachFeatureAtPixel(pixel, function(feature) {
        return feature;
      });
      tooltip.style.display = feature ? '' : 'none';
      if (feature) {
        overlay.setPosition(evt.coordinate);
        tooltip.innerHTML = feature.get('name');
      }
    };
    
    map.on('pointermove', displayTooltip);
    html,
    body {
      height: 100%;
      width: 100%;
      padding: 0px;
      margin: 0px;
    }
    
    .map {
      height: 100%;
      width: 100%;
    }
    <link rel="stylesheet" href="https://openlayers.org/en/v5.1.3/css/ol.css" type="text/css">
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.1.3/build/ol.js"></script>
    <div id="map" class="map"></div>
    <div id="tooltip"></div>