31 #include "lwgeom_pg.h" 37 #include "access/htup_details.h" 69 double dist = PG_GETARG_FLOAT8(1);
73 bool preserve_collapsed =
false;
76 if ((PG_NARGS() > 2) && (!PG_ARGISNULL(2)))
77 preserve_collapsed = PG_GETARG_BOOL(2);
81 PG_RETURN_POINTER(geom);
86 if ( ! out ) PG_RETURN_NULL();
97 PG_FREE_IF_COPY(geom, 0);
98 PG_RETURN_POINTER(result);
113 PG_RETURN_POINTER(geom);
115 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
116 area = PG_GETARG_FLOAT8(1);
118 if ( (PG_NARGS()>2) && (!PG_ARGISNULL(2)) )
119 set_area = PG_GETARG_INT32(2);
124 if ( ! out ) PG_RETURN_NULL();
131 PG_FREE_IF_COPY(geom, 0);
132 PG_RETURN_POINTER(result);
157 double distance = PG_GETARG_FLOAT8(1);
164 double length, slength, tlength;
166 if ( distance < 0 || distance > 1 )
168 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
174 elog(ERROR,
"line_interpolate_point: 1st arg isn't a line");
184 PG_RETURN_POINTER(result);
194 if ( distance == 0.0 || distance == 1.0 )
196 if ( distance == 0.0 )
212 for ( i = 0; i < nsegs; i++ )
215 POINT4D *p1ptr=&p1, *p2ptr=&p2;
229 if ( distance < tlength + slength )
231 double dseg = (distance - tlength) / slength;
247 PG_FREE_IF_COPY(gser, 0);
307 #define CHECK_RING_IS_CLOSE 308 #define SAMEPOINT(a,b) ((a)->x==(b)->x&&(a)->y==(b)->y) 331 grid.
ipx = PG_GETARG_FLOAT8(1);
332 grid.
ipy = PG_GETARG_FLOAT8(2);
333 grid.
xsize = PG_GETARG_FLOAT8(3);
334 grid.
ysize = PG_GETARG_FLOAT8(4);
339 PG_RETURN_POINTER(in_geom);
345 PG_RETURN_POINTER(in_geom);
350 POSTGIS_DEBUGF(3,
"SnapToGrid got a %s",
lwtype_name(in_lwgeom->
type));
353 if ( out_lwgeom == NULL ) PG_RETURN_NULL();
356 if ( in_lwgeom->
bbox )
362 POSTGIS_DEBUGF(3,
"SnapToGrid made a %s",
lwtype_name(out_lwgeom->
type));
366 PG_RETURN_POINTER(out_geom);
370 #if POSTGIS_DEBUG_LEVEL >= 4 375 lwpgnotice(
"GRID(%g %g %g %g, %g %g %g %g)",
394 in_geom = PG_GETARG_GSERIALIZED_P(0);
399 PG_RETURN_POINTER(in_geom);
402 in_point = PG_GETARG_GSERIALIZED_P(1);
404 if ( in_lwpoint == NULL )
406 lwpgerror(
"Offset geometry must be a point");
409 grid.
xsize = PG_GETARG_FLOAT8(2);
410 grid.
ysize = PG_GETARG_FLOAT8(3);
411 grid.
zsize = PG_GETARG_FLOAT8(4);
412 grid.
msize = PG_GETARG_FLOAT8(5);
416 grid.
ipx = offsetpoint.
x;
417 grid.
ipy = offsetpoint.
y;
423 #if POSTGIS_DEBUG_LEVEL >= 4 430 PG_RETURN_POINTER(in_geom);
435 POSTGIS_DEBUGF(3,
"SnapToGrid got a %s",
lwtype_name(in_lwgeom->
type));
438 if ( out_lwgeom == NULL ) PG_RETURN_NULL();
447 POSTGIS_DEBUGF(3,
"SnapToGrid made a %s",
lwtype_name(out_lwgeom->
type));
451 PG_RETURN_POINTER(out_geom);
464 int type1, type2, rv;
477 elog(ERROR,
"This function only accepts LINESTRING as arguments.");
486 PG_FREE_IF_COPY(geom1, 0);
487 PG_FREE_IF_COPY(geom2, 1);
505 double from = PG_GETARG_FLOAT8(1);
506 double to = PG_GETARG_FLOAT8(2);
512 if ( from < 0 || from > 1 )
514 elog(ERROR,
"line_interpolate_point: 2nd arg isn't within [0,1]");
518 if ( to < 0 || to > 1 )
520 elog(ERROR,
"line_interpolate_point: 3rd arg isn't within [0,1]");
526 elog(ERROR,
"2nd arg must be smaller then 3rd arg");
538 PG_FREE_IF_COPY(geom, 0);
558 double length = 0.0, sublength = 0.0, minprop = 0.0, maxprop = 0.0;
566 PG_FREE_IF_COPY(geom, 0);
571 for ( i = 0; i < iline->ngeoms; i++ )
581 for ( i = 0; i < iline->ngeoms; i++ )
584 double subfrom = 0.0, subto = 0.0;
591 maxprop = sublength / length;
595 if ( from > maxprop || to < minprop )
598 if ( from <= minprop )
603 if ( from > minprop && from <= maxprop )
604 subfrom = (from - minprop) / (maxprop - minprop);
606 if ( to < maxprop && to >= minprop )
607 subto = (to - minprop) / (maxprop - minprop);
636 elog(ERROR,
"line_substring: 1st arg isn't a line");
642 PG_FREE_IF_COPY(geom, 0);
643 PG_RETURN_POINTER(ret);
660 return ((seg2->
x-seg1->
x)*(point->
y-seg1->
y)-(point->
x-seg1->
x)*(seg2->
y-seg1->
y));
679 if (seg1->
x > seg2->
x)
689 if (seg1->
y > seg2->
y)
700 POSTGIS_DEBUGF(3,
"maxX minX/maxY minY: %.8f %.8f/%.8f %.8f", maxX, minX, maxY, minY);
702 if (maxX < point->
x || minX > point->
x)
704 POSTGIS_DEBUGF(3,
"X value %.8f falls outside the range %.8f-%.8f", point->
x, minX, maxX);
708 else if (maxY < point->
y || minY > point->
y)
710 POSTGIS_DEBUGF(3,
"Y value %.8f falls outside the range %.8f-%.8f", point->
y, minY, maxY);
731 POSTGIS_DEBUG(2,
"point_in_ring called.");
737 for (i=0; i<lines->
ngeoms; i++)
744 POSTGIS_DEBUGF(3,
"segment: (%.8f, %.8f),(%.8f, %.8f)", seg1->
x, seg1->
y, seg2->
x, seg2->
y);
745 POSTGIS_DEBUGF(3,
"side result: %.8f", side);
749 if (((seg2->
x - seg1->
x)*(seg2->
x - seg1->
x) + (seg2->
y - seg1->
y)*(seg2->
y - seg1->
y)) < 1e-12*1e-12)
751 POSTGIS_DEBUG(3,
"segment is zero length... ignoring.");
762 POSTGIS_DEBUGF(3,
"point on ring boundary between points %d, %d", i, i+1);
773 if ((seg1->
y <= point->
y) && (point->
y < seg2->
y) && (side > 0))
775 POSTGIS_DEBUG(3,
"incrementing winding number.");
784 else if ((seg2->
y <= point->
y) && (point->
y < seg1->
y) && (side < 0))
786 POSTGIS_DEBUG(3,
"decrementing winding number.");
792 POSTGIS_DEBUGF(3,
"winding number %d", wn);
813 POSTGIS_DEBUG(2,
"point_in_ring called.");
816 for (i=0; i<pts->
npoints-1; i++)
823 POSTGIS_DEBUGF(3,
"segment: (%.8f, %.8f),(%.8f, %.8f)", seg1->
x, seg1->
y, seg2->
x, seg2->
y);
824 POSTGIS_DEBUGF(3,
"side result: %.8f", side);
828 if ((seg2->
x == seg1->
x) && (seg2->
y == seg1->
y))
830 POSTGIS_DEBUG(3,
"segment is zero length... ignoring.");
841 POSTGIS_DEBUGF(3,
"point on ring boundary between points %d, %d", i, i+1);
852 if ((seg1->
y <= point->
y) && (point->
y < seg2->
y) && (side > 0))
854 POSTGIS_DEBUG(3,
"incrementing winding number.");
863 else if ((seg2->
y <= point->
y) && (point->
y < seg1->
y) && (side < 0))
865 POSTGIS_DEBUG(3,
"decrementing winding number.");
871 POSTGIS_DEBUGF(3,
"winding number %d", wn);
887 POSTGIS_DEBUGF(2,
"point_in_polygon called for %p %d %p.", root, ringCount, point);
894 POSTGIS_DEBUG(3,
"point_in_polygon_rtree: outside exterior ring.");
899 for (i=1; i<ringCount; i++)
903 POSTGIS_DEBUGF(3,
"point_in_polygon_rtree: within hole %d.", i);
920 int i, p,
r, in_ring;
924 POSTGIS_DEBUGF(2,
"point_in_multipolygon_rtree called for %p %d %p.", root, polyCount, point);
932 for ( p = 0; p < polyCount; p++ )
935 POSTGIS_DEBUGF(4,
"point_in_multipolygon_rtree: exterior ring (%d), point_in_ring returned %d", p, in_ring);
938 POSTGIS_DEBUG(3,
"point_in_multipolygon_rtree: outside exterior ring.");
940 else if ( in_ring == 0 )
942 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: on edge of exterior ring %d", p);
947 for(r=1; r<ringCounts[p]; r++)
950 POSTGIS_DEBUGF(4,
"point_in_multipolygon_rtree: interior ring (%d), point_in_ring returned %d", r, in_ring);
953 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: within hole %d of exterior ring %d", r, p);
959 POSTGIS_DEBUGF(3,
"point_in_multipolygon_rtree: on edge of hole %d of exterior ring %d", r, p);
985 int i, result, in_ring;
988 POSTGIS_DEBUG(2,
"point_in_polygon called.");
994 if ( polygon->
nrings == 0 )
return -1;
999 POSTGIS_DEBUG(3,
"point_in_polygon: outside exterior ring.");
1004 for (i=1; i<polygon->
nrings; i++)
1009 POSTGIS_DEBUGF(3,
"point_in_polygon: within hole %d.", i);
1014 POSTGIS_DEBUGF(3,
"point_in_polygon: on edge of hole %d.", i);
1028 int i, j, result, in_ring;
1031 POSTGIS_DEBUG(2,
"point_in_polygon called.");
1038 for (j = 0; j < mpolygon->
ngeoms; j++ )
1044 if ( polygon->
nrings == 0 )
continue;
1049 POSTGIS_DEBUG(3,
"point_in_polygon: outside exterior ring.");
1059 for (i=1; i<polygon->
nrings; i++)
1064 POSTGIS_DEBUGF(3,
"point_in_polygon: within hole %d.", i);
1070 POSTGIS_DEBUGF(3,
"point_in_polygon: on edge of hole %d.", i);
1101 TupleDesc resultTupleDesc;
1102 HeapTuple resultTuple;
1104 Datum result_values[2];
1105 bool result_is_null[2];
1108 if (PG_ARGISNULL(0))
1111 geom = PG_GETARG_GSERIALIZED_P(0);
1123 if (!(mbc && mbc->
center))
1125 lwpgerror(
"Error calculating minimum bounding circle.");
1140 get_call_result_type(fcinfo, NULL, &resultTupleDesc);
1141 BlessTupleDesc(resultTupleDesc);
1143 result_values[0] = PointerGetDatum(center);
1144 result_is_null[0] =
false;
1145 result_values[1] = Float8GetDatum(radius);
1146 result_is_null[1] =
false;
1148 resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
1150 result = HeapTupleGetDatum(resultTuple);
1152 PG_RETURN_DATUM(result);
1169 int segs_per_quarter;
1171 if (PG_ARGISNULL(0))
1174 geom = PG_GETARG_GSERIALIZED_P(0);
1175 segs_per_quarter = PG_GETARG_INT32(1);
1187 if (!(mbc && mbc->
center))
1189 lwpgerror(
"Error calculating minimum bounding circle.");
1207 PG_RETURN_POINTER(center);
1223 static const double min_default_tolerance = 1e-8;
1224 double tolerance = min_default_tolerance;
1225 bool compute_tolerance_from_box;
1226 bool fail_if_not_converged;
1230 if (PG_ARGISNULL(0))
1233 compute_tolerance_from_box = PG_ARGISNULL(1);
1235 if (!compute_tolerance_from_box)
1237 tolerance = PG_GETARG_FLOAT8(1);
1240 lwpgerror(
"Tolerance must be positive.");
1245 max_iter = PG_ARGISNULL(2) ? -1 : PG_GETARG_INT32(2);
1246 fail_if_not_converged = PG_ARGISNULL(3) ?
LW_FALSE : PG_GETARG_BOOL(3);
1250 lwpgerror(
"Maximum iterations must be positive.");
1255 geom = PG_GETARG_GSERIALIZED_P(0);
1258 if (compute_tolerance_from_box)
1263 static const double tolerance_coefficient = 1e-6;
1276 tolerance =
FP_MAX(min_default_tolerance, tolerance_coefficient * min_dim);
1280 lwresult =
lwgeom_median(input, tolerance, max_iter, fail_if_not_converged);
1285 lwpgerror(
"Error computing geometric median.");
1291 PG_RETURN_POINTER(result);
1307 if (PG_ARGISNULL(0))
1310 geom = PG_GETARG_GSERIALIZED_P(0);
1316 PG_FREE_IF_COPY(geom, 0);
1318 PG_RETURN_BOOL(is_clockwise);
1334 if (PG_ARGISNULL(0))
1337 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1344 PG_FREE_IF_COPY(geom, 0);
1346 PG_RETURN_BOOL(is_ccw);
void ptarray_set_point4d(POINTARRAY *pa, int n, const POINT4D *p4d)
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
static int point_in_ring_rtree(RTREE_NODE *root, const POINT2D *point)
Datum LWGEOM_simplify2d(PG_FUNCTION_ARGS)
POINTARRAY * ptarray_construct(char hasz, char hasm, uint32_t npoints)
Construct an empty pointarray, allocating storage and setting the npoints, but not filling in any inf...
static int point_in_ring(POINTARRAY *pts, const POINT2D *point)
LWGEOM * lwgeom_grid(const LWGEOM *lwgeom, const gridspec *grid)
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2)
Given two lines, characterize how (and if) they cross each other.
Datum ST_IsPolygonCW(PG_FUNCTION_ARGS)
The following struct and methods are used for a 1D RTree implementation, described at: http://lin-ear...
LWPOINT * lwpoint_make2d(int srid, double x, double y)
Datum area(PG_FUNCTION_ARGS)
void lwpoint_free(LWPOINT *pt)
void lwgeom_free(LWGEOM *geom)
POINTARRAY * ptarray_substring(POINTARRAY *pa, double d1, double d2, double tolerance)
start location (distance from start / total distance) end location (distance from start / total dist...
double ptarray_length_2d(const POINTARRAY *pts)
Find the 2d length of the given POINTARRAY (even if it's 3d)
Datum LWGEOM_snaptogrid(PG_FUNCTION_ARGS)
int point_in_multipolygon_rtree(RTREE_NODE **root, int polyCount, int *ringCounts, LWPOINT *point)
LWMLINE * RTreeFindLineSegments(RTREE_NODE *root, double value)
Retrieves a collection of line segments given the root and crossing value.
Datum ST_GeometricMedian(PG_FUNCTION_ARGS)
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
void error_if_srid_mismatch(int srid1, int srid2)
LWPOINT * lwpoint_construct_empty(int srid, char hasz, char hasm)
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Datum LWGEOM_SetEffectiveArea(PG_FUNCTION_ARGS)
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
int point_in_multipolygon(LWMPOLY *mpolygon, LWPOINT *point)
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Datum ST_IsPolygonCCW(PG_FUNCTION_ARGS)
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
void interpolate_point4d(POINT4D *A, POINT4D *B, POINT4D *I, double F)
Find interpolation point I between point A and point B so that the len(AI) == len(AB)*F and I falls o...
LWGEOM * lwgeom_set_effective_area(const LWGEOM *igeom, int set_area, double trshld)
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
Datum LWGEOM_line_substring(PG_FUNCTION_ARGS)
Datum LWGEOM_snaptogrid_pointoff(PG_FUNCTION_ARGS)
LWBOUNDINGCIRCLE * lwgeom_calculate_mbc(const LWGEOM *g)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, int n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from...
static int is_clockwise(int num_points, double *x, double *y, double *z)
#define LW_TRUE
Return types for functions with status returns.
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
LWGEOM * lwgeom_simplify(const LWGEOM *igeom, double dist, int preserve_collapsed)
#define SRID_UNKNOWN
Unknown SRID value.
LWMLINE * lwgeom_as_lwmline(const LWGEOM *lwgeom)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Datum distance(PG_FUNCTION_ARGS)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
int point_in_polygon(LWPOLY *polygon, LWPOINT *point)
void lwgeom_reverse(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
static int isOnSegment(const POINT2D *seg1, const POINT2D *seg2, const POINT2D *point)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Datum LWGEOM_line_interpolate_point(PG_FUNCTION_ARGS)
Datum ST_LineCrossingDirection(PG_FUNCTION_ARGS)
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
#define FLAGS_GET_M(flags)
static double determineSide(const POINT2D *seg1, const POINT2D *seg2, const POINT2D *point)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
LWPOLY * lwpoly_construct_circle(int srid, double x, double y, double radius, uint32_t segments_per_quarter, char exterior)
int point_in_polygon_rtree(RTREE_NODE **root, int ringCount, LWPOINT *point)
int lwgeom_is_clockwise(LWGEOM *lwgeom)
Check clockwise orientation on LWGEOM polygons.
LWPOINT * lwgeom_median(const LWGEOM *g, double tol, uint32_t maxiter, char fail_if_not_converged)
LWPOINT * lwpoint_construct(int srid, GBOX *bbox, POINTARRAY *point)
void * lwalloc(size_t size)
Datum ST_MinimumBoundingCircle(PG_FUNCTION_ARGS)
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
void lwmline_release(LWMLINE *lwline)
#define FP_CONTAINS_BOTTOM(A, X, B)
PG_FUNCTION_INFO_V1(LWGEOM_simplify2d)
void lwline_release(LWLINE *lwline)
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Datum ST_MinimumBoundingRadius(PG_FUNCTION_ARGS)
void lwboundingcircle_destroy(LWBOUNDINGCIRCLE *c)
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)...
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
This library is the generic geometry handling section of PostGIS.