Reputation: 83
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
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
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)
Upvotes: 2