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 
)
extern

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

A spheroid with major axis == minor axis will be treated as a sphere. Pass in a tolerance in spheroid units.

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: