16

I need to be able to calculate a bounding box or circle for a given WGS84 latitude and WGS84 longitude, and distance but have no idea where to start!

The distance from the start Lat/Lon would be 10Km or less.

Would it be possible for someone to give me some pointers / Example on how to do this

5
  • For circles that do not cover either pole, a detailed answer is given at gis.stackexchange.com/questions/19221/…. But this isn't the full story, as the current replies suggest: you can make speed-accuracy-program complexity tradeoffs. Note, too, that there is a "wrap-around" problem in specifying bounding boxes when you work in lat-lon (the difficulties occur at the +-180 degree meridian). For a solution to this, see gis.stackexchange.com/questions/17788/….
    – whuber
    Feb 3, 2012 at 20:19
  • Do you really need a box, or would 4 points near a given point be sufficient? Given a point p, find 4 points d distance at directions NE, SW, SE, and NW from p. Feb 6, 2012 at 19:27
  • @Kirk - If you have the coordinates of the 4 points, then you have the box... Feb 6, 2012 at 19:30
  • @martinstoeckli right, I was just hoping to simplify the problem by not having to visualize what a box projected onto a sphere looks like. Note also the problem could be generalized to make it clear that the sides of the box are not required to fall on the same latitude/longitude (a rotated box in other words). Feb 6, 2012 at 19:36
  • @Kirk - Ahh well, if you need it that exactly, then you are right of course. I think the box is only useful to find the possible candidates quickly. To check if two points are within a certain distance (circle), the more complex haversine formula can be used. Feb 6, 2012 at 19:51

4 Answers 4

15

WGS-what? WGS-84? Depending on what accuracy you need, you may need to know a lot more information - my guess is that's why you've been down voted, though no-one bothered to leave a comment saying why.

Here are two ways:

Inaccurate, but probably 'good enough'

One degree of latitude is approximately 10001.965729/90 kilometres (distance from the equator to the pole, divided by ninety degrees) or 111.113 kilometres, using the WGS-84 datum. This is an approximation because of the shape of the earth, and because distances change as you approach the poles (one reason to use latitude, not longitude - eventually the distance of one degree of longitude is zero!) The earth is also not a perfect sphere. Both these are reasons to use a more complex projection- and datum-based approach, in my second answer.

10001.965729km = 90 degrees
1km = 90/10001.965729 degrees = 0.0089982311916 degrees
10km = 0.089982311915998 degrees

This is using decimal degrees, not degrees / minutes / seconds.

So, your bounding box will be your point, plus and minus 0.08999 degrees. Alternatively you could use this number as a radius, giving you a bounding circle.

Any GIS person reading this will shudder. It will be mostly accurate, though, depending where you are in the world. For a 10km radius it should be fine.

Much more accurate, but more code

Use a projection library and specify your datum, etc. I recommend Proj4; it's widely used so Google returns heaps of results for questions about it, and there are Delphi wrappers. If you have trouble using it, post another question here on SO - it's out of scope for this one. The Proj4 website has examples using the basic APIs, and although these are in C it should be fairly easily translatable. Their API reference is the best place to start, followed by the FAQ.

I'd use WGS-84 as a basic datum (representation of the earth) unless you know a specific one you want to use, or that was used for creating your coordinates. It's commonly used and pretty accurate.

