27 #include "catalog/pg_type.h"
29 #include "../postgis_config.h"
38 #include "lwgeom_pg.h"
41 #include "lwgeom_transform.h"
45 #define INVMINDIST 1.0e8
48 #define INVMINDIST 1.0e7
85 bool use_spheroid =
false;
89 g1 = PG_GETARG_GSERIALIZED_P(0);
90 g2 = PG_GETARG_GSERIALIZED_P(1);
107 PG_FREE_IF_COPY(g1, 0);
108 PG_FREE_IF_COPY(g2, 1);
118 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__,
distance);
123 PG_FREE_IF_COPY(g1, 0);
124 PG_FREE_IF_COPY(g2, 1);
148 bool use_spheroid =
true;
152 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
153 tolerance = PG_GETARG_FLOAT8(2);
156 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
157 use_spheroid = PG_GETARG_BOOL(3);
165 if ( ! use_spheroid )
166 s.a =
s.b =
s.radius;
174 PG_FREE_IF_COPY(g1, 0);
175 PG_FREE_IF_COPY(g2, 1);
188 PG_FREE_IF_COPY(g1, 0);
189 PG_FREE_IF_COPY(g2, 1);
208 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
209 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
210 const GSERIALIZED *g1 = shared_gserialized_get(shared_geom1);
211 const GSERIALIZED *g2 = shared_gserialized_get(shared_geom2);
213 bool use_spheroid =
true;
217 use_spheroid = PG_GETARG_BOOL(2);
225 if ( ! use_spheroid )
226 s.a =
s.b =
s.radius;
255 elog(ERROR,
"distance returned negative!");
269 SHARED_GSERIALIZED *shared_geom1 = ToastCacheGetGeometry(fcinfo, 0);
270 SHARED_GSERIALIZED *shared_geom2 = ToastCacheGetGeometry(fcinfo, 1);
271 const GSERIALIZED *g1 = shared_gserialized_get(shared_geom1);
272 const GSERIALIZED *g2 = shared_gserialized_get(shared_geom2);
275 bool use_spheroid =
true;
282 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
283 tolerance = PG_GETARG_FLOAT8(2);
286 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
287 use_spheroid = PG_GETARG_BOOL(3);
293 if ( ! use_spheroid )
294 s.a =
s.b =
s.radius;
298 PG_RETURN_BOOL(
false);
308 elog(ERROR,
"lwgeom_distance_spheroid returned negative!");
314 PG_RETURN_BOOL(dwithin);
320 PG_RETURN_BOOL(CallerFInfoFunctionCall2(
322 PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
334 double tolerance = 0.0;
336 bool use_spheroid =
true;
340 g1 = PG_GETARG_GSERIALIZED_P(0);
341 g2 = PG_GETARG_GSERIALIZED_P(1);
348 PG_FREE_IF_COPY(g1, 0);
349 PG_FREE_IF_COPY(g2, 1);
350 PG_RETURN_FLOAT8(0.0);
354 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
355 tolerance = PG_GETARG_FLOAT8(2);
358 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
359 use_spheroid = PG_GETARG_BOOL(3);
365 if ( ! use_spheroid )
366 s.a =
s.b =
s.radius;
370 elog(ERROR,
"geography_distance_tree failed!");
392 double tolerance = 0.0;
394 bool use_spheroid =
true;
398 g1 = PG_GETARG_GSERIALIZED_P(0);
399 g2 = PG_GETARG_GSERIALIZED_P(1);
403 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
404 tolerance = PG_GETARG_FLOAT8(2);
407 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
408 use_spheroid = PG_GETARG_BOOL(3);
414 if ( ! use_spheroid )
415 s.a =
s.b =
s.radius;
423 PG_RETURN_BOOL(
false);
431 PG_FREE_IF_COPY(g1, 0);
432 PG_FREE_IF_COPY(g2, 1);
437 elog(ERROR,
"lwgeom_distance_spheroid returned negative!");
438 PG_RETURN_BOOL(
false);
441 PG_RETURN_BOOL(
distance <= tolerance);
461 g = PG_GETARG_GSERIALIZED_P_COPY(0);
476 PG_RETURN_POINTER(g);
484 PG_RETURN_POINTER(g_out);
502 g = PG_GETARG_GSERIALIZED_P(0);
505 use_spheroid = PG_GETARG_BOOL(1);
516 PG_RETURN_FLOAT8(0.0);
520 gbox = *(lwgeom->
bbox);
524 #ifndef PROJ_GEODESIC
532 if ( gbox.
zmax > 0.0 && gbox.
zmin < 0.0 )
538 if ( ! use_spheroid )
539 s.a =
s.b =
s.radius;
546 PG_FREE_IF_COPY(g, 0);
551 elog(ERROR,
"lwgeom_area_spher(oid) returned area < 0.0");
555 PG_RETURN_FLOAT8(area);
573 g = PG_GETARG_GSERIALIZED_P(0);
579 PG_RETURN_FLOAT8(0.0);
588 PG_RETURN_FLOAT8(0.0);
592 use_spheroid = PG_GETARG_BOOL(1);
598 if ( ! use_spheroid )
599 s.a =
s.b =
s.radius;
607 elog(ERROR,
"lwgeom_length_spheroid returned length < 0.0");
614 PG_FREE_IF_COPY(g, 0);
615 PG_RETURN_FLOAT8(length);
632 g = PG_GETARG_GSERIALIZED_P(0);
639 PG_RETURN_FLOAT8(0.0);
643 use_spheroid = PG_GETARG_BOOL(1);
649 if ( ! use_spheroid )
650 s.a =
s.b =
s.radius;
658 elog(ERROR,
"lwgeom_length_spheroid returned length < 0.0");
665 PG_FREE_IF_COPY(g, 0);
666 PG_RETURN_FLOAT8(length);
683 POSTGIS_DEBUG(4,
"gserialized_datum_get_gbox_p returned LW_FAILURE");
684 elog(ERROR,
"Error in gserialized_datum_get_gbox_p calculation.");
694 PG_RETURN_POINTER(geography_serialize(lwpoint));
714 g1 = PG_GETARG_GSERIALIZED_P(0);
715 g2 = PG_GETARG_GSERIALIZED_P(1);
727 PG_FREE_IF_COPY(g1, 0);
728 PG_FREE_IF_COPY(g2, 1);
729 PG_RETURN_BOOL(
false);
738 PG_FREE_IF_COPY(g1, 0);
739 PG_FREE_IF_COPY(g2, 1);
755 g1 = PG_GETARG_GSERIALIZED_P(1);
756 g2 = PG_GETARG_GSERIALIZED_P(0);
768 PG_FREE_IF_COPY(g1, 1);
769 PG_FREE_IF_COPY(g2, 0);
770 PG_RETURN_BOOL(
false);
779 PG_FREE_IF_COPY(g1, 1);
780 PG_FREE_IF_COPY(g2, 0);
796 GBOX gbox, gbox1, gbox2;
801 double xwidth, ywidth;
806 g1 = PG_GETARG_GSERIALIZED_P(0);
817 elog(ERROR,
"Error in geography_bestsrid calling gserialized_get_gbox_p(g1, &gbox1)");
819 POSTGIS_DEBUGF(4,
"calculated gbox = %s",
gbox_to_string(&gbox1));
822 elog(ERROR,
"Error in geography_bestsrid calling with infinite coordinate geographies");
829 g2 = PG_GETARG_GSERIALIZED_P(1);
833 elog(ERROR,
"Error in geography_bestsrid calling gserialized_get_gbox_p(g2, &gbox2)");
839 elog(ERROR,
"Error in geography_bestsrid calling with second arg infinite coordinate geographies");
849 gbox = gbox2 = gbox1;
853 if ( empty1 && empty2 )
870 POSTGIS_DEBUGF(2,
"xwidth %g", xwidth);
871 POSTGIS_DEBUGF(2,
"ywidth %g", ywidth);
872 POSTGIS_DEBUGF(2,
"center POINT(%g %g)", center.
x, center.
y);
875 if ( center.
y > 70.0 && ywidth < 45.0 )
877 PG_RETURN_INT32(SRID_NORTH_LAMBERT);
881 if ( center.
y < -70.0 && ywidth < 45.0 )
883 PG_RETURN_INT32(SRID_SOUTH_LAMBERT);
894 int zone = floor((center.
x + 180.0) / 6.0);
896 if ( zone > 59 ) zone = 59;
899 if ( center.
y < 0.0 )
901 PG_RETURN_INT32( SRID_SOUTH_UTM_START + zone );
906 PG_RETURN_INT32( SRID_NORTH_UTM_START + zone );
919 int yzone = 3 + floor(center.
y / 30.0);
922 if ( (yzone == 2 || yzone == 3) && xwidth < 30.0 )
924 xzone = 6 + floor(center.
x / 30.0);
927 else if ( (yzone == 1 || yzone == 4) && xwidth < 45.0 )
929 xzone = 4 + floor(center.
x / 45.0);
932 else if ( (yzone == 0 || yzone == 5) && xwidth < 90.0 )
934 xzone = 2 + floor(center.
x / 90.0);
940 PG_RETURN_INT32(SRID_LAEA_START + 20 * yzone + xzone);
948 PG_RETURN_INT32(SRID_WORLD_MERCATOR);
964 double azimuth = 0.0;
970 if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
974 g = PG_GETARG_GSERIALIZED_P(0);
980 elog(ERROR,
"ST_Project(geography) is only valid for point inputs");
991 elog(ERROR,
"ST_Project(geography) cannot project from an empty start point");
995 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
996 azimuth = PG_GETARG_FLOAT8(2);
1004 PG_RETURN_POINTER(g);
1011 if ( lwp_projected == NULL )
1013 elog(ERROR,
"lwgeom_project_spheroid returned null");
1022 PG_FREE_IF_COPY(g, 0);
1023 PG_RETURN_POINTER(g_out);
1034 LWGEOM *lwgeom1, *lwgeom2;
1041 g1 = PG_GETARG_GSERIALIZED_P(0);
1042 g2 = PG_GETARG_GSERIALIZED_P(1);
1047 elog(ERROR,
"ST_Project(geography) is only valid for point inputs");
1056 PG_RETURN_POINTER(g2);
1067 elog(ERROR,
"ST_Project(geography) cannot project from an empty point");
1082 elog(ERROR,
"lwgeom_project_spheroid_lwpoint returned null");
1092 PG_FREE_IF_COPY(g1, 0);
1093 PG_FREE_IF_COPY(g2, 1);
1094 PG_RETURN_POINTER(g3);
1112 uint32_t type1, type2;
1119 elog(ERROR,
"ST_Azimuth(geography, geography) is only valid for point inputs");
1131 elog(ERROR,
"ST_Azimuth(geography, geography) cannot work with empty points");
1145 PG_FREE_IF_COPY(g1, 0);
1146 PG_FREE_IF_COPY(g2, 1);
1149 if( !isfinite(azimuth) )
1154 PG_RETURN_FLOAT8(azimuth);
1170 double max_seg_length = PG_GETARG_FLOAT8(1) /
WGS84_RADIUS;
1175 PG_RETURN_POINTER(g1);
1193 g2 = geography_serialize(lwgeom2);
1198 PG_FREE_IF_COPY(g1, 0);
1200 PG_RETURN_POINTER(g2);
1214 double from_fraction = PG_GETARG_FLOAT8(1);
1215 double to_fraction = PG_GETARG_FLOAT8(2);
1220 bool use_spheroid =
true;
1222 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
1223 use_spheroid = PG_GETARG_BOOL(3);
1228 PG_FREE_IF_COPY(gs, 0);
1232 if ( from_fraction < 0 || from_fraction > 1 )
1234 elog(ERROR,
"%s: second argument is not within [0,1]", __func__);
1235 PG_FREE_IF_COPY(gs, 0);
1238 if ( to_fraction < 0 || to_fraction > 1 )
1240 elog(ERROR,
"%s: argument arg is not within [0,1]", __func__);
1241 PG_FREE_IF_COPY(gs, 0);
1244 if ( from_fraction > to_fraction )
1246 elog(ERROR,
"%s: second argument must be smaller than third argument", __func__);
1253 elog(ERROR,
"%s: first argument is not a line", __func__);
1254 PG_FREE_IF_COPY(gs, 0);
1261 if ( ! use_spheroid )
1262 s.a =
s.b =
s.radius;
1268 PG_FREE_IF_COPY(gs, 0);
1270 result = geography_serialize(lwresult);
1273 PG_RETURN_POINTER(
result);
1289 double distance_fraction = PG_GETARG_FLOAT8(1);
1291 bool use_spheroid = PG_GETARG_BOOL(2);
1293 bool repeat = (PG_NARGS() > 3) && PG_GETARG_BOOL(3);
1302 PG_FREE_IF_COPY(gs, 0);
1306 if ( distance_fraction < 0 || distance_fraction > 1 )
1308 elog(ERROR,
"%s: second arg is not within [0,1]", __func__);
1309 PG_FREE_IF_COPY(gs, 0);
1316 elog(ERROR,
"%s: first arg is not a line", __func__);
1317 PG_FREE_IF_COPY(gs, 0);
1325 if ( ! use_spheroid )
1326 s.a =
s.b =
s.radius;
1331 PG_FREE_IF_COPY(gs, 0);
1334 result = geography_serialize(lwresult);
1337 PG_RETURN_POINTER(
result);
1350 bool use_spheroid = PG_GETARG_BOOL(2);
1364 PG_FREE_IF_COPY(gs1, 0);
1365 PG_FREE_IF_COPY(gs2, 1);
1371 elog(ERROR,
"%s: 1st arg is not a line", __func__);
1376 elog(ERROR,
"%s: 2nd arg is not a point", __func__);
1381 if ( ! use_spheroid ) {
1382 s.a =
s.b =
s.radius;
1397 PG_RETURN_FLOAT8(ret);
1411 LWGEOM *point, *lwg1, *lwg2;
1422 PG_FREE_IF_COPY(g1, 0);
1423 PG_FREE_IF_COPY(g2, 1);
1428 result = geography_serialize(point);
1433 PG_FREE_IF_COPY(g1, 0);
1434 PG_FREE_IF_COPY(g2, 1);
1435 PG_RETURN_POINTER(
result);
1447 bool use_spheroid = PG_GETARG_BOOL(2);
1448 LWGEOM *line, *lwgeom1, *lwgeom2;
1460 PG_FREE_IF_COPY(g1, 0);
1461 PG_FREE_IF_COPY(g2, 1);
1469 if ( ! use_spheroid )
1470 s.a =
s.b =
s.radius;
1477 result = geography_serialize(line);
1480 PG_FREE_IF_COPY(g1, 0);
1481 PG_FREE_IF_COPY(g2, 1);
1482 PG_RETURN_POINTER(
result);
char result[OUT_DOUBLE_BUFFER_SIZE]
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
char * gbox_to_string(const GBOX *gbox)
Allocate a string representation of the GBOX, based on dimensionality of flags.
GSERIALIZED * gserialized_expand(GSERIALIZED *g, double distance)
Return a GSERIALIZED with an expanded bounding box.
Datum geography_length(PG_FUNCTION_ARGS)
Datum geography_area(PG_FUNCTION_ARGS)
Datum geography_expand(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(geography_distance_knn)
Datum geography_azimuth(PG_FUNCTION_ARGS)
Datum geography_line_substring(PG_FUNCTION_ARGS)
Datum geography_line_locate_point(PG_FUNCTION_ARGS)
Datum geography_shortestline(PG_FUNCTION_ARGS)
Datum geography_closestpoint(PG_FUNCTION_ARGS)
Datum geography_distance_tree(PG_FUNCTION_ARGS)
Datum geography_project_geography(PG_FUNCTION_ARGS)
Datum geography_point_outside(PG_FUNCTION_ARGS)
Datum geography_distance_uncached(PG_FUNCTION_ARGS)
Datum geography_distance(PG_FUNCTION_ARGS)
Datum geography_segmentize(PG_FUNCTION_ARGS)
Datum geography_covers(PG_FUNCTION_ARGS)
Datum geography_intersects(PG_FUNCTION_ARGS)
Datum geography_dwithin(PG_FUNCTION_ARGS)
Datum geography_coveredby(PG_FUNCTION_ARGS)
Datum geography_perimeter(PG_FUNCTION_ARGS)
Datum geography_bestsrid(PG_FUNCTION_ARGS)
Datum geography_dwithin_uncached(PG_FUNCTION_ARGS)
Datum geography_project(PG_FUNCTION_ARGS)
Datum geography_line_interpolate_point(PG_FUNCTION_ARGS)
Datum geography_distance_knn(PG_FUNCTION_ARGS)
int geography_tree_distance(const GSERIALIZED *g1, const GSERIALIZED *g2, const SPHEROID *s, double tolerance, double *distance)
int geography_dwithin_cache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1, SHARED_GSERIALIZED *g2, const SPHEROID *s, double tolerance, int *dwithin)
int geography_distance_cache(FunctionCallInfo fcinfo, SHARED_GSERIALIZED *g1, SHARED_GSERIALIZED *g2, const SPHEROID *s, double *distance)
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
lwflags_t gserialized_get_lwflags(const GSERIALIZED *g)
Read the flags from a GSERIALIZED and return a standard lwflag integer.
int gserialized_datum_get_gbox_p(Datum gsdatum, GBOX *gbox)
Given a GSERIALIZED datum, as quickly as possible (peaking into the top of the memory) return the gbo...
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
double ptarray_locate_point_spheroid(const POINTARRAY *pa, const POINT4D *p4d, const SPHEROID *s, double tolerance, double *mindistout, POINT4D *proj4d)
Locate a point along the point array defining a geographic line.
LWGEOM * geography_interpolate_points(const LWLINE *line, double length_fraction, const SPHEROID *s, char repeat)
Interpolate a point along a geographic line.
LWPOINT * lwgeom_project_spheroid(const LWPOINT *r, const SPHEROID *spheroid, double distance, double azimuth)
Calculate the location of a point on a spheroid, give a start point, bearing and distance.
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
LWGEOM * lwgeom_segmentize_sphere(const LWGEOM *lwg_in, double max_seg_length)
Derive a new geometry with vertices added to ensure no vertex is more than max_seg_length (in radians...
void lwpoint_free(LWPOINT *pt)
double lwgeom_distance_spheroid(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2, const SPHEROID *spheroid, double tolerance)
Calculate the geodetic distance from lwgeom1 to lwgeom2 on the spheroid.
void lwgeom_free(LWGEOM *geom)
int gbox_pt_outside(const GBOX *gbox, POINT2D *pt_outside)
Calculate a spherical point that falls outside the geocentric gbox.
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
double lwgeom_area_spheroid(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the geodetic area of a lwgeom on the spheroid.
int lwgeom_covers_lwgeom_sphere(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
Calculate covers predicate for two lwgeoms on the sphere.
LWGEOM * geography_substring(const LWLINE *line, const SPHEROID *s, double from, double to, double tolerance)
Return the part of a line between two fractional locations.
LWPOINT * lwgeom_project_spheroid_lwpoint(const LWPOINT *from, const LWPOINT *to, const SPHEROID *spheroid, double distance)
Calculate the location of a point on a spheroid, give a start point, end point and distance.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
int lwgeom_isfinite(const LWGEOM *lwgeom)
Check if a LWGEOM has any non-finite (NaN or Inf) coordinates.
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
void lwgeom_add_bbox_deep(LWGEOM *lwgeom, GBOX *gbox)
Compute a box for geom and all sub-geometries, if not already computed.
double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s)
Calculate the geodetic length of a lwgeom on the unit sphere.
#define LW_TRUE
Return types for functions with status returns.
double lwgeom_azumith_spheroid(const LWPOINT *r, const LWPOINT *s, const SPHEROID *spheroid)
Calculate the bearing between two points on a spheroid.
void lwline_free(LWLINE *line)
This library is the generic geometry handling section of PostGIS.
double gbox_angular_height(const GBOX *gbox)
GBOX utility functions to figure out coverage/location on the globe.
double gbox_angular_width(const GBOX *gbox)
Returns the angular width (longitudinal span) of the box in radians.
#define FP_TOLERANCE
Floating point comparators.
int gbox_centroid(const GBOX *gbox, POINT2D *out)
Computes the average(ish) center of the box and returns success.
LWGEOM * geography_tree_closestpoint(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2, double threshold)
LWGEOM * geography_tree_shortestline(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2, double threshold, const SPHEROID *spheroid)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
static double distance(double x1, double y1, double x2, double y2)