PostGIS  2.5.7dev-r@@SVN_REVISION@@

◆ lwgeom_distance_spheroid()

double lwgeom_distance_spheroid ( const LWGEOM lwgeom1,
const LWGEOM lwgeom2,
const SPHEROID spheroid,
double  tolerance 
)

Calculate the distance between two LWGEOMs, using the coordinates are longitude and latitude.

Calculate the geodetic distance from lwgeom1 to lwgeom2 on the spheroid.

Return immediately when the calculated distance drops below the tolerance (useful for dwithin calculations). Return a negative distance for incalculable cases.

Definition at line 2187 of file lwgeodetic.c.

2188 {
2189  uint8_t type1, type2;
2190  int check_intersection = LW_FALSE;
2191  GBOX gbox1, gbox2;
2192 
2193  gbox_init(&gbox1);
2194  gbox_init(&gbox2);
2195 
2196  assert(lwgeom1);
2197  assert(lwgeom2);
2198 
2199  LWDEBUGF(4, "entered function, tolerance %.8g", tolerance);
2200 
2201  /* What's the distance to an empty geometry? We don't know.
2202  Return a negative number so the caller can catch this case. */
2203  if ( lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2) )
2204  {
2205  return -1.0;
2206  }
2207 
2208  type1 = lwgeom1->type;
2209  type2 = lwgeom2->type;
2210 
2211  /* Make sure we have boxes */
2212  if ( lwgeom1->bbox )
2213  gbox1 = *(lwgeom1->bbox);
2214  else
2215  lwgeom_calculate_gbox_geodetic(lwgeom1, &gbox1);
2216 
2217  /* Make sure we have boxes */
2218  if ( lwgeom2->bbox )
2219  gbox2 = *(lwgeom2->bbox);
2220  else
2221  lwgeom_calculate_gbox_geodetic(lwgeom2, &gbox2);
2222 
2223  /* If the boxes aren't disjoint, we have to check for edge intersections */
2224  if ( gbox_overlaps(&gbox1, &gbox2) )
2225  check_intersection = LW_TRUE;
2226 
2227  /* Point/line combinations can all be handled with simple point array iterations */
2228  if ( ( type1 == POINTTYPE || type1 == LINETYPE ) &&
2229  ( type2 == POINTTYPE || type2 == LINETYPE ) )
2230  {
2231  POINTARRAY *pa1, *pa2;
2232 
2233  if ( type1 == POINTTYPE )
2234  pa1 = ((LWPOINT*)lwgeom1)->point;
2235  else
2236  pa1 = ((LWLINE*)lwgeom1)->points;
2237 
2238  if ( type2 == POINTTYPE )
2239  pa2 = ((LWPOINT*)lwgeom2)->point;
2240  else
2241  pa2 = ((LWLINE*)lwgeom2)->points;
2242 
2243  return ptarray_distance_spheroid(pa1, pa2, spheroid, tolerance, check_intersection);
2244  }
2245 
2246  /* Point/Polygon cases, if point-in-poly, return zero, else return distance. */
2247  if ( ( type1 == POLYGONTYPE && type2 == POINTTYPE ) ||
2248  ( type2 == POLYGONTYPE && type1 == POINTTYPE ) )
2249  {
2250  const POINT2D *p;
2251  LWPOLY *lwpoly;
2252  LWPOINT *lwpt;
2253  double distance = FLT_MAX;
2254  uint32_t i;
2255 
2256  if ( type1 == POINTTYPE )
2257  {
2258  lwpt = (LWPOINT*)lwgeom1;
2259  lwpoly = (LWPOLY*)lwgeom2;
2260  }
2261  else
2262  {
2263  lwpt = (LWPOINT*)lwgeom2;
2264  lwpoly = (LWPOLY*)lwgeom1;
2265  }
2266  p = getPoint2d_cp(lwpt->point, 0);
2267 
2268  /* Point in polygon implies zero distance */
2269  if ( lwpoly_covers_point2d(lwpoly, p) )
2270  {
2271  return 0.0;
2272  }
2273 
2274  /* Not inside, so what's the actual distance? */
2275  for ( i = 0; i < lwpoly->nrings; i++ )
2276  {
2277  double ring_distance = ptarray_distance_spheroid(lwpoly->rings[i], lwpt->point, spheroid, tolerance, check_intersection);
2278  if ( ring_distance < distance )
2279  distance = ring_distance;
2280  if ( distance < tolerance )
2281  return distance;
2282  }
2283  return distance;
2284  }
2285 
2286  /* Line/polygon case, if start point-in-poly, return zero, else return distance. */
2287  if ( ( type1 == POLYGONTYPE && type2 == LINETYPE ) ||
2288  ( type2 == POLYGONTYPE && type1 == LINETYPE ) )
2289  {
2290  const POINT2D *p;
2291  LWPOLY *lwpoly;
2292  LWLINE *lwline;
2293  double distance = FLT_MAX;
2294  uint32_t i;
2295 
2296  if ( type1 == LINETYPE )
2297  {
2298  lwline = (LWLINE*)lwgeom1;
2299  lwpoly = (LWPOLY*)lwgeom2;
2300  }
2301  else
2302  {
2303  lwline = (LWLINE*)lwgeom2;
2304  lwpoly = (LWPOLY*)lwgeom1;
2305  }
2306  p = getPoint2d_cp(lwline->points, 0);
2307 
2308  LWDEBUG(4, "checking if a point of line is in polygon");
2309 
2310  /* Point in polygon implies zero distance */
2311  if ( lwpoly_covers_point2d(lwpoly, p) )
2312  return 0.0;
2313 
2314  LWDEBUG(4, "checking ring distances");
2315 
2316  /* Not contained, so what's the actual distance? */
2317  for ( i = 0; i < lwpoly->nrings; i++ )
2318  {
2319  double ring_distance = ptarray_distance_spheroid(lwpoly->rings[i], lwline->points, spheroid, tolerance, check_intersection);
2320  LWDEBUGF(4, "ring[%d] ring_distance = %.8g", i, ring_distance);
2321  if ( ring_distance < distance )
2322  distance = ring_distance;
2323  if ( distance < tolerance )
2324  return distance;
2325  }
2326  LWDEBUGF(4, "all rings checked, returning distance = %.8g", distance);
2327  return distance;
2328 
2329  }
2330 
2331  /* Polygon/polygon case, if start point-in-poly, return zero, else
2332  * return distance. */
2333  if (type1 == POLYGONTYPE && type2 == POLYGONTYPE)
2334  {
2335  const POINT2D* p;
2336  LWPOLY* lwpoly1 = (LWPOLY*)lwgeom1;
2337  LWPOLY* lwpoly2 = (LWPOLY*)lwgeom2;
2338  double distance = FLT_MAX;
2339  uint32_t i, j;
2340 
2341  /* Point of 2 in polygon 1 implies zero distance */
2342  p = getPoint2d_cp(lwpoly1->rings[0], 0);
2343  if (lwpoly_covers_point2d(lwpoly2, p)) return 0.0;
2344 
2345  /* Point of 1 in polygon 2 implies zero distance */
2346  p = getPoint2d_cp(lwpoly2->rings[0], 0);
2347  if (lwpoly_covers_point2d(lwpoly1, p)) return 0.0;
2348 
2349  /* Not contained, so what's the actual distance? */
2350  for (i = 0; i < lwpoly1->nrings; i++)
2351  {
2352  for (j = 0; j < lwpoly2->nrings; j++)
2353  {
2354  double ring_distance =
2356  lwpoly1->rings[i],
2357  lwpoly2->rings[j],
2358  spheroid,
2359  tolerance,
2360  check_intersection);
2361  if (ring_distance < distance)
2362  distance = ring_distance;
2363  if (distance < tolerance) return distance;
2364  }
2365  }
2366  return distance;
2367  }
2368 
2369  /* Recurse into collections */
2370  if ( lwtype_is_collection(type1) )
2371  {
2372  uint32_t i;
2373  double distance = FLT_MAX;
2374  LWCOLLECTION *col = (LWCOLLECTION*)lwgeom1;
2375 
2376  for ( i = 0; i < col->ngeoms; i++ )
2377  {
2378  double geom_distance = lwgeom_distance_spheroid(
2379  col->geoms[i], lwgeom2, spheroid, tolerance);
2380  if ( geom_distance < distance )
2381  distance = geom_distance;
2382  if ( distance < tolerance )
2383  return distance;
2384  }
2385  return distance;
2386  }
2387 
2388  /* Recurse into collections */
2389  if ( lwtype_is_collection(type2) )
2390  {
2391  uint32_t i;
2392  double distance = FLT_MAX;
2393  LWCOLLECTION *col = (LWCOLLECTION*)lwgeom2;
2394 
2395  for ( i = 0; i < col->ngeoms; i++ )
2396  {
2397  double geom_distance = lwgeom_distance_spheroid(lwgeom1, col->geoms[i], spheroid, tolerance);
2398  if ( geom_distance < distance )
2399  distance = geom_distance;
2400  if ( distance < tolerance )
2401  return distance;
2402  }
2403  return distance;
2404  }
2405 
2406 
2407  lwerror("arguments include unsupported geometry type (%s, %s)", lwtype_name(type1), lwtype_name(type1));
2408  return -1.0;
2409 
2410 }
int gbox_overlaps(const GBOX *g1, const GBOX *g2)
Return LW_TRUE if the GBOX overlaps, LW_FALSE otherwise.
Definition: g_box.c:290
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition: g_box.c:47
#define LW_FALSE
Definition: liblwgeom.h:77
#define LINETYPE
Definition: liblwgeom.h:86
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition: lwgeom.c:1093
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
#define POLYGONTYPE
Definition: liblwgeom.h:87
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwgeom.c:1393
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwgeom_api.c:374
int lwpoly_covers_point2d(const LWPOLY *poly, const POINT2D *pt_to_test)
Given a polygon (lon/lat decimal degrees) and point (lon/lat decimal degrees) and a guaranteed outsid...
Definition: lwgeodetic.c:2518
double lwgeom_distance_spheroid(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2, const SPHEROID *spheroid, double tolerance)
Calculate the distance between two LWGEOMs, using the coordinates are longitude and latitude.
Definition: lwgeodetic.c:2187
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
Definition: lwgeodetic.c:3028
static double ptarray_distance_spheroid(const POINTARRAY *pa1, const POINTARRAY *pa2, const SPHEROID *s, double tolerance, int check_intersection)
Definition: lwgeodetic.c:1835
Datum distance(PG_FUNCTION_ARGS)
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
uint32_t ngeoms
Definition: liblwgeom.h:510
LWGEOM ** geoms
Definition: liblwgeom.h:512
uint8_t type
Definition: liblwgeom.h:399
GBOX * bbox
Definition: liblwgeom.h:401
POINTARRAY * points
Definition: liblwgeom.h:425
POINTARRAY * point
Definition: liblwgeom.h:414
POINTARRAY ** rings
Definition: liblwgeom.h:460
uint32_t nrings
Definition: liblwgeom.h:458
unsigned int uint32_t
Definition: uthash.h:78
unsigned char uint8_t
Definition: uthash.h:79

References LWGEOM::bbox, distance(), gbox_init(), gbox_overlaps(), LWCOLLECTION::geoms, getPoint2d_cp(), LINETYPE, LW_FALSE, LW_TRUE, LWDEBUG, LWDEBUGF, lwerror(), lwgeom_calculate_gbox_geodetic(), lwgeom_distance_spheroid(), lwgeom_is_empty(), lwpoly_covers_point2d(), lwtype_is_collection(), lwtype_name(), LWCOLLECTION::ngeoms, LWPOLY::nrings, LWPOINT::point, LWLINE::points, POINTTYPE, POLYGONTYPE, ptarray_distance_spheroid(), LWPOLY::rings, and LWGEOM::type.

Referenced by geography_centroid_from_mline(), geography_distance_knn(), geography_distance_uncached(), geography_dwithin(), geography_dwithin_uncached(), geometry_distance_spheroid(), lwgeom_distance_spheroid(), test_lwgeom_distance_sphere(), test_tree_circ_distance(), and test_tree_circ_distance_threshold().

Here is the call graph for this function:
Here is the caller graph for this function: