Mr920X
Mr920X

Reputation: 35

Determine if coordinates is within bounding box

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

Answers (3)

user3481644
user3481644

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

high_breed
high_breed

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

Ripi2
Ripi2

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

Related Questions