If your position comes from Google Maps (for example), specify a Mercator projection. You may want to use another projection, or use, say, UTM coordinates instead of latitude and longitude, depending on the source of your data and if you want high accuracy for a small local area. (UTM has multiple zones, all of which change the distortion so that within that zone, it's highly accurate; if you use a zone for coordinates outside it the distortion will greatly increase as you move away. If you view the whole earth projected from one zone, it might ben unrecognisable. But within a zone, UTM translations will be about as good as you can get. Coordinates are generally specified in meters, not in degrees, so it may be more useful for your you, given you need a 10km radius. 10km is easily within a single zone, you just need to choose the appropriate zone based on your centre coordinate. The only tricky bit is when you approach a border: it's a common situation, and it's fine, just be consistent in how you choose which one you use. Proj4 will also let you translate projections, so you can go from your Mercator WGS-84 lat/long to a UTM zone n, for example, or to and from two UTM zones.)

2
  • 2
    For where we live, a surveyor once told me he uses 1 degree approximately equals 108 km for his mental calculations. Mentally 10 km is roughly 0.1 degree. As these are rough approximations best to treat them accurate to 1 significant digit (2 or 3 at most) rather than 0.089982311915998 as that implies a level of precision. Feb 5, 2012 at 22:06
  • 1
    It's really not difficult to calculate the degrees more accurate, taking the latitude into account. Since the computer makes the calculation, there is nothing gained with an approximation (see the first function in my example). Feb 6, 2012 at 19:09
3

Assuming you want to make a query in a database, you probably want to make a fast (inaccurate) search, and afterwards calculating the distance for the resulting places exactly. Is that your scenario?

The following function (in PHP, sorry) will roughly calculate the differences in latitude and longitude. This differences depend on the latitude of your search point. Use them (with a small tolerance) to make a fast search in the database. The box can be calculated simply with latitude+-deltaLatitude and longitude+-deltaLongitude.

deltaLatitude[rad] = distance[m] / earthRadius[m]
deltaLongitude[rad] = distance[m] / (cos(latitude[rad]) * $earthRadius[m])

/**
 * Calculates the deltas in latitude and longitude to use, for a db search
 * around a location in the database.
 * @param float $distance Radius to use for the search [m]
 * @param float $latitude Latitude of the location, we need the angle deltas for [deg decimal]
 * @param float $deltaLatitude Calculated delta in latitude [deg]
 * @param float $deltaLongitude Calculated delta in longitude [deg]
 * @param float $earthRadius Mean earth radius in [m]
 */
public static function angleFromSphericDistance($distance, $latitude,
  &$deltaLatitude, &$deltaLongitude, $earthRadius = 6371000)
{
  $lat = deg2rad($latitude);

  $radiusOnLatitude = cos($lat) * $earthRadius;
  $deltaLatitude = $distance / $earthRadius;
  $deltaLongitude = $distance / $radiusOnLatitude;

  $deltaLatitude = rad2deg($deltaLatitude);
  $deltaLongitude = rad2deg($deltaLongitude);
}

With the haversine formula, you can calculate distances on the sphere. Use it for each of the found places, to get the "exact" distance. This way you can test, if the two places are within a certain radius (a circle instead of the box).

/**
 * Calculates the great-circle distance between two points, with
 * the Haversine formula.
 * @param float $latitudeFrom Latitude of start point in [deg decimal]
 * @param float $longitudeFrom Longitude of start point in [deg decimal]
 * @param float $latitudeTo Latitude of target point in [deg decimal]
 * @param float $longitudeTo Longitude of target point in [deg decimal]
 * @param float $earthRadius Mean earth radius in [m]
 * @return float Distance between points in [m] (same as earthRadius)
 */
public static function haversineGreatCircleDistance(
  $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
  // convert from degrees to radians
  $latFrom = deg2rad($latitudeFrom);
  $lonFrom = deg2rad($longitudeFrom);
  $latTo = deg2rad($latitudeTo);
  $lonTo = deg2rad($longitudeTo);

  $latDelta = $latTo - $latFrom;
  $lonDelta = $lonTo - $lonFrom;

  $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
    cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
  return $angle * $earthRadius;
}
3

To test whether a lat/lon is within or outside a bounding circle, you need to compute the distance from your reference lat/lon to the lat/lon point you wish to test. Since your distance is 10km or less, I would try using the Equirectangular approximation to get the distance rather than Haversine because of simplicity. To get the distance in km:

x = (lonRef - lon) * cos ( latRef )
y = latRef - lat
distance = EarthRadius * sqrt( x*x + y*y )

Important note: lat/lon in these formula are in radians not degrees. Typical value of EarthRadius is 6371 km which will return distance in units of km. Now it is a simple test if your distance is within or outside the circle. If a bounding circle works, I would go with that.

For a bounding rectangle, I would assume you want the rectangle defined by being parallel to the equator. I would then compute the corners of the bounding box using range/bearing calculations (bearings being 45 deg, 135 deg, 225 deg and 315 deg). From there, I would assume your are not around the poles and use a point in polygon test.

2

Below is T-SQL code that I use for building bounding box in SQL-Server 2012. In my case I get decimal values for Lat, Long. I use this to quickly limit number of rows before I use SQL STDistance function to verify that results are actually within particular distance. Geography functions are very costly in SQL Server thus by building bounding box I'm able to greatly reduce number of times it has to be executed.

DECLARE @Lat DECIMAL(20, 13) = 35.7862
   ,@Long DECIMAL(20, 13) = -80.3095
   ,@Radius DECIMAL(7, 2) = 5
   ,@Distance DECIMAL(10, 2)
   ,@Earth_Radius INT = 6371000;

SET @Distance = @Radius * 1609.344;

DECLARE @NorthLat DECIMAL(20, 13) = @Lat + DEGREES(@distance / @Earth_Radius)
   ,@SouthLat DECIMAL(20, 13) = @Lat - DEGREES(@distance / @Earth_Radius)
   ,@EastLong DECIMAL(20, 13) = @Long + DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)))
   ,@WestLong DECIMAL(20, 13) = @Long - DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)));

SELECT *
    FROM CustomerPosition AS cp
    WHERE (
            cp.Lat >= @SouthLat
            AND cp.Lat <= @NorthLat )
        AND (
              cp.Long >= @WestLong
              AND cp.Long <= @EastLong )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.