Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS);
Datum LWGEOM_envelope(PG_FUNCTION_ARGS);
Datum LWGEOM_isempty(PG_FUNCTION_ARGS);
+Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS);
// internal
char * lwgeom_summary_recursive(char *serialized, int offset);
PG_RETURN_POINTER(result);
}
#endif // ! USE_GEOS
+
+// Returns a modified POINTARRAY so that no segment is
+// longer then the given distance (computed using 2d).
+// Every input point is kept.
+// Z and M values for added points (if needed) are set to 0.
+POINTARRAY *
+segmentize2d_ptarray(POINTARRAY *ipa, double dist)
+{
+ double segdist;
+ POINT4D *p1, *p2, *ip, *op;
+ POINT4D pbuf;
+ POINTARRAY *opa;
+ int maxpoints = ipa->npoints;
+ int ptsize = ipa->ndims * sizeof(double);
+ int ipoff=0; // input point offset
+
+ pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
+
+ // Initial storage
+ opa = (POINTARRAY *)palloc(ptsize * maxpoints);
+ opa->ndims = ipa->ndims;
+ opa->npoints = 0;
+ opa->serialized_pointlist = (char *)palloc(maxpoints*ptsize);
+
+ // Add first point
+ opa->npoints++;
+ p1 = (POINT4D *)getPoint(ipa, ipoff);
+ op = (POINT4D *)getPoint(opa, opa->npoints-1);
+ memcpy(op, p1, ptsize);
+ ipoff++;
+
+ while (ipoff<ipa->npoints)
+ {
+ p2 = (POINT4D *)getPoint(ipa, ipoff);
+
+ segdist = distance2d_pt_pt((POINT2D *)p1, (POINT2D *)p2);
+
+ if (segdist > dist) // add an intermediate point
+ {
+ pbuf.x = p1->x + (p2->x-p1->x)/segdist * dist;
+ pbuf.y = p1->y + (p2->y-p1->y)/segdist * dist;
+ // might also compute z and m if available...
+ ip = &pbuf;
+ p1 = ip;
+ }
+ else // copy second point
+ {
+ ip = p2;
+ p1 = p2;
+ ipoff++;
+ }
+
+ // Add point
+ if ( ++(opa->npoints) > maxpoints ) {
+ maxpoints *= 1.5;
+ opa->serialized_pointlist = (char *)repalloc(
+ opa->serialized_pointlist,
+ maxpoints*ptsize
+ );
+ }
+ op = (POINT4D *)getPoint(opa, opa->npoints-1);
+ memcpy(op, ip, ptsize);
+ }
+
+ return opa;
+}
+
+// Returns a modified [multi]polygon so that no ring segment is
+// longer then the given distance (computed using 2d).
+// Every input point is kept.
+// Z and M values for added points (if needed) are set to 0.
+PG_FUNCTION_INFO_V1(LWGEOM_segmentize2d);
+Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
+{
+ LWGEOM *geom = (LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ double dist = PG_GETARG_FLOAT8(1);
+ LWGEOM *result = NULL;
+ int type = lwgeom_getType(geom->type);
+ LWGEOM_EXPLODED *exp;
+ int i, j;
+ char *srl;
+
+ if ( (type != POLYGONTYPE) && (type != MULTIPOLYGONTYPE) )
+ {
+ elog(ERROR,"segmentize: 1st arg isnt a [multi-]polygon\n");
+ PG_RETURN_NULL();
+ }
+
+ exp = lwgeom_explode(SERIALIZED_FORM(geom));
+
+ for (i=0; i<exp->npolys; i++)
+ {
+ LWPOLY *poly = lwpoly_deserialize(exp->polys[i]);
+ for (j=0; j<poly->nrings; j++)
+ {
+ POINTARRAY *ring = poly->rings[j];
+ poly->rings[j] = segmentize2d_ptarray(ring, dist);
+ }
+ pfree_polygon(poly);
+ exp->polys[i] = lwpoly_serialize(poly);
+ }
+
+ // Serialize exploded structure
+ srl = lwexploded_serialize(exp, lwgeom_hasBBOX(geom->type));
+ pfree_exploded(exp);
+
+ // Construct return value
+ result = LWGEOM_construct(srl, lwgeom_getSRID(geom),
+ lwgeom_hasBBOX(geom->type));
+
+ PG_RETURN_POINTER(result);
+}