31 #include "lwgeom_pg.h"
37 #include "access/htup_details.h"
68 double dist = PG_GETARG_FLOAT8(1);
72 bool preserve_collapsed =
false;
75 if ((PG_NARGS() > 2) && (!PG_ARGISNULL(2)))
76 preserve_collapsed = PG_GETARG_BOOL(2);
80 PG_RETURN_POINTER(geom);
85 if ( ! out ) PG_RETURN_NULL();
93 PG_FREE_IF_COPY(geom, 0);
94 PG_RETURN_POINTER(result);
109 PG_RETURN_POINTER(geom);
111 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
112 area = PG_GETARG_FLOAT8(1);
114 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
115 set_area = PG_GETARG_INT32(2);
120 if ( ! out ) PG_RETURN_NULL();
127 PG_FREE_IF_COPY(geom, 0);
128 PG_RETURN_POINTER(result);
139 int preserve_endpoints=1;
143 PG_RETURN_POINTER(geom);
145 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
146 n_iterations = PG_GETARG_INT32(1);
148 if (n_iterations< 1 || n_iterations>5)
149 elog(ERROR,
"Number of iterations must be between 1 and 5 : %s", __func__);
151 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
153 if(PG_GETARG_BOOL(2))
154 preserve_endpoints = 1;
156 preserve_endpoints = 0;
162 if ( ! out ) PG_RETURN_NULL();
169 PG_FREE_IF_COPY(geom, 0);
170 PG_RETURN_POINTER(result);
188 double distance_fraction = PG_GETARG_FLOAT8(1);
189 int repeat = PG_NARGS() > 2 && PG_GETARG_BOOL(2);
195 if ( distance_fraction < 0 || distance_fraction > 1 )
197 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
198 PG_FREE_IF_COPY(gser, 0);
204 elog(ERROR,
"line_interpolate_point: 1st arg isn't a line");
205 PG_FREE_IF_COPY(gser, 0);
213 PG_FREE_IF_COPY(gser, 0);
225 PG_RETURN_POINTER(result);
284 #define CHECK_RING_IS_CLOSE
285 #define SAMEPOINT(a,b) ((a)->x==(b)->x&&(a)->y==(b)->y)
308 grid.
ipx = PG_GETARG_FLOAT8(1);
309 grid.
ipy = PG_GETARG_FLOAT8(2);
310 grid.
xsize = PG_GETARG_FLOAT8(3);
311 grid.
ysize = PG_GETARG_FLOAT8(4);
316 PG_RETURN_POINTER(in_geom);
322 PG_RETURN_POINTER(in_geom);
327 POSTGIS_DEBUGF(3,
"SnapToGrid got a %s",
lwtype_name(in_lwgeom->
type));
330 if ( out_lwgeom == NULL ) PG_RETURN_NULL();
333 if ( in_lwgeom->
bbox )
336 POSTGIS_DEBUGF(3,
"SnapToGrid made a %s",
lwtype_name(out_lwgeom->
type));
340 PG_RETURN_POINTER(out_geom);
344 #if POSTGIS_DEBUG_LEVEL >= 4
349 lwpgnotice(
"GRID(%g %g %g %g, %g %g %g %g)",
368 in_geom = PG_GETARG_GSERIALIZED_P(0);
373 PG_RETURN_POINTER(in_geom);
376 in_point = PG_GETARG_GSERIALIZED_P(1);
378 if ( in_lwpoint == NULL )
380 lwpgerror(
"Offset geometry must be a point");
383 grid.
xsize = PG_GETARG_FLOAT8(2);
384 grid.
ysize = PG_GETARG_FLOAT8(3);
385 grid.
zsize = PG_GETARG_FLOAT8(4);
386 grid.
msize = PG_GETARG_FLOAT8(5);
390 grid.
ipx = offsetpoint.
x;
391 grid.
ipy = offsetpoint.
y;
397 #if POSTGIS_DEBUG_LEVEL >= 4
404 PG_RETURN_POINTER(in_geom);
409 POSTGIS_DEBUGF(3,
"SnapToGrid got a %s",
lwtype_name(in_lwgeom->
type));
412 if ( out_lwgeom == NULL ) PG_RETURN_NULL();
420 POSTGIS_DEBUGF(3,
"SnapToGrid made a %s",
lwtype_name(out_lwgeom->
type));
424 PG_RETURN_POINTER(out_geom);
437 int type1, type2, rv;
450 elog(ERROR,
"This function only accepts LINESTRING as arguments.");
459 PG_FREE_IF_COPY(geom1, 0);
460 PG_FREE_IF_COPY(geom2, 1);
478 double from = PG_GETARG_FLOAT8(1);
479 double to = PG_GETARG_FLOAT8(2);
485 if ( from < 0 || from > 1 )
487 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
491 if ( to < 0 || to > 1 )
493 elog(ERROR,
"line_interpolate_point: 3rd arg isn't within [0,1]");
499 elog(ERROR,
"2nd arg must be smaller then 3rd arg");
511 PG_FREE_IF_COPY(geom, 0);
531 double length = 0.0, sublength = 0.0, minprop = 0.0, maxprop = 0.0;
539 PG_FREE_IF_COPY(geom, 0);
544 for ( i = 0; i < iline->
ngeoms; i++ )
554 for ( i = 0; i < iline->
ngeoms; i++ )
557 double subfrom = 0.0, subto = 0.0;
564 maxprop = sublength / length;
568 if ( from > maxprop || to < minprop )
571 if ( from <= minprop )
576 if ( from > minprop && from <= maxprop )
577 subfrom = (from - minprop) / (maxprop - minprop);
579 if ( to < maxprop && to >= minprop )
580 subto = (to - minprop) / (maxprop - minprop);
609 elog(ERROR,
"line_substring: 1st arg isn't a line");
615 PG_FREE_IF_COPY(geom, 0);
616 PG_RETURN_POINTER(ret);
633 return ((seg2->
x-seg1->
x)*(point->
y-seg1->
y)-(point->
x-seg1->
x)*(seg2->
y-seg1->
y));
652 if (seg1->
x > seg2->
x)
662 if (seg1->
y > seg2->
y)
673 POSTGIS_DEBUGF(3,
"maxX minX/maxY minY: %.8f %.8f/%.8f %.8f", maxX, minX, maxY, minY);
675 if (maxX < point->
x || minX > point->
x)
677 POSTGIS_DEBUGF(3,
"X value %.8f falls outside the range %.8f-%.8f", point->
x, minX, maxX);
681 else if (maxY < point->
y || minY > point->
y)
683 POSTGIS_DEBUGF(3,
"Y value %.8f falls outside the range %.8f-%.8f", point->
y, minY, maxY);
704 POSTGIS_DEBUG(2,
"point_in_ring called.");
710 for (i=0; i<lines->
ngeoms; i++)
717 POSTGIS_DEBUGF(3,
"segment: (%.8f, %.8f),(%.8f, %.8f)", seg1->
x, seg1->
y, seg2->
x, seg2->
y);
718 POSTGIS_DEBUGF(3,
"side result: %.8f", side);
722 if (((seg2->
x - seg1->
x)*(seg2->
x - seg1->
x) + (seg2->
y - seg1->
y)*(seg2->
y - seg1->
y)) < 1e-12*1e-12)
724 POSTGIS_DEBUG(3,
"segment is zero length... ignoring.");
735 POSTGIS_DEBUGF(3,
"point on ring boundary between points %d, %d", i, i+1);
746 if ((seg1->
y <= point->
y) && (point->
y < seg2->
y) && (side > 0))
748 POSTGIS_DEBUG(3,
"incrementing winding number.");
757 else if ((seg2->
y <= point->
y) && (point->
y < seg1->
y) && (side < 0))
759 POSTGIS_DEBUG(3,
"decrementing winding number.");
765 POSTGIS_DEBUGF(3,
"winding number %d", wn);
786 POSTGIS_DEBUG(2,
"point_in_ring called.");
789 for (i=0; i<pts->
npoints-1; i++)
796 POSTGIS_DEBUGF(3,
"segment: (%.8f, %.8f),(%.8f, %.8f)", seg1->
x, seg1->
y, seg2->
x, seg2->
y);
797 POSTGIS_DEBUGF(3,
"side result: %.8f", side);
801 if ((seg2->
x == seg1->
x) && (seg2->
y == seg1->
y))
803 POSTGIS_DEBUG(3,
"segment is zero length... ignoring.");
814 POSTGIS_DEBUGF(3,
"point on ring boundary between points %d, %d", i, i+1);
825 if ((seg1->
y <= point->
y) && (point->
y < seg2->
y) && (side > 0))
827 POSTGIS_DEBUG(3,
"incrementing winding number.");
836 else if ((seg2->
y <= point->
y) && (point->
y < seg1->
y) && (side < 0))
838 POSTGIS_DEBUG(3,
"decrementing winding number.");
844 POSTGIS_DEBUGF(3,
"winding number %d", wn);
860 POSTGIS_DEBUGF(2,
"point_in_polygon called for %p %d %p.", root, ringCount, point);
867 POSTGIS_DEBUG(3,
"point_in_polygon_rtree: outside exterior ring.");
872 for (i=1; i<ringCount; i++)
876 POSTGIS_DEBUGF(3,
"point_in_polygon_rtree: within hole %d.", i);
893 int i, p,
r, in_ring;
897 POSTGIS_DEBUGF(2,
"point_in_multipolygon_rtree called for %p %d %p.", root, polyCount, point);
905 for ( p = 0; p < polyCount; p++ )
908 POSTGIS_DEBUGF(4,
"point_in_multipolygon_rtree: exterior ring (%d), point_in_ring returned %d", p, in_ring);
911 POSTGIS_DEBUG(3,
"point_in_multipolygon_rtree: outside exterior ring.");
913 else if ( in_ring == 0 )
915 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: on edge of exterior ring %d", p);
920 for(
r=1;
r<ringCounts[p];
r++)
923 POSTGIS_DEBUGF(4,
"point_in_multipolygon_rtree: interior ring (%d), point_in_ring returned %d",
r, in_ring);
926 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: within hole %d of exterior ring %d",
r, p);
932 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: on edge of hole %d of exterior ring %d",
r, p);
962 POSTGIS_DEBUG(2,
"point_in_polygon called.");
968 if ( polygon->
nrings == 0 )
return -1;
973 POSTGIS_DEBUG(3,
"point_in_polygon: outside exterior ring.");
978 for (i=1; i<polygon->
nrings; i++)
983 POSTGIS_DEBUGF(3,
"point_in_polygon: within hole %d.", i);
988 POSTGIS_DEBUGF(3,
"point_in_polygon: on edge of hole %d.", i);
1003 int result, in_ring;
1006 POSTGIS_DEBUG(2,
"point_in_polygon called.");
1013 for (j = 0; j < mpolygon->
ngeoms; j++ )
1019 if ( polygon->
nrings == 0 )
continue;
1024 POSTGIS_DEBUG(3,
"point_in_polygon: outside exterior ring.");
1034 for (i=1; i<polygon->
nrings; i++)
1039 POSTGIS_DEBUGF(3,
"point_in_polygon: within hole %d.", i);
1045 POSTGIS_DEBUGF(3,
"point_in_polygon: on edge of hole %d.", i);
1076 TupleDesc resultTupleDesc;
1077 HeapTuple resultTuple;
1079 Datum result_values[2];
1080 bool result_is_null[2];
1083 if (PG_ARGISNULL(0))
1086 geom = PG_GETARG_GSERIALIZED_P(0);
1098 if (!(mbc && mbc->
center))
1100 lwpgerror(
"Error calculating minimum bounding circle.");
1115 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
1116 BlessTupleDesc(resultTupleDesc);
1118 result_values[0] = PointerGetDatum(center);
1119 result_is_null[0] =
false;
1120 result_values[1] = Float8GetDatum(radius);
1121 result_is_null[1] =
false;
1123 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
1125 result = HeapTupleGetDatum(resultTuple);
1127 PG_RETURN_DATUM(result);
1144 int segs_per_quarter;
1146 if (PG_ARGISNULL(0))
1149 geom = PG_GETARG_GSERIALIZED_P(0);
1150 segs_per_quarter = PG_GETARG_INT32(1);
1162 if (!(mbc && mbc->
center))
1164 lwpgerror(
"Error calculating minimum bounding circle.");
1182 PG_RETURN_POINTER(center);
1198 static const double min_default_tolerance = 1e-8;
1199 double tolerance = min_default_tolerance;
1200 bool compute_tolerance_from_box;
1201 bool fail_if_not_converged;
1205 if (PG_ARGISNULL(0))
1208 compute_tolerance_from_box = PG_ARGISNULL(1);
1210 if (!compute_tolerance_from_box)
1212 tolerance = PG_GETARG_FLOAT8(1);
1215 lwpgerror(
"Tolerance must be positive.");
1220 max_iter = PG_ARGISNULL(2) ? -1 : PG_GETARG_INT32(2);
1221 fail_if_not_converged = PG_ARGISNULL(3) ?
LW_FALSE : PG_GETARG_BOOL(3);
1225 lwpgerror(
"Maximum iterations must be positive.");
1230 geom = PG_GETARG_GSERIALIZED_P(0);
1233 if (compute_tolerance_from_box)
1238 static const double tolerance_coefficient = 1e-6;
1251 tolerance =
FP_MAX(min_default_tolerance, tolerance_coefficient * min_dim);
1255 lwresult =
lwgeom_median(input, tolerance, max_iter, fail_if_not_converged);
1260 lwpgerror(
"Error computing geometric median.");
1266 PG_RETURN_POINTER(result);
1282 if (PG_ARGISNULL(0))
1285 geom = PG_GETARG_GSERIALIZED_P(0);
1291 PG_FREE_IF_COPY(geom, 0);
1309 if (PG_ARGISNULL(0))
1312 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1317 PG_FREE_IF_COPY(geom, 0);
1319 PG_RETURN_BOOL(is_ccw);
LWGEOM * lwgeom_set_effective_area(const LWGEOM *igeom, int set_area, double trshld)
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)...
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 *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
LWPOINT * lwpoint_make2d(int srid, double x, double y)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
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)
LWPOLY * lwpoly_construct_circle(int srid, double x, double y, double radius, uint32_t segments_per_quarter, char exterior)
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.
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
void lwmline_release(LWMLINE *lwline)
LWBOUNDINGCIRCLE * lwgeom_calculate_mbc(const LWGEOM *g)
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
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(int 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.
#define FLAGS_GET_M(flags)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
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.
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
void * lwalloc(size_t size)
void error_if_srid_mismatch(int srid1, int srid2)
LWMPOINT * lwmpoint_construct(int srid, const POINTARRAY *pa)
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.
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm)
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
int lwgeom_is_clockwise(LWGEOM *lwgeom)
Ensure the outer ring is clockwise oriented and all inner rings are counter-clockwise.
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
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)
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
Datum area(PG_FUNCTION_ARGS)
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 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 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...