31 #include "lwgeom_pg.h"
36 #include "access/htup_details.h"
66 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
67 double dist = PG_GETARG_FLOAT8(1);
71 bool preserve_collapsed =
false;
76 PG_RETURN_POINTER(geom);
79 if ((PG_NARGS() > 2) && (!PG_ARGISNULL(2)))
80 preserve_collapsed = PG_GETARG_BOOL(2);
86 PG_RETURN_POINTER(geom);
92 PG_RETURN_POINTER(result);
107 PG_RETURN_POINTER(geom);
109 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
110 area = PG_GETARG_FLOAT8(1);
112 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
113 set_area = PG_GETARG_INT32(2);
118 if ( ! out ) PG_RETURN_NULL();
125 PG_FREE_IF_COPY(geom, 0);
126 PG_RETURN_POINTER(result);
137 int preserve_endpoints=1;
141 PG_RETURN_POINTER(geom);
143 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
144 n_iterations = PG_GETARG_INT32(1);
146 if (n_iterations< 1 || n_iterations>5)
147 elog(ERROR,
"Number of iterations must be between 1 and 5 : %s", __func__);
149 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
151 if(PG_GETARG_BOOL(2))
152 preserve_endpoints = 1;
154 preserve_endpoints = 0;
160 if ( ! out ) PG_RETURN_NULL();
167 PG_FREE_IF_COPY(geom, 0);
168 PG_RETURN_POINTER(result);
186 double distance_fraction = PG_GETARG_FLOAT8(1);
187 int repeat = PG_NARGS() > 2 && PG_GETARG_BOOL(2);
193 if ( distance_fraction < 0 || distance_fraction > 1 )
195 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
196 PG_FREE_IF_COPY(gser, 0);
202 elog(ERROR,
"line_interpolate_point: 1st arg isn't a line");
203 PG_FREE_IF_COPY(gser, 0);
211 PG_FREE_IF_COPY(gser, 0);
223 PG_RETURN_POINTER(result);
238 double distance = PG_GETARG_FLOAT8(1);
243 if (distance < 0 || distance > 1)
245 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
251 elog(ERROR,
"line_interpolate_point: 1st arg isn't a line");
261 PG_FREE_IF_COPY(gser, 0);
266 PG_RETURN_POINTER(result);
326 #define CHECK_RING_IS_CLOSE
327 #define SAMEPOINT(a,b) ((a)->x==(b)->x&&(a)->y==(b)->y)
350 grid.
ipx = PG_GETARG_FLOAT8(1);
351 grid.
ipy = PG_GETARG_FLOAT8(2);
352 grid.
xsize = PG_GETARG_FLOAT8(3);
353 grid.
ysize = PG_GETARG_FLOAT8(4);
358 PG_RETURN_POINTER(in_geom);
364 PG_RETURN_POINTER(in_geom);
369 POSTGIS_DEBUGF(3,
"SnapToGrid got a %s",
lwtype_name(in_lwgeom->
type));
372 if ( out_lwgeom == NULL ) PG_RETURN_NULL();
375 if ( in_lwgeom->
bbox )
378 POSTGIS_DEBUGF(3,
"SnapToGrid made a %s",
lwtype_name(out_lwgeom->
type));
382 PG_RETURN_POINTER(out_geom);
386 #if POSTGIS_DEBUG_LEVEL >= 4
391 lwpgnotice(
"GRID(%g %g %g %g, %g %g %g %g)",
410 in_geom = PG_GETARG_GSERIALIZED_P(0);
415 PG_RETURN_POINTER(in_geom);
418 in_point = PG_GETARG_GSERIALIZED_P(1);
420 if ( in_lwpoint == NULL )
422 lwpgerror(
"Offset geometry must be a point");
425 grid.
xsize = PG_GETARG_FLOAT8(2);
426 grid.
ysize = PG_GETARG_FLOAT8(3);
427 grid.
zsize = PG_GETARG_FLOAT8(4);
428 grid.
msize = PG_GETARG_FLOAT8(5);
432 grid.
ipx = offsetpoint.
x;
433 grid.
ipy = offsetpoint.
y;
437 #if POSTGIS_DEBUG_LEVEL >= 4
444 PG_RETURN_POINTER(in_geom);
449 POSTGIS_DEBUGF(3,
"SnapToGrid got a %s",
lwtype_name(in_lwgeom->
type));
452 if ( out_lwgeom == NULL ) PG_RETURN_NULL();
460 POSTGIS_DEBUGF(3,
"SnapToGrid made a %s",
lwtype_name(out_lwgeom->
type));
464 PG_RETURN_POINTER(out_geom);
477 int type1, type2, rv;
490 elog(ERROR,
"This function only accepts LINESTRING as arguments.");
499 PG_FREE_IF_COPY(geom1, 0);
500 PG_FREE_IF_COPY(geom2, 1);
518 double from = PG_GETARG_FLOAT8(1);
519 double to = PG_GETARG_FLOAT8(2);
525 if ( from < 0 || from > 1 )
527 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
531 if ( to < 0 || to > 1 )
533 elog(ERROR,
"line_interpolate_point: 3rd arg isn't within [0,1]");
539 elog(ERROR,
"2nd arg must be smaller then 3rd arg");
551 PG_FREE_IF_COPY(geom, 0);
568 uint32_t i = 0, g = 0;
571 double length = 0.0, sublength = 0.0, minprop = 0.0, maxprop = 0.0;
579 PG_FREE_IF_COPY(geom, 0);
584 for ( i = 0; i < iline->
ngeoms; i++ )
594 for ( i = 0; i < iline->
ngeoms; i++ )
597 double subfrom = 0.0, subto = 0.0;
604 maxprop = sublength / length;
608 if ( from > maxprop || to < minprop )
611 if ( from <= minprop )
616 if ( from > minprop && from <= maxprop )
617 subfrom = (from - minprop) / (maxprop - minprop);
619 if ( to < maxprop && to >= minprop )
620 subto = (to - minprop) / (maxprop - minprop);
649 elog(ERROR,
"line_substring: 1st arg isn't a line");
655 PG_FREE_IF_COPY(geom, 0);
656 PG_RETURN_POINTER(ret);
673 return ((seg2->
x-seg1->
x)*(point->
y-seg1->
y)-(point->
x-seg1->
x)*(seg2->
y-seg1->
y));
692 if (seg1->
x > seg2->
x)
702 if (seg1->
y > seg2->
y)
713 POSTGIS_DEBUGF(3,
"maxX minX/maxY minY: %.8f %.8f/%.8f %.8f", maxX, minX, maxY, minY);
715 if (maxX < point->
x || minX > point->
x)
717 POSTGIS_DEBUGF(3,
"X value %.8f falls outside the range %.8f-%.8f", point->
x, minX, maxX);
721 else if (maxY < point->
y || minY > point->
y)
723 POSTGIS_DEBUGF(3,
"Y value %.8f falls outside the range %.8f-%.8f", point->
y, minY, maxY);
744 POSTGIS_DEBUG(2,
"point_in_ring called.");
750 for (i=0; i<lines->
ngeoms; i++)
757 POSTGIS_DEBUGF(3,
"segment: (%.8f, %.8f),(%.8f, %.8f)", seg1->
x, seg1->
y, seg2->
x, seg2->
y);
758 POSTGIS_DEBUGF(3,
"side result: %.8f", side);
762 if (((seg2->
x - seg1->
x)*(seg2->
x - seg1->
x) + (seg2->
y - seg1->
y)*(seg2->
y - seg1->
y)) < 1e-12*1e-12)
764 POSTGIS_DEBUG(3,
"segment is zero length... ignoring.");
775 POSTGIS_DEBUGF(3,
"point on ring boundary between points %d, %d", i, i+1);
786 if ((seg1->
y <= point->
y) && (point->
y < seg2->
y) && (side > 0))
788 POSTGIS_DEBUG(3,
"incrementing winding number.");
797 else if ((seg2->
y <= point->
y) && (point->
y < seg1->
y) && (side < 0))
799 POSTGIS_DEBUG(3,
"decrementing winding number.");
805 POSTGIS_DEBUGF(3,
"winding number %d", wn);
826 POSTGIS_DEBUG(2,
"point_in_ring called.");
829 for (i=0; i<pts->
npoints-1; i++)
836 POSTGIS_DEBUGF(3,
"segment: (%.8f, %.8f),(%.8f, %.8f)", seg1->
x, seg1->
y, seg2->
x, seg2->
y);
837 POSTGIS_DEBUGF(3,
"side result: %.8f", side);
841 if ((seg2->
x == seg1->
x) && (seg2->
y == seg1->
y))
843 POSTGIS_DEBUG(3,
"segment is zero length... ignoring.");
854 POSTGIS_DEBUGF(3,
"point on ring boundary between points %d, %d", i, i+1);
865 if ((seg1->
y <= point->
y) && (point->
y < seg2->
y) && (side > 0))
867 POSTGIS_DEBUG(3,
"incrementing winding number.");
876 else if ((seg2->
y <= point->
y) && (point->
y < seg1->
y) && (side < 0))
878 POSTGIS_DEBUG(3,
"decrementing winding number.");
884 POSTGIS_DEBUGF(3,
"winding number %d", wn);
900 POSTGIS_DEBUGF(2,
"point_in_polygon called for %p %d %p.", root, ringCount, point);
907 POSTGIS_DEBUG(3,
"point_in_polygon_rtree: outside exterior ring.");
912 for (i=1; i<ringCount; i++)
916 POSTGIS_DEBUGF(3,
"point_in_polygon_rtree: within hole %d.", i);
933 int i, p,
r, in_ring;
937 POSTGIS_DEBUGF(2,
"point_in_multipolygon_rtree called for %p %d %p.", root, polyCount, point);
948 for ( p = 0; p < polyCount; p++ )
951 if( ringCounts[p] == 0 )
continue;
954 POSTGIS_DEBUGF(4,
"point_in_multipolygon_rtree: exterior ring (%d), point_in_ring returned %d", p, in_ring);
957 POSTGIS_DEBUG(3,
"point_in_multipolygon_rtree: outside exterior ring.");
959 else if ( in_ring == 0 )
961 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: on edge of exterior ring %d", p);
966 for(
r=1;
r<ringCounts[p];
r++)
969 POSTGIS_DEBUGF(4,
"point_in_multipolygon_rtree: interior ring (%d), point_in_ring returned %d",
r, in_ring);
972 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: within hole %d of exterior ring %d",
r, p);
978 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: on edge of hole %d of exterior ring %d",
r, p);
1005 int result, in_ring;
1008 POSTGIS_DEBUG(2,
"point_in_polygon called.");
1014 if ( polygon->
nrings == 0 )
return -1;
1019 POSTGIS_DEBUG(3,
"point_in_polygon: outside exterior ring.");
1024 for (i=1; i<polygon->
nrings; i++)
1029 POSTGIS_DEBUGF(3,
"point_in_polygon: within hole %d.", i);
1034 POSTGIS_DEBUGF(3,
"point_in_polygon: on edge of hole %d.", i);
1049 int result, in_ring;
1052 POSTGIS_DEBUG(2,
"point_in_polygon called.");
1062 for (j = 0; j < mpolygon->
ngeoms; j++ )
1068 if ( polygon->
nrings == 0 )
continue;
1073 POSTGIS_DEBUG(3,
"point_in_polygon: outside exterior ring.");
1083 for (i=1; i<polygon->
nrings; i++)
1088 POSTGIS_DEBUGF(3,
"point_in_polygon: within hole %d.", i);
1094 POSTGIS_DEBUGF(3,
"point_in_polygon: on edge of hole %d.", i);
1125 TupleDesc resultTupleDesc;
1126 HeapTuple resultTuple;
1128 Datum result_values[2];
1129 bool result_is_null[2];
1132 if (PG_ARGISNULL(0))
1135 geom = PG_GETARG_GSERIALIZED_P(0);
1147 if (!(mbc && mbc->
center))
1149 lwpgerror(
"Error calculating minimum bounding circle.");
1164 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
1165 BlessTupleDesc(resultTupleDesc);
1167 result_values[0] = PointerGetDatum(center);
1168 result_is_null[0] =
false;
1169 result_values[1] = Float8GetDatum(radius);
1170 result_is_null[1] =
false;
1172 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
1174 result = HeapTupleGetDatum(resultTuple);
1176 PG_RETURN_DATUM(result);
1193 int segs_per_quarter;
1195 if (PG_ARGISNULL(0))
1198 geom = PG_GETARG_GSERIALIZED_P(0);
1199 segs_per_quarter = PG_GETARG_INT32(1);
1211 if (!(mbc && mbc->
center))
1213 lwpgerror(
"Error calculating minimum bounding circle.");
1231 PG_RETURN_POINTER(center);
1247 static const double min_default_tolerance = 1e-8;
1248 double tolerance = min_default_tolerance;
1249 bool compute_tolerance_from_box;
1250 bool fail_if_not_converged;
1254 if (PG_ARGISNULL(0))
1257 compute_tolerance_from_box = PG_ARGISNULL(1);
1259 if (!compute_tolerance_from_box)
1261 tolerance = PG_GETARG_FLOAT8(1);
1264 lwpgerror(
"Tolerance must be positive.");
1269 max_iter = PG_ARGISNULL(2) ? -1 : PG_GETARG_INT32(2);
1270 fail_if_not_converged = PG_ARGISNULL(3) ?
LW_FALSE : PG_GETARG_BOOL(3);
1274 lwpgerror(
"Maximum iterations must be positive.");
1279 geom = PG_GETARG_GSERIALIZED_P(0);
1282 if (compute_tolerance_from_box)
1287 static const double tolerance_coefficient = 1e-6;
1300 tolerance =
FP_MAX(min_default_tolerance, tolerance_coefficient * min_dim);
1304 lwresult =
lwgeom_median(input, tolerance, max_iter, fail_if_not_converged);
1309 lwpgerror(
"Error computing geometric median.");
1315 PG_RETURN_POINTER(result);
1331 if (PG_ARGISNULL(0))
1334 geom = PG_GETARG_GSERIALIZED_P(0);
1340 PG_FREE_IF_COPY(geom, 0);
1358 if (PG_ARGISNULL(0))
1361 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1366 PG_FREE_IF_COPY(geom, 0);
1368 PG_RETURN_BOOL(is_ccw);
LWGEOM * lwgeom_set_effective_area(const LWGEOM *igeom, int set_area, double trshld)
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)...
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,...
LWPOINT * lwpoint_construct_empty(int32_t srid, char hasz, char hasm)
LWPOLY * lwpoly_construct_circle(int32_t srid, double x, double y, double radius, uint32_t segments_per_quarter, char exterior)
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
LWPOINT * lwline_interpolate_point_3d(const LWLINE *line, double distance)
Interpolate one point along a line in 3D.
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
int lwgeom_simplify_in_place(LWGEOM *igeom, double dist, int preserve_collapsed)
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
void lwpoint_free(LWPOINT *pt)
POINTARRAY * ptarray_substring(POINTARRAY *pa, double d1, double d2, double tolerance)
@d1 start location (distance from start / total distance) @d2 end location (distance from start / tot...
void lwgeom_free(LWGEOM *geom)
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
void lwline_release(LWLINE *lwline)
int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2)
Given two lines, characterize how (and if) they cross each other.
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
void lwmline_release(LWMLINE *lwline)
LWBOUNDINGCIRCLE * lwgeom_calculate_mbc(const LWGEOM *g)
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
POINTARRAY * lwline_interpolate_points(const LWLINE *line, double length_fraction, char repeat)
Interpolate one or more points along a line.
LWGEOM * lwgeom_chaikin(const LWGEOM *igeom, int n_iterations, int preserve_endpoint)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
LWPOINT * lwpoint_construct(int32_t srid, GBOX *bbox, POINTARRAY *point)
void lwboundingcircle_destroy(LWBOUNDINGCIRCLE *c)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
void * lwalloc(size_t size)
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWPOINT * lwgeom_median(const LWGEOM *g, double tol, uint32_t maxiter, char fail_if_not_converged)
#define LW_TRUE
Return types for functions with status returns.
#define SRID_UNKNOWN
Unknown SRID value.
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
int lwgeom_is_clockwise(LWGEOM *lwgeom)
Ensure the outer ring is clockwise oriented and all inner rings are counter-clockwise.
LWMPOINT * lwmpoint_construct(int32_t srid, const POINTARRAY *pa)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
This library is the generic geometry handling section of PostGIS.
#define FP_CONTAINS_BOTTOM(A, X, B)
int lwpoint_is_empty(const LWPOINT *point)
int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point)
int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int *ringCounts, LWPOINT *point)
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS)
static int isOnSegment(const POINT2D *seg1, const POINT2D *seg2, const POINT2D *point)
static int point_in_ring_rtree(RTREE_NODE *root, const POINT2D *point)
Datum ST_MinimumBoundingCircle(PG_FUNCTION_ARGS)
static int point_in_ring(POINTARRAY *pts, const POINT2D *point)
Datum LWGEOM_ChaikinSmoothing(PG_FUNCTION_ARGS)
Datum ST_GeometricMedian(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(LWGEOM_simplify2d)
Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS)
int point_in_polygon_rtree(RTREE_NODE **root, int ringCount, LWPOINT *point)
Datum ST_IsPolygonCW(PG_FUNCTION_ARGS)
Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS)
Datum ST_IsPolygonCCW(PG_FUNCTION_ARGS)
Datum ST_MinimumBoundingRadius(PG_FUNCTION_ARGS)
int point_in_polygon(LWPOLY *polygon, LWPOINT *point)
Datum ST_LineCrossingDirection(PG_FUNCTION_ARGS)
Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS)
Datum ST_3DLineInterpolatePoint(PG_FUNCTION_ARGS)
Datum LWGEOM_line_substring(PG_FUNCTION_ARGS)
Datum LWGEOM_SetEffectiveArea(PG_FUNCTION_ARGS)
static double determineSide(const POINT2D *seg1, const POINT2D *seg2, const POINT2D *point)
LWMLINE * RTreeFindLineSegments(RTREE_NODE *root, double value)
Retrieves a collection of line segments given the root and crossing value.
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
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)
static int is_clockwise(int num_points, double *x, double *y, double *z)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
The following struct and methods are used for a 1D RTree implementation, described at: http://lin-ear...