PostGIS 3.7.0dev-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 2066 of file lwgeodetic.c.

2067{
2068 uint8_t type1, type2;
2069 int check_intersection = LW_FALSE;
2070 GBOX gbox1, gbox2;
2071
2072 gbox_init(&gbox1);
2073 gbox_init(&gbox2);
2074
2075 assert(lwgeom1);
2076 assert(lwgeom2);
2077
2078 LWDEBUGF(4, "entered function, tolerance %.8g", tolerance);
2079
2080 /* What's the distance to an empty geometry? We don't know.
2081 Return a negative number so the caller can catch this case. */
2082 if ( lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2) )
2083 {
2084 return -1.0;
2085 }
2086
2087 type1 = lwgeom1->type;
2088 type2 = lwgeom2->type;
2089
2090 /* Make sure we have boxes */
2091 if ( FLAGS_GET_GEODETIC(lwgeom1->flags) && lwgeom1->bbox )
2092 gbox1 = *(lwgeom1->bbox);
2093 else
2094 lwgeom_calculate_gbox_geodetic(lwgeom1, &gbox1);
2095
2096 /* Make sure we have boxes */
2097 if ( FLAGS_GET_GEODETIC(lwgeom2->flags) && lwgeom2->bbox )
2098 gbox2 = *(lwgeom2->bbox);
2099 else
2100 lwgeom_calculate_gbox_geodetic(lwgeom2, &gbox2);
2101
2102 /* If the boxes aren't disjoint, we have to check for edge intersections */
2103 if ( gbox_overlaps(&gbox1, &gbox2) )
2104 check_intersection = LW_TRUE;
2105
2106 /* Point/line combinations can all be handled with simple point array iterations */
2107 if ( ( type1 == POINTTYPE || type1 == LINETYPE ) &&
2108 ( type2 == POINTTYPE || type2 == LINETYPE ) )
2109 {
2110 POINTARRAY *pa1, *pa2;
2111
2112 if ( type1 == POINTTYPE )
2113 pa1 = ((LWPOINT*)lwgeom1)->point;
2114 else
2115 pa1 = ((LWLINE*)lwgeom1)->points;
2116
2117 if ( type2 == POINTTYPE )
2118 pa2 = ((LWPOINT*)lwgeom2)->point;
2119 else
2120 pa2 = ((LWLINE*)lwgeom2)->points;
2121
2122 return ptarray_distance_spheroid(pa1, pa2, spheroid, tolerance, check_intersection);
2123 }
2124
2125 /* Point/Polygon cases, if point-in-poly, return zero, else return distance. */
2126 if ( ( type1 == POLYGONTYPE && type2 == POINTTYPE ) ||
2127 ( type2 == POLYGONTYPE && type1 == POINTTYPE ) )
2128 {
2129 const POINT2D *p;
2130 LWPOLY *lwpoly;
2131 LWPOINT *lwpt;
2132 double distance = FLT_MAX;
2133 uint32_t i;
2134
2135 if ( type1 == POINTTYPE )
2136 {
2137 lwpt = (LWPOINT*)lwgeom1;
2138 lwpoly = (LWPOLY*)lwgeom2;
2139 }
2140 else
2141 {
2142 lwpt = (LWPOINT*)lwgeom2;
2143 lwpoly = (LWPOLY*)lwgeom1;
2144 }
2145 p = getPoint2d_cp(lwpt->point, 0);
2146
2147 /* Point in polygon implies zero distance */
2148 if ( lwpoly_covers_point2d(lwpoly, p) )
2149 {
2150 return 0.0;
2151 }
2152
2153 /* Not inside, so what's the actual distance? */
2154 for ( i = 0; i < lwpoly->nrings; i++ )
2155 {
2156 double ring_distance = ptarray_distance_spheroid(lwpoly->rings[i], lwpt->point, spheroid, tolerance, check_intersection);
2157 if ( ring_distance < distance )
2158 distance = ring_distance;
2159 if ( distance <= tolerance )
2160 return distance;
2161 }
2162 return distance;
2163 }
2164
2165 /* Line/polygon case, if start point-in-poly, return zero, else return distance. */
2166 if ( ( type1 == POLYGONTYPE && type2 == LINETYPE ) ||
2167 ( type2 == POLYGONTYPE && type1 == LINETYPE ) )
2168 {
2169 const POINT2D *p;
2170 LWPOLY *lwpoly;
2171 LWLINE *lwline;
2172 double distance = FLT_MAX;
2173 uint32_t i;
2174
2175 if ( type1 == LINETYPE )
2176 {
2177 lwline = (LWLINE*)lwgeom1;
2178 lwpoly = (LWPOLY*)lwgeom2;
2179 }
2180 else
2181 {
2182 lwline = (LWLINE*)lwgeom2;
2183 lwpoly = (LWPOLY*)lwgeom1;
2184 }
2185 p = getPoint2d_cp(lwline->points, 0);
2186
2187 LWDEBUG(4, "checking if a point of line is in polygon");
2188
2189 /* Point in polygon implies zero distance */
2190 if ( lwpoly_covers_point2d(lwpoly, p) )
2191 return 0.0;
2192
2193 LWDEBUG(4, "checking ring distances");
2194
2195 /* Not contained, so what's the actual distance? */
2196 for ( i = 0; i < lwpoly->nrings; i++ )
2197 {
2198 double ring_distance = ptarray_distance_spheroid(lwpoly->rings[i], lwline->points, spheroid, tolerance, check_intersection);
2199 LWDEBUGF(4, "ring[%d] ring_distance = %.8g", i, ring_distance);
2200 if ( ring_distance < distance )
2201 distance = ring_distance;
2202 if ( distance <= tolerance )
2203 return distance;
2204 }
2205 LWDEBUGF(4, "all rings checked, returning distance = %.8g", distance);
2206 return distance;
2207
2208 }
2209
2210 /* Polygon/polygon case, if start point-in-poly, return zero, else
2211 * return distance. */
2212 if (type1 == POLYGONTYPE && type2 == POLYGONTYPE)
2213 {
2214 const POINT2D* p;
2215 LWPOLY* lwpoly1 = (LWPOLY*)lwgeom1;
2216 LWPOLY* lwpoly2 = (LWPOLY*)lwgeom2;
2217 double distance = FLT_MAX;
2218 uint32_t i, j;
2219
2220 /* Point of 2 in polygon 1 implies zero distance */
2221 p = getPoint2d_cp(lwpoly1->rings[0], 0);
2222 if (lwpoly_covers_point2d(lwpoly2, p)) return 0.0;
2223
2224 /* Point of 1 in polygon 2 implies zero distance */
2225 p = getPoint2d_cp(lwpoly2->rings[0], 0);
2226 if (lwpoly_covers_point2d(lwpoly1, p)) return 0.0;
2227
2228 /* Not contained, so what's the actual distance? */
2229 for (i = 0; i < lwpoly1->nrings; i++)
2230 {
2231 for (j = 0; j < lwpoly2->nrings; j++)
2232 {
2233 double ring_distance =
2235 lwpoly1->rings[i],
2236 lwpoly2->rings[j],
2237 spheroid,
2238 tolerance,
2239 check_intersection);
2240 if (ring_distance < distance)
2241 distance = ring_distance;
2242 if (distance <= tolerance) return distance;
2243 }
2244 }
2245 return distance;
2246 }
2247
2248 /* Recurse into collections */
2249 if ( lwtype_is_collection(type1) )
2250 {
2251 uint32_t i;
2252 double distance = FLT_MAX;
2253 LWCOLLECTION *col = (LWCOLLECTION*)lwgeom1;
2254
2255 for ( i = 0; i < col->ngeoms; i++ )
2256 {
2257 double geom_distance = lwgeom_distance_spheroid(
2258 col->geoms[i], lwgeom2, spheroid, tolerance);
2259 if ( geom_distance < distance )
2260 distance = geom_distance;
2261 if ( distance <= tolerance )
2262 return distance;
2263 }
2264 return distance;
2265 }
2266
2267 /* Recurse into collections */
2268 if ( lwtype_is_collection(type2) )
2269 {
2270 uint32_t i;
2271 double distance = FLT_MAX;
2272 LWCOLLECTION *col = (LWCOLLECTION*)lwgeom2;
2273
2274 for ( i = 0; i < col->ngeoms; i++ )
2275 {
2276 double geom_distance = lwgeom_distance_spheroid(lwgeom1, col->geoms[i], spheroid, tolerance);
2277 if ( geom_distance < distance )
2278 distance = geom_distance;
2279 if ( distance <= tolerance )
2280 return distance;
2281 }
2282 return distance;
2283 }
2284
2285
2286 lwerror("arguments include unsupported geometry type (%s, %s)", lwtype_name(type1), lwtype_name(type1));
2287 return -1.0;
2288
2289}
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:94
#define LINETYPE
Definition liblwgeom.h:103
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition lwgeom.c:1196
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
#define POLYGONTYPE
Definition liblwgeom.h:104
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
#define FLAGS_GET_GEODETIC(flags)
Definition liblwgeom.h:168
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:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
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:199
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:97
static double distance(double x1, double y1, double x2, double y2)
Definition lwtree.c:1032
uint32_t ngeoms
Definition liblwgeom.h:580
LWGEOM ** geoms
Definition liblwgeom.h:575
uint8_t type
Definition liblwgeom.h:462
GBOX * bbox
Definition liblwgeom.h:458
lwflags_t flags
Definition liblwgeom.h:461
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY * point
Definition liblwgeom.h:471
POINTARRAY ** rings
Definition liblwgeom.h:519
uint32_t nrings
Definition liblwgeom.h:524

References LWGEOM::bbox, distance(), LWGEOM::flags, FLAGS_GET_GEODETIC, 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: