-- port LINESTRING extension to LWGEOM
+- geometry_same implementation
- WKB support in loader (canonical form is OK)
extern void lwgeom_translate_recursive(char *serialized, double xoff, double yoff, double zoff);
extern void lwgeom_translate_ptarray(POINTARRAY *pa, double xoff, double yoff, double zoff);
extern int lwgeom_pt_inside_circle(POINT2D *p, double cx, double cy, double rad);
-extern POINTARRAY *segmentize2d_ptarray(POINTARRAY *ipa, double dist);
+extern POINTARRAY *ptarray_segmentize2d(POINTARRAY *ipa, double dist);
extern int32 lwgeom_npoints(char *serialized);
extern char ptarray_isccw(const POINTARRAY *pa);
extern void lwgeom_reverse(LWGEOM *lwgeom);
extern void dump_lwexploded(LWGEOM_EXPLODED *exploded);
extern void ptarray_reverse(POINTARRAY *pa);
+extern LWGEOM *lwgeom_segmentize2d(LWGEOM *line, double dist);
+extern LWLINE *lwline_segmentize2d(LWLINE *line, double dist);
+extern LWPOLY *lwpoly_segmentize2d(LWPOLY *line, double dist);
+extern LWCOLLECTION *lwcollection_segmentize2d(LWCOLLECTION *coll, double dist);
extern unsigned char parse_hex(char *str);
extern void deparse_hex(unsigned char str, unsigned char *result);
extern char *parse_lwgeom_wkt(char *wkt_input);
return (LWGEOM *)col;
}
+
+LWCOLLECTION *
+lwcollection_segmentize2d(LWCOLLECTION *col, double dist)
+{
+ unsigned int i;
+ LWGEOM **newgeoms;
+
+ if ( ! col->ngeoms ) return col;
+
+ newgeoms = lwalloc(sizeof(LWGEOM *)*col->ngeoms);
+ for (i=0; i<col->ngeoms; i++)
+ newgeoms[i] = lwgeom_segmentize2d(col->geoms[i], dist);
+
+ return lwcollection_construct(col->type, col->SRID, col->bbox,
+ col->ngeoms, newgeoms);
+}
TYPE_SETHASSRID(lwgeom->type, 0);
lwgeom->SRID = -1;
}
+
+LWGEOM *
+lwgeom_segmentize2d(LWGEOM *lwgeom, double dist)
+{
+ switch(TYPE_GETTYPE(lwgeom->type))
+ {
+ case LINETYPE:
+ return (LWGEOM *)lwline_segmentize2d((LWLINE *)lwgeom,
+ dist);
+ case POLYGONTYPE:
+ return (LWGEOM *)lwpoly_segmentize2d((LWPOLY *)lwgeom,
+ dist);
+ case MULTILINETYPE:
+ case MULTIPOLYGONTYPE:
+ case COLLECTIONTYPE:
+ return (LWGEOM *)lwcollection_segmentize2d(
+ (LWCOLLECTION *)lwgeom, dist);
+ default:
+ return lwgeom;
+ }
+}
// Spatial functions
extern void lwgeom_reverse(LWGEOM lwgeom);
extern void lwgeom_forceRHR(LWGEOM lwgeom);
+extern LWGEOM lwgeom_segmentize2d(LWGEOM lwgeom, double dist);
}
#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 = pointArray_ptsize(ipa);
- int ipoff=0; // input point offset
-
- pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
-
- // Initial storage
- opa = (POINTARRAY *)lwalloc(ptsize * maxpoints);
- opa->dims = ipa->dims;
- opa->npoints = 0;
- opa->serialized_pointlist = (char *)lwalloc(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 *)lwrealloc(
- 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.
PG_FUNCTION_INFO_V1(LWGEOM_segmentize2d);
Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
{
- PG_LWGEOM *geom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
- double dist = PG_GETARG_FLOAT8(1);
- PG_LWGEOM *result = NULL;
- int type = lwgeom_getType(geom->type);
- LWGEOM_EXPLODED *exp;
- int i, j;
- char *srl;
+ PG_LWGEOM *outgeom, *ingeom;
+ double dist;
+ LWGEOM *inlwgeom, *outlwgeom;
+ size_t size, retsize;
- if ( (type != POLYGONTYPE) && (type != MULTIPOLYGONTYPE) )
- {
- elog(ERROR,"segmentize: 1st arg isnt a [multi-]polygon\n");
- PG_RETURN_NULL();
- }
+ ingeom = (PG_LWGEOM *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ dist = PG_GETARG_FLOAT8(1);
- exp = lwgeom_explode(SERIALIZED_FORM(geom));
+ // Avoid deserialize/serialize steps
+ if ( (TYPE_GETTYPE(ingeom->type) == POINTTYPE) ||
+ (TYPE_GETTYPE(ingeom->type) == MULTIPOINTTYPE) )
+ PG_RETURN_POINTER(ingeom);
- 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);
- }
+ inlwgeom = lwgeom_deserialize(SERIALIZED_FORM(ingeom));
+ outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
- // Serialize exploded structure
- srl = lwexploded_serialize(exp, lwgeom_hasBBOX(geom->type));
- pfree_exploded(exp);
+ size = lwgeom_serialize_size(outlwgeom);
+ outgeom = palloc(size+4);
+ outgeom->size = size+4;
+ lwgeom_serialize_buf(outlwgeom, SERIALIZED_FORM(outgeom), &retsize);
- // Construct return value
- result = PG_LWGEOM_construct(srl, lwgeom_getSRID(geom),
- lwgeom_hasBBOX(geom->type));
+ if ( size != retsize )
+ {
+ lwerror ("lwgeom_serialize_buf returned size(%d) != lwgeom_serialize_size (%d)", retsize, size);
+ }
- PG_RETURN_POINTER(result);
+ PG_RETURN_POINTER(outgeom);
}
// Reverse vertex order of geometry
{
ptarray_reverse(line->points);
}
+
+LWLINE *
+lwline_segmentize2d(LWLINE *line, double dist)
+{
+ return lwline_construct(line->SRID, line->bbox,
+ ptarray_segmentize2d(line->points, dist));
+}
for (i=0; i<poly->nrings; i++)
ptarray_reverse(poly->rings[i]);
}
+
+LWPOLY *
+lwpoly_segmentize2d(LWPOLY *poly, double dist)
+{
+ POINTARRAY **newrings;
+ unsigned int i;
+
+ newrings = lwalloc(sizeof(POINTARRAY *)*poly->nrings);
+ for (i=0; i<poly->nrings; i++)
+ {
+ newrings[i] = ptarray_segmentize2d(poly->rings[i], dist);
+ }
+ return lwpoly_construct(poly->SRID, poly->bbox,
+ poly->nrings, newrings);
+}
return result;
}
+
+// 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 *
+ptarray_segmentize2d(POINTARRAY *ipa, double dist)
+{
+ double segdist;
+ POINT4D *p1, *p2, *ip, *op;
+ POINT4D pbuf;
+ POINTARRAY *opa;
+ int maxpoints = ipa->npoints;
+ int ptsize = pointArray_ptsize(ipa);
+ int ipoff=0; // input point offset
+
+ pbuf.x = pbuf.y = pbuf.z = pbuf.m = 0;
+
+ // Initial storage
+ opa = (POINTARRAY *)lwalloc(ptsize * maxpoints);
+ opa->dims = ipa->dims;
+ opa->npoints = 0;
+ opa->serialized_pointlist = (char *)lwalloc(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 *)lwrealloc(
+ opa->serialized_pointlist,
+ maxpoints*ptsize
+ );
+ }
+ op = (POINT4D *)getPoint(opa, opa->npoints-1);
+ memcpy(op, ip, ptsize);
+ }
+
+ return opa;
+}
+