Jon
Jon

Reputation: 83

Check if lat / long is within a Nokia HERE Map polygon

Is there a way to determine if a lat / long is within a nokia.maps.map.Polygon?

I can use the method nokiaMap.getObjectsAt to check if there’s a polygon under a given map pixel location but this doesn’t help with a latitude and longitude.

There is a method nokiaMap.geoToPixel which I was thinking of using to get a pixel location and then call nokiaMap.getObjectsAt but the documentation states “result values outside the visible map area are likely to be very unreliable” which I have seen to be the case so can't use this approach.

nokiaMap.geoToPixel documentation http://developer.here.com/docs/maps_js/topics_api_pub/nokia.maps.map.Display.html#topic-apiref__Display-geoToPixel-method

Upvotes: 1

Views: 966

Answers (2)

Noorul
Noorul

Reputation: 949

I wrote a PL/SQL procedure that uses Ray casting algorithm to calculate if the point is in polygon or not. There is no limit on the number of vertices of the polygon. Here, the longitudes and latitudes of vertices and the point to check are submitted in decimal minutes format and are pipe seperated.

create or replace function PIP(verLong in varchar2,
                               verLat  in varchar2,
                               xLong   in number,
                               yLat    in number) return boolean

 is

  i number := 0;

  j number := 0;

  c boolean := false;

  tempLong number;

  tempLat number;

  latDegree number;

  minLength number;

  pi NUMBER := 3.1415926;

  x number := xLong;

  y number := yLat;

  TYPE coodArray IS TABLE OF VARCHAR2(1000) INDEX BY BINARY_INTEGER;

  longArray coodArray;

  latArray coodArray;

begin

  --Convert reference point in meters

  --Round number to 4 places

  x := round(x, 4);

  y := round(y, 4);

  --convert latitude to degrees

  latDegree := y / 60;

  --convert latitude from degrees to radians

  latDegree := (latDegree * pi) / 180;

  --compute minute or arc in meters given the latitude value

  minLength := 1852.3 - (9.4 * Cos(2 * latDegree));

  --Multiply the latitude and longitude pair with the length factor to get co-ordinates in meters

  x := x * minLength;

  y := y * minLength;

  loop

    --Retrieve the longitudes and latitudes from the string of latitudes or longitudes

    tempLong := to_number(get_token(verLong, i + 1, '|'));

    tempLat := to_number(get_token(verLat, i + 1, '|'));

    i := i + 1;

    if (tempLong is null) then

      exit;

    end if;

    --Round the numbers upto four decimals

    tempLong := round(tempLong, 4);

    tempLat := round(tempLat, 4);

    --convert latitude to degrees

    latDegree := tempLat / 60;

    --convert latitude from degrees to radians

    latDegree := (latDegree * pi) / 180;

    --compute the minute of an arc in meters given the latitude value

    minLength := 1852.3 - (9.4 * Cos(2 * latDegree));

    --Multiply the latitude and longitude pair with the length factor to get co-ordinates in meters

    tempLong := tempLong * minLength;

    tempLat := tempLat * minLength;

    longArray(i) := tempLong;

    latArray(i) := tempLat;

  end Loop;

  j := latArray.COUNT;

  --Check whether the point lies inside the polygon formed by the vertices (Ray casting algorithm)

  for i in 1 .. j loop

    if (((latArray(i) > y) != (latArray(j) > y)) and
       (x < (Longarray(j) - Longarray(i)) * (y - Latarray(i)) /
       (latarray(j) - Latarray(i)) + longarray(i))) then

      c := not c;

    end if;

    j := i;

  end loop;

  return c;

end PIP;

Thanks, Noorul

Upvotes: 1

Jason Fox
Jason Fox

Reputation: 5300

This requires an implementation of the point in polygon algorithm from computational geometry. An example of this can be found below:

nokia.maps.map.Polygon.prototype.containsCoordinate = function(arg) {
    var latitude, longitude;

    if (arg instanceof  nokia.maps.geo.Coordinate){
      latitude = arg.latitude;
      longitude = arg.longitude;
    } else if (arg instanceof Array && arg.length === 2 && !isNaN(arg[0]) && !isNaN(arg[1])){
      latitude = arg[0];
      longitude = arg[1];
    }

    // Fail fast if not in the bounding box - don't bother with Ray Cast method
    if (!poly.getBoundingBox().contains(
      nokia.maps.geo.BoundingBox.coverAll(
        [new nokia.maps.geo.Coordinate(latitude, longitude)]))){
      return false;
    }

    var inPoly = false,
      path = this.path,
      numPoints = path.getLength(),
      j = numPoints-1;

      for(var i=0; i < numPoints; i++) {
      var vertex1 = path.getLatLng(i),
        vertex2 = path.getLatLng(j);

        if (vertex1[1] < longitude && vertex2[1] >= longitude ||
          vertex2[1] < longitude && vertex1[1] >= longitude) {
          if (vertex1[0] + (longitude - vertex1[1]) / (vertex2[1] - vertex1[1]) 
             * (vertex2[0] - vertex1[0]) < latitude) {
            inPoly = !inPoly;
          }
        }
        j = i;
      }
    return inPoly;
  };

You can call it using either a Coordinate or a pair of numbers. e.g:

poly.containsCoordinate(coordinate)

Working Example

Upvotes: 2

Related Questions