Search code examples
javascriptnode.jstypescriptgeometryleaflet

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.

Solution

  • 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