28 #include "../postgis_config.h" 38 #include "lwgeom_pg.h" 41 #include "lwgeom_transform.h" 45 #define INVMINDIST 1.0e8 48 #define INVMINDIST 1.0e9 78 bool use_spheroid =
false;
82 g1 = PG_GETARG_GSERIALIZED_P(0);
83 g2 = PG_GETARG_GSERIALIZED_P(1);
100 PG_FREE_IF_COPY(g1, 0);
101 PG_FREE_IF_COPY(g2, 1);
111 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__, distance);
116 PG_FREE_IF_COPY(g1, 0);
117 PG_FREE_IF_COPY(g2, 1);
120 if ( distance < 0.0 )
125 PG_RETURN_FLOAT8(distance);
141 bool use_spheroid =
true;
145 g1 = PG_GETARG_GSERIALIZED_P(0);
146 g2 = PG_GETARG_GSERIALIZED_P(1);
149 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
150 tolerance = PG_GETARG_FLOAT8(2);
153 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
154 use_spheroid = PG_GETARG_BOOL(3);
162 if ( ! use_spheroid )
171 PG_FREE_IF_COPY(g1, 0);
172 PG_FREE_IF_COPY(g2, 1);
182 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__, distance);
187 PG_FREE_IF_COPY(g1, 0);
188 PG_FREE_IF_COPY(g2, 1);
191 if ( distance < 0.0 )
196 PG_RETURN_FLOAT8(distance);
210 double tolerance = 0.0;
211 bool use_spheroid =
true;
215 g1 = PG_GETARG_GSERIALIZED_P(0);
216 g2 = PG_GETARG_GSERIALIZED_P(1);
219 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
220 tolerance = PG_GETARG_FLOAT8(2);
223 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
224 use_spheroid = PG_GETARG_BOOL(3);
232 if ( ! use_spheroid )
238 PG_FREE_IF_COPY(g1, 0);
239 PG_FREE_IF_COPY(g2, 1);
254 PG_FREE_IF_COPY(g1, 0);
255 PG_FREE_IF_COPY(g2, 1);
261 if ( distance < 0.0 )
263 elog(ERROR,
"distance returned negative!");
267 PG_RETURN_FLOAT8(distance);
280 double tolerance = 0.0;
282 bool use_spheroid =
true;
287 g1 = PG_GETARG_GSERIALIZED_P(0);
288 g2 = PG_GETARG_GSERIALIZED_P(1);
291 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
292 tolerance = PG_GETARG_FLOAT8(2);
295 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
296 use_spheroid = PG_GETARG_BOOL(3);
304 if ( ! use_spheroid )
310 PG_FREE_IF_COPY(g1, 0);
311 PG_FREE_IF_COPY(g2, 1);
312 PG_RETURN_BOOL(
FALSE);
322 if ( distance < 0.0 )
323 elog(ERROR,
"lwgeom_distance_spheroid returned negative!");
324 dwithin = (distance <= tolerance);
330 PG_FREE_IF_COPY(g1, 0);
331 PG_FREE_IF_COPY(g2, 1);
333 PG_RETURN_BOOL(dwithin);
346 double tolerance = 0.0;
348 bool use_spheroid =
true;
352 g1 = PG_GETARG_GSERIALIZED_P(0);
353 g2 = PG_GETARG_GSERIALIZED_P(1);
358 PG_FREE_IF_COPY(g1, 0);
359 PG_FREE_IF_COPY(g2, 1);
360 PG_RETURN_FLOAT8(0.0);
364 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
365 tolerance = PG_GETARG_FLOAT8(2);
368 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
369 use_spheroid = PG_GETARG_BOOL(3);
377 if ( ! use_spheroid )
382 elog(ERROR,
"geography_distance_tree failed!");
386 PG_RETURN_FLOAT8(distance);
402 double tolerance = 0.0;
404 bool use_spheroid =
true;
408 g1 = PG_GETARG_GSERIALIZED_P(0);
409 g2 = PG_GETARG_GSERIALIZED_P(1);
412 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
413 tolerance = PG_GETARG_FLOAT8(2);
416 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
417 use_spheroid = PG_GETARG_BOOL(3);
425 if ( ! use_spheroid )
434 PG_RETURN_BOOL(
FALSE);
442 PG_FREE_IF_COPY(g1, 0);
443 PG_FREE_IF_COPY(g2, 1);
446 if ( distance < 0.0 )
448 elog(ERROR,
"lwgeom_distance_spheroid returned negative!");
449 PG_RETURN_BOOL(
FALSE);
452 PG_RETURN_BOOL(distance <= tolerance);
472 g = PG_GETARG_GSERIALIZED_P_COPY(0);
475 distance = PG_GETARG_FLOAT8(1);
487 PG_RETURN_POINTER(g);
495 PG_RETURN_POINTER(g_out);
513 g = PG_GETARG_GSERIALIZED_P(0);
516 use_spheroid = PG_GETARG_BOOL(1);
527 PG_RETURN_FLOAT8(0.0);
531 gbox = *(lwgeom->
bbox);
543 if ( gbox.
zmax > 0.0 && gbox.
zmin < 0.0 )
549 if ( ! use_spheroid )
560 PG_FREE_IF_COPY(g, 0);
565 elog(ERROR,
"lwgeom_area_spher(oid) returned area < 0.0");
569 PG_RETURN_FLOAT8(area);
587 g = PG_GETARG_GSERIALIZED_P(0);
593 PG_RETURN_FLOAT8(0.0);
602 PG_RETURN_FLOAT8(0.0);
606 use_spheroid = PG_GETARG_BOOL(1);
612 if ( ! use_spheroid )
621 elog(ERROR,
"lwgeom_length_spheroid returned length < 0.0");
628 PG_FREE_IF_COPY(g, 0);
629 PG_RETURN_FLOAT8(length);
646 g = PG_GETARG_GSERIALIZED_P(0);
653 PG_RETURN_FLOAT8(0.0);
657 use_spheroid = PG_GETARG_BOOL(1);
663 if ( ! use_spheroid )
672 elog(ERROR,
"lwgeom_length_spheroid returned length < 0.0");
679 PG_FREE_IF_COPY(g, 0);
680 PG_RETURN_FLOAT8(length);
698 g = PG_GETARG_GSERIALIZED_P(0);
703 POSTGIS_DEBUG(4,
"gserialized_get_gbox_p returned LW_FAILURE");
704 elog(ERROR,
"Error in gserialized_get_gbox_p calculation.");
718 SET_VARSIZE(g_out, g_out_size);
720 PG_FREE_IF_COPY(g, 0);
721 PG_RETURN_POINTER(g_out);
743 g1 = PG_GETARG_GSERIALIZED_P(0);
744 g2 = PG_GETARG_GSERIALIZED_P(1);
760 PG_FREE_IF_COPY(g1, 0);
761 PG_FREE_IF_COPY(g2, 1);
762 PG_RETURN_BOOL(
false);
771 PG_FREE_IF_COPY(g1, 0);
772 PG_FREE_IF_COPY(g2, 1);
774 PG_RETURN_BOOL(result);
788 GBOX gbox, gbox1, gbox2;
793 double xwidth, ywidth;
796 Datum d1 = PG_GETARG_DATUM(0);
797 Datum d2 = PG_GETARG_DATUM(1);
807 elog(ERROR,
"Error in geography_bestsrid calling gserialized_get_gbox_p(g1, &gbox1)");
809 POSTGIS_DEBUGF(4,
"calculated gbox = %s",
gbox_to_string(&gbox1));
818 elog(ERROR,
"Error in geography_bestsrid calling gserialized_get_gbox_p(g2, &gbox2)");
826 gbox = gbox2 = gbox1;
830 if ( empty1 && empty2 )
847 POSTGIS_DEBUGF(2,
"xwidth %g", xwidth);
848 POSTGIS_DEBUGF(2,
"ywidth %g", ywidth);
849 POSTGIS_DEBUGF(2,
"center POINT(%g %g)", center.
x, center.
y);
852 if ( center.
y > 70.0 && ywidth < 45.0 )
854 PG_RETURN_INT32(SRID_NORTH_LAMBERT);
858 if ( center.
y < -70.0 && ywidth < 45.0 )
860 PG_RETURN_INT32(SRID_SOUTH_LAMBERT);
871 int zone = floor((center.
x + 180.0) / 6.0);
873 if ( zone > 59 ) zone = 59;
876 if ( center.
y < 0.0 )
878 PG_RETURN_INT32( SRID_SOUTH_UTM_START + zone );
883 PG_RETURN_INT32( SRID_NORTH_UTM_START + zone );
896 int yzone = 3 + floor(center.
y / 30.0);
899 if ( (yzone == 2 || yzone == 3) && xwidth < 30.0 )
901 xzone = 6 + floor(center.
x / 30.0);
904 else if ( (yzone == 1 || yzone == 4) && xwidth < 45.0 )
906 xzone = 4 + floor(center.
x / 45.0);
909 else if ( (yzone == 0 || yzone == 5) && xwidth < 90.0 )
911 xzone = 2 + floor(center.
x / 90.0);
917 PG_RETURN_INT32(SRID_LAEA_START + 20 * yzone + xzone);
925 PG_RETURN_INT32(SRID_WORLD_MERCATOR);
941 double azimuth = 0.0;
947 if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
951 g = PG_GETARG_GSERIALIZED_P(0);
957 elog(ERROR,
"ST_Project(geography) is only valid for point inputs");
961 distance = PG_GETARG_FLOAT8(1);
968 elog(ERROR,
"ST_Project(geography) cannot project from an empty start point");
972 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
973 azimuth = PG_GETARG_FLOAT8(2);
981 PG_RETURN_POINTER(g);
988 if ( lwp_projected == NULL )
990 elog(ERROR,
"lwgeom_project_spheroid returned null");
999 PG_FREE_IF_COPY(g, 0);
1000 PG_RETURN_POINTER(g_out);
1021 g1 = PG_GETARG_GSERIALIZED_P(0);
1022 g2 = PG_GETARG_GSERIALIZED_P(1);
1029 elog(ERROR,
"ST_Azimuth(geography, geography) is only valid for point inputs");
1041 elog(ERROR,
"ST_Azimuth(geography, geography) cannot work with empty points");
1055 PG_FREE_IF_COPY(g1, 0);
1056 PG_FREE_IF_COPY(g2, 1);
1059 if( isnan(azimuth) )
1064 PG_RETURN_FLOAT8(azimuth);
1080 double max_seg_length;
1084 g1 = PG_GETARG_GSERIALIZED_P(0);
1092 PG_RETURN_POINTER(g1);
1110 g2 = geography_serialize(lwgeom2);
1115 PG_FREE_IF_COPY(g1, 0);
1117 PG_RETURN_POINTER(g2);
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *box)
Read the bounding box off a serialization and calculate one if it is not already there.
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
int lwgeom_calculate_gbox_geodetic(const LWGEOM *geom, GBOX *gbox)
Calculate the geodetic bounding box for an LWGEOM.
void lwgeom_add_bbox_deep(LWGEOM *lwgeom, GBOX *gbox)
Compute a box for geom and all sub-geometries, if not already computed.
Datum geography_segmentize(PG_FUNCTION_ARGS)
double lwgeom_azumith_spheroid(const LWPOINT *r, const LWPOINT *s, const SPHEROID *spheroid)
Calculate the bearing between two points on a spheroid.
int geography_distance_cache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2, const SPHEROID *s, double *distance)
Datum geography_distance(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
char * gbox_to_string(const GBOX *gbox)
Allocate a string representation of the GBOX, based on dimensionality of flags.
Datum geography_length(PG_FUNCTION_ARGS)
int lwgeom_covers_lwgeom_sphere(const LWGEOM *lwgeom1, const LWGEOM *lwgeom2)
Calculate covers predicate for two lwgeoms on the sphere.
LWPOINT * lwpoint_make2d(int srid, double x, double y)
Datum area(PG_FUNCTION_ARGS)
Datum geography_distance_knn(PG_FUNCTION_ARGS)
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
Datum geography_dwithin_uncached(PG_FUNCTION_ARGS)
int gbox_centroid(const GBOX *gbox, POINT2D *out)
Computes the average(ish) center of the box and returns success.
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.
void error_if_srid_mismatch(int srid1, int srid2)
int geography_tree_distance(const GSERIALIZED *g1, const GSERIALIZED *g2, const SPHEROID *s, double tolerance, double *distance)
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
double lwgeom_length_spheroid(const LWGEOM *geom, const SPHEROID *s)
Calculate the geodetic length of a lwgeom on the unit sphere.
Datum geography_area(PG_FUNCTION_ARGS)
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
GSERIALIZED * gserialized_expand(GSERIALIZED *g, double distance)
Return a GSERIALIZED with an expanded bounding box.
Datum geography_bestsrid(PG_FUNCTION_ARGS)
#define LW_TRUE
Return types for functions with status returns.
Datum geography_point_outside(PG_FUNCTION_ARGS)
#define FP_TOLERANCE
Floating point comparators.
Datum distance(PG_FUNCTION_ARGS)
int gbox_union(const GBOX *g1, const GBOX *g2, GBOX *gout)
Update the output GBOX to be large enough to include both inputs.
double lwgeom_area_sphere(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the geodetic area of a lwgeom on the sphere.
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
int geography_dwithin_cache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2, const SPHEROID *s, double tolerance, int *dwithin)
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...
Datum geography_expand(PG_FUNCTION_ARGS)
Datum geography_distance_tree(PG_FUNCTION_ARGS)
double gbox_angular_height(const GBOX *gbox)
GBOX utility functions to figure out coverage/location on the globe.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Datum geography_covers(PG_FUNCTION_ARGS)
Datum geography_azimuth(PG_FUNCTION_ARGS)
int gbox_pt_outside(const GBOX *gbox, POINT2D *pt_outside)
Calculate a spherical point that falls outside the geocentric gbox.
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Datum geography_distance_uncached(PG_FUNCTION_ARGS)
double lwgeom_area_spheroid(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the geodetic area of a lwgeom on the spheroid.
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.
PG_FUNCTION_INFO_V1(geography_distance_knn)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
GSERIALIZED * gserialized_from_lwgeom(LWGEOM *geom, size_t *size)
Allocate a new GSERIALIZED from an LWGEOM.
Datum geography_dwithin(PG_FUNCTION_ARGS)
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
This library is the generic geometry handling section of PostGIS.
Datum geography_perimeter(PG_FUNCTION_ARGS)
Datum geography_project(PG_FUNCTION_ARGS)
double gbox_angular_width(const GBOX *gbox)
Returns the angular width (longitudinal span) of the box in radians.