PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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 gbox.c:283
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition gbox.c:40
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
#define LW_FALSE
Definition liblwgeom.h:108
#define LINETYPE
Definition liblwgeom.h:117
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition lwgeom.c:1087
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
#define POLYGONTYPE
Definition liblwgeom.h:118
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
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...
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.
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
static double ptarray_distance_spheroid(const POINTARRAY *pa1, const POINTARRAY *pa2, const SPHEROID *s, double tolerance, int check_intersection)
#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
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition lwinline.h:193
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition lwinline.h:91
static double distance(double x1, double y1, double x2, double y2)
Definition lwtree.c:1032
uint32_t ngeoms
Definition liblwgeom.h:566
LWGEOM ** geoms
Definition liblwgeom.h:561
uint8_t type
Definition liblwgeom.h:448
GBOX * bbox
Definition liblwgeom.h:444
POINTARRAY * points
Definition liblwgeom.h:469
POINTARRAY * point
Definition liblwgeom.h:457
POINTARRAY ** rings
Definition liblwgeom.h:505
uint32_t nrings
Definition liblwgeom.h:510

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: