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.0e9
79 bool use_spheroid =
false;
83 g1 = PG_GETARG_GSERIALIZED_P(0);
84 g2 = PG_GETARG_GSERIALIZED_P(1);
101 PG_FREE_IF_COPY(g1, 0);
102 PG_FREE_IF_COPY(g2, 1);
112 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__,
distance);
117 PG_FREE_IF_COPY(g1, 0);
118 PG_FREE_IF_COPY(g2, 1);
142 bool use_spheroid =
true;
146 g1 = PG_GETARG_GSERIALIZED_P(0);
147 g2 = PG_GETARG_GSERIALIZED_P(1);
150 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
151 tolerance = PG_GETARG_FLOAT8(2);
154 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
155 use_spheroid = PG_GETARG_BOOL(3);
163 if ( ! use_spheroid )
164 s.a =
s.b =
s.radius;
172 PG_FREE_IF_COPY(g1, 0);
173 PG_FREE_IF_COPY(g2, 1);
183 POSTGIS_DEBUGF(2,
"[GIST] '%s' got distance %g", __func__,
distance);
188 PG_FREE_IF_COPY(g1, 0);
189 PG_FREE_IF_COPY(g2, 1);
211 bool use_spheroid =
true;
215 g1 = PG_GETARG_GSERIALIZED_P(0);
216 g2 = PG_GETARG_GSERIALIZED_P(1);
219 use_spheroid = PG_GETARG_BOOL(2);
227 if ( ! use_spheroid )
228 s.a =
s.b =
s.radius;
233 PG_FREE_IF_COPY(g1, 0);
234 PG_FREE_IF_COPY(g2, 1);
254 PG_FREE_IF_COPY(g1, 0);
255 PG_FREE_IF_COPY(g2, 1);
263 elog(ERROR,
"distance returned negative!");
280 double tolerance = 0.0;
281 bool use_spheroid =
true;
288 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
289 tolerance = PG_GETARG_FLOAT8(2);
292 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
293 use_spheroid = PG_GETARG_BOOL(3);
299 if ( ! use_spheroid )
300 s.a =
s.b =
s.radius;
304 PG_RETURN_BOOL(
false);
314 elog(ERROR,
"lwgeom_distance_spheroid returned negative!");
320 PG_FREE_IF_COPY(g1, 0);
321 PG_FREE_IF_COPY(g2, 1);
322 PG_RETURN_BOOL(dwithin);
328 PG_RETURN_BOOL(CallerFInfoFunctionCall2(
330 PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)));
342 double tolerance = 0.0;
344 bool use_spheroid =
true;
348 g1 = PG_GETARG_GSERIALIZED_P(0);
349 g2 = PG_GETARG_GSERIALIZED_P(1);
356 PG_FREE_IF_COPY(g1, 0);
357 PG_FREE_IF_COPY(g2, 1);
358 PG_RETURN_FLOAT8(0.0);
362 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
363 tolerance = PG_GETARG_FLOAT8(2);
366 if ( PG_NARGS() > 3 && ! PG_ARGISNULL(3) )
367 use_spheroid = PG_GETARG_BOOL(3);
373 if ( ! use_spheroid )
374 s.a =
s.b =
s.radius;
378 elog(ERROR,
"geography_distance_tree failed!");
401 double tolerance = 0.0;
403 bool use_spheroid =
true;
407 g1 = PG_GETARG_GSERIALIZED_P(0);
408 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);
423 if ( ! use_spheroid )
424 s.a =
s.b =
s.radius;
432 PG_RETURN_BOOL(
false);
440 PG_FREE_IF_COPY(g1, 0);
441 PG_FREE_IF_COPY(g2, 1);
446 elog(ERROR,
"lwgeom_distance_spheroid returned negative!");
447 PG_RETURN_BOOL(
false);
450 PG_RETURN_BOOL(
distance <= tolerance);
470 g = PG_GETARG_GSERIALIZED_P_COPY(0);
485 PG_RETURN_POINTER(g);
493 PG_RETURN_POINTER(g_out);
511 g = PG_GETARG_GSERIALIZED_P(0);
514 use_spheroid = PG_GETARG_BOOL(1);
525 PG_RETURN_FLOAT8(0.0);
529 gbox = *(lwgeom->
bbox);
533 #ifndef PROJ_GEODESIC
541 if ( gbox.
zmax > 0.0 && gbox.
zmin < 0.0 )
547 if ( ! use_spheroid )
548 s.a =
s.b =
s.radius;
558 PG_FREE_IF_COPY(g, 0);
563 elog(ERROR,
"lwgeom_area_spher(oid) returned area < 0.0");
567 PG_RETURN_FLOAT8(area);
585 g = PG_GETARG_GSERIALIZED_P(0);
591 PG_RETURN_FLOAT8(0.0);
600 PG_RETURN_FLOAT8(0.0);
604 use_spheroid = PG_GETARG_BOOL(1);
610 if ( ! use_spheroid )
611 s.a =
s.b =
s.radius;
619 elog(ERROR,
"lwgeom_length_spheroid returned length < 0.0");
626 PG_FREE_IF_COPY(g, 0);
627 PG_RETURN_FLOAT8(length);
644 g = PG_GETARG_GSERIALIZED_P(0);
651 PG_RETURN_FLOAT8(0.0);
655 use_spheroid = PG_GETARG_BOOL(1);
661 if ( ! use_spheroid )
662 s.a =
s.b =
s.radius;
670 elog(ERROR,
"lwgeom_length_spheroid returned length < 0.0");
677 PG_FREE_IF_COPY(g, 0);
678 PG_RETURN_FLOAT8(length);
695 g = PG_GETARG_GSERIALIZED_P(0);
700 POSTGIS_DEBUG(4,
"gserialized_get_gbox_p returned LW_FAILURE");
701 elog(ERROR,
"Error in gserialized_get_gbox_p calculation.");
711 g_out = geography_serialize(lwpoint);
713 PG_FREE_IF_COPY(g, 0);
714 PG_RETURN_POINTER(g_out);
735 g1 = PG_GETARG_GSERIALIZED_P(0);
736 g2 = PG_GETARG_GSERIALIZED_P(1);
748 PG_FREE_IF_COPY(g1, 0);
749 PG_FREE_IF_COPY(g2, 1);
750 PG_RETURN_BOOL(
false);
759 PG_FREE_IF_COPY(g1, 0);
760 PG_FREE_IF_COPY(g2, 1);
762 PG_RETURN_BOOL(result);
776 g1 = PG_GETARG_GSERIALIZED_P(1);
777 g2 = PG_GETARG_GSERIALIZED_P(0);
789 PG_FREE_IF_COPY(g1, 1);
790 PG_FREE_IF_COPY(g2, 0);
791 PG_RETURN_BOOL(
false);
800 PG_FREE_IF_COPY(g1, 1);
801 PG_FREE_IF_COPY(g2, 0);
803 PG_RETURN_BOOL(result);
817 GBOX gbox, gbox1, gbox2;
822 double xwidth, ywidth;
827 g1 = PG_GETARG_GSERIALIZED_P(0);
838 elog(ERROR,
"Error in geography_bestsrid calling gserialized_get_gbox_p(g1, &gbox1)");
840 POSTGIS_DEBUGF(4,
"calculated gbox = %s",
gbox_to_string(&gbox1));
843 elog(ERROR,
"Error in geography_bestsrid calling with infinite coordinate geographies");
850 g2 = PG_GETARG_GSERIALIZED_P(1);
854 elog(ERROR,
"Error in geography_bestsrid calling gserialized_get_gbox_p(g2, &gbox2)");
860 elog(ERROR,
"Error in geography_bestsrid calling with second arg infinite coordinate geographies");
870 gbox = gbox2 = gbox1;
874 if ( empty1 && empty2 )
891 POSTGIS_DEBUGF(2,
"xwidth %g", xwidth);
892 POSTGIS_DEBUGF(2,
"ywidth %g", ywidth);
893 POSTGIS_DEBUGF(2,
"center POINT(%g %g)", center.
x, center.
y);
896 if ( center.
y > 70.0 && ywidth < 45.0 )
898 PG_RETURN_INT32(SRID_NORTH_LAMBERT);
902 if ( center.
y < -70.0 && ywidth < 45.0 )
904 PG_RETURN_INT32(SRID_SOUTH_LAMBERT);
915 int zone = floor((center.
x + 180.0) / 6.0);
917 if ( zone > 59 ) zone = 59;
920 if ( center.
y < 0.0 )
922 PG_RETURN_INT32( SRID_SOUTH_UTM_START + zone );
927 PG_RETURN_INT32( SRID_NORTH_UTM_START + zone );
940 int yzone = 3 + floor(center.
y / 30.0);
943 if ( (yzone == 2 || yzone == 3) && xwidth < 30.0 )
945 xzone = 6 + floor(center.
x / 30.0);
948 else if ( (yzone == 1 || yzone == 4) && xwidth < 45.0 )
950 xzone = 4 + floor(center.
x / 45.0);
953 else if ( (yzone == 0 || yzone == 5) && xwidth < 90.0 )
955 xzone = 2 + floor(center.
x / 90.0);
961 PG_RETURN_INT32(SRID_LAEA_START + 20 * yzone + xzone);
969 PG_RETURN_INT32(SRID_WORLD_MERCATOR);
985 double azimuth = 0.0;
991 if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
995 g = PG_GETARG_GSERIALIZED_P(0);
1001 elog(ERROR,
"ST_Project(geography) is only valid for point inputs");
1012 elog(ERROR,
"ST_Project(geography) cannot project from an empty start point");
1016 if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
1017 azimuth = PG_GETARG_FLOAT8(2);
1025 PG_RETURN_POINTER(g);
1032 if ( lwp_projected == NULL )
1034 elog(ERROR,
"lwgeom_project_spheroid returned null");
1043 PG_FREE_IF_COPY(g, 0);
1044 PG_RETURN_POINTER(g_out);
1062 uint32_t type1, type2;
1065 g1 = PG_GETARG_GSERIALIZED_P(0);
1066 g2 = PG_GETARG_GSERIALIZED_P(1);
1073 elog(ERROR,
"ST_Azimuth(geography, geography) is only valid for point inputs");
1085 elog(ERROR,
"ST_Azimuth(geography, geography) cannot work with empty points");
1099 PG_FREE_IF_COPY(g1, 0);
1100 PG_FREE_IF_COPY(g2, 1);
1103 if( isnan(azimuth) )
1108 PG_RETURN_FLOAT8(azimuth);
1124 double max_seg_length;
1128 g1 = PG_GETARG_GSERIALIZED_P(0);
1136 PG_RETURN_POINTER(g1);
1154 g2 = geography_serialize(lwgeom2);
1159 PG_FREE_IF_COPY(g1, 0);
1161 PG_RETURN_POINTER(g2);
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_distance_tree(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_distance_knn(PG_FUNCTION_ARGS)
int geography_dwithin_cache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const GSERIALIZED *g2, const SPHEROID *s, double tolerance, int *dwithin)
int geography_tree_distance(const GSERIALIZED *g1, const GSERIALIZED *g2, const SPHEROID *s, double tolerance, double *distance)
int geography_distance_cache(FunctionCallInfo fcinfo, const GSERIALIZED *g1, const 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.
void lwgeom_set_geodetic(LWGEOM *geom, int value)
Set the FLAGS geodetic bit on geometry an all sub-geometries and pointlists.
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.
#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.
double lwgeom_area_sphere(const LWGEOM *lwgeom, const SPHEROID *spheroid)
Calculate the geodetic area of a lwgeom on the sphere.
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.
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)