Reputation: 35
I need to create a function that, given a
, b
and c
returns a boolean indicating if c
is within a
and b
.
All variables have the following type:
type Coordinate = {
lat: number;
lon: number;
};
I've came up with a solution that initially I though was correctly, but after testing with Google Maps, I find out it's wrong.
The function:
function inBoundingBox(
bottomLeft: Coordinate,
topRight: Coordinate,
point: Coordinate
) {
let isLongInRange: boolean;
if (topRight.lon < bottomLeft.lon) {
isLongInRange = point.lon >= bottomLeft.lon || point.lon <= topRight.lon;
} else {
isLongInRange = point.lon >= bottomLeft.lon && point.lon <= topRight.lon;
}
return (
point.lat >= bottomLeft.lat && point.lat <= topRight.lat && isLongInRange
);
}
One example that should work:
const topRight: Coordinate = {
lat: -23.5273,
lon: -46.833881
};
const bottomLeft: Coordinate = {
lat: -23.537519,
lon: -46.840019
};
const point = {
lat: -23.52785,
lon: -46.840545
};
const result = inBoundingBox(bottomLeft, topRight, point);
console.log(result) // false, where should be true.
And a visual representation is here.
I need help to find out where exactly the code is wrong, and how to fix it.
I also tried to use Leaflet to see if it works, but the result is the same:
function leafletContains(bottomLeft, topRight, pos) {
var bounds = new L.LatLngBounds(
new L.LatLng(bottomLeft.lat, bottomLeft.lon),
new L.LatLng(topRight.lat, topRight.lon)
);
return bounds.contains(new L.LatLng(pos.lat, pos.lon));
}
leafLetContains({ lat: -23.537519, lon: -46.840019 }, { lat: -23.5273, lon: -46.833881 }, { lat: -23.527811, lon: -46.840201 }) // false, where should be true.
Upvotes: 2
Views: 3976
Reputation: 440
One comment mentioned the edge case of the bounding box crossing the equator, and also date lines, where latitude and/or longitude coordinates change sign. My solution will "move" the bounding box off of those lines and also move the point as well. At this point in the problem, it is not a matter of is the point over a particular location, but is it within the box.
For example, if the box is N "units" (radians or DMS) below the equator, then "move" the box up by N units and also the point, then do the math.
And, yes, I know that moving a bounding box on the surface of a sphere changes its physical size, but that is not the point at this time. The question is: Is BB-LL-lat < Point-lat < BB-UR-lat? And similar for longitude. Adjusting the coordinate system does not affect the math relationship, despite changes in physical dimension when projected on to the Earth. The question is NOT "what is the distance?", it IS "Is the point between the lines?"
Upvotes: 0
Reputation: 61
this line is wrong
else {
isLongInRange = point.lon >= bottomLeft.lon && point.lon <= topRight.lon;
}
Has to be ||
instead of &&
and one of the following: switch around
the >=
and <=
or switch palces of bottomLeft.lon
and topRight.lon
else {
isLongInRange = point.lon <= bottomLeft.lon || point.lon >= topRight.lon;
}
Upvotes: 1
Reputation: 7198
A bounding box test must check the four sides of the box.
A box in the surface of a sphere is not a rectangle, so it's hard to work with x,y coordinates. But with "polar" coordinates (lat, lon) it's a lot easy:
I'm not a javascript coder, so forgive my mistakes in this code:
function inBoundingBox(
bottomLeft: Coordinate,
topRight: Coordinate,
point: Coordinate
) {
let isLongInRange: boolean;
let isLatiInRange: boolean;
isLongInRange = point.lon >= bottomLeft.lon && point.lon <= topRight.lon;
isLatiInRange = point.lat >= bottomLeft.lat && point.lat <= topRight.lat;
return ( isLongInRange && isLatiInRange );
}
assuming bottomLeft.lon < topRight.lon
and bottomLeft.lat < topRight.lat
Upvotes: 4