PostGIS  2.4.9dev-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 calulated distance drops below the tolerance (useful for dwithin calculations). Return a negative distance for incalculable cases.

Definition at line 2183 of file lwgeodetic.c.

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_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(), geography_distance_knn(), geography_distance_uncached(), geography_dwithin(), geography_dwithin_uncached(), geometry_distance_spheroid(), test_lwgeom_distance_sphere(), test_tree_circ_distance(), and test_tree_circ_distance_threshold().

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