[postgis-tickets] r16444 - ST_OffsetCurve: support for MULTILINESTRING, GEOMETRYCOLLECTION and non-simple inputs
Darafei
komzpa at gmail.com
Mon Mar 5 08:54:13 PST 2018
Author: komzpa
Date: 2018-03-05 08:54:13 -0800 (Mon, 05 Mar 2018)
New Revision: 16444
Modified:
trunk/NEWS
trunk/liblwgeom/cunit/cu_clean.c
trunk/liblwgeom/cunit/cu_geos.c
trunk/liblwgeom/liblwgeom.h.in
trunk/liblwgeom/lwcollection.c
trunk/liblwgeom/lwgeom_geos.c
trunk/liblwgeom/lwgeom_geos.h
trunk/liblwgeom/lwgeom_geos_clean.c
trunk/liblwgeom/lwgeom_geos_node.c
trunk/liblwgeom/lwlinearreferencing.c
trunk/postgis/lwgeom_geos.c
trunk/regress/offsetcurve.sql
trunk/regress/offsetcurve_expected
Log:
ST_OffsetCurve: support for MULTILINESTRING, GEOMETRYCOLLECTION and non-simple inputs
Closes #2508
Closes https://github.com/postgis/postgis/pull/224
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/NEWS 2018-03-05 16:54:13 UTC (rev 16444)
@@ -37,10 +37,11 @@
- #3977, ST_ClusterKMeans is now faster and simpler (Darafei Praliaskouski)
- #3982, ST_AsEncodedPolyline supports LINESTRING EMPTY and MULTIPOINT EMPTY
(Darafei Praliaskouski)
- - #3986, ST_AsText now has second argument to limit decimal digits
+ - #3986, ST_AsText now has second argument to limit decimal digits
(Marc Ducobu, Darafei Praliaskouski)
- #4020, Casting from box3d to geometry now returns correctly connected
PolyhedralSurface (Matthias Bay)
+ - #2508, ST_OffsetCurve now works with collections (Darafei Praliaskouski)
PostGIS 2.4.0
2017/09/30
Modified: trunk/liblwgeom/cunit/cu_clean.c
===================================================================
--- trunk/liblwgeom/cunit/cu_clean.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/cunit/cu_clean.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -101,7 +101,7 @@
/* CU_ASSERT_STRING_EQUAL(ewkt,
"GEOMETRYCOLLECTION(POINT(0 0),MULTIPOLYGON(((5 5,0 0,0 10,5 5)),((5 5,10 10,10 0,5 5))),LINESTRING(10 0,10 10))");*/
gexp = lwgeom_from_wkt(
-"GEOMETRYCOLLECTION(POINT(0 0),MULTIPOLYGON(((5 5,0 0,0 10,5 5)),((5 5,10 10,10 0,5 5))),LINESTRING(10 0,10 10))",
+"GEOMETRYCOLLECTION(MULTIPOLYGON(((5 5,10 10,10 0,5 5)),((0 0,0 10,5 5,0 0))),LINESTRING(10 0,10 10),POINT(0 0))",
LW_PARSER_CHECK_NONE);
check_geom_equal(gout, gexp);
lwfree(ewkt);
Modified: trunk/liblwgeom/cunit/cu_geos.c
===================================================================
--- trunk/liblwgeom/cunit/cu_geos.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/cunit/cu_geos.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -63,8 +63,6 @@
lwgeom_free(geom_out);
lwgeom_free(geom_in);
}
-
-
}
static void test_geos_linemerge(void)
@@ -93,7 +91,24 @@
lwgeom_free(geom2);
}
+static void
+test_geos_offsetcurve(void)
+{
+ char* ewkt;
+ char* out_ewkt;
+ LWGEOM* geom1;
+ LWGEOM* geom2;
+ ewkt = "MULTILINESTRING((-10 0, -10 100), (0 -5, 0 0))";
+ geom1 = lwgeom_from_wkt(ewkt, LW_PARSER_CHECK_NONE);
+ geom2 = lwgeom_offsetcurve(geom1, 2, 10, 1, 1);
+ out_ewkt = lwgeom_to_ewkt((LWGEOM*)geom2);
+ ASSERT_STRING_EQUAL(out_ewkt, "MULTILINESTRING((-12 0,-12 100),(-2 -5,-2 0))");
+ lwfree(out_ewkt);
+ lwgeom_free(geom1);
+ lwgeom_free(geom2);
+}
+
static void test_geos_subdivide(void)
{
#if POSTGIS_GEOS_VERSION < 35
@@ -134,4 +149,5 @@
PG_ADD_TEST(suite, test_geos_noop);
PG_ADD_TEST(suite, test_geos_subdivide);
PG_ADD_TEST(suite, test_geos_linemerge);
+ PG_ADD_TEST(suite, test_geos_offsetcurve);
}
Modified: trunk/liblwgeom/liblwgeom.h.in
===================================================================
--- trunk/liblwgeom/liblwgeom.h.in 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/liblwgeom.h.in 2018-03-05 16:54:13 UTC (rev 16444)
@@ -630,6 +630,7 @@
extern LWPSURFACE* lwpsurface_add_lwpoly(LWPSURFACE *mobj, const LWPOLY *obj);
extern LWTIN* lwtin_add_lwtriangle(LWTIN *mobj, const LWTRIANGLE *obj);
+extern LWCOLLECTION* lwcollection_concat_in_place(LWCOLLECTION* col1, const LWCOLLECTION* col2);
/***********************************************************************
@@ -2290,7 +2291,7 @@
/*
* An offset curve against the input line.
*
- * @param lwline a lineal geometry
+ * @param geom a lineal geometry or collection of them
* @param size offset distance. Offset left if negative and right if positive
* @param quadsegs number of quadrature segments in curves (try 8)
* @param joinStyle (1 = round, 2 = mitre, 3 = bevel)
@@ -2297,9 +2298,8 @@
* @param mitreLimit (try 5.0)
* @return derived geometry (linestring or multilinestring)
*
- * Requires GEOS-3.2.0+
*/
-LWGEOM* lwgeom_offsetcurve(const LWLINE *lwline, double size, int quadsegs, int joinStyle, double mitreLimit);
+LWGEOM* lwgeom_offsetcurve(const LWGEOM *geom, double size, int quadsegs, int joinStyle, double mitreLimit);
/*
* Return true if the input geometry is "simple" as per OGC defn.
Modified: trunk/liblwgeom/lwcollection.c
===================================================================
--- trunk/liblwgeom/lwcollection.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/lwcollection.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -186,9 +186,10 @@
*/
LWCOLLECTION* lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
{
- if ( col == NULL || geom == NULL ) return NULL;
+ if (!col || !geom) return NULL;
- if ( col->geoms == NULL && (col->ngeoms || col->maxgeoms) ) {
+ if (!col->geoms && (col->ngeoms || col->maxgeoms))
+ {
lwerror("Collection is in inconsistent state. Null memory but non-zero collection counts.");
return NULL;
}
@@ -200,7 +201,7 @@
}
/* In case this is a truly empty, make some initial space */
- if ( col->geoms == NULL )
+ if (!col->geoms)
{
col->maxgeoms = 2;
col->ngeoms = 0;
@@ -214,17 +215,16 @@
/* See http://trac.osgeo.org/postgis/ticket/2933 */
/* Make sure we don't already have a reference to this geom */
{
- int i = 0;
- for ( i = 0; i < col->ngeoms; i++ )
- {
- if ( col->geoms[i] == geom )
+ uint32_t i = 0;
+ for (i = 0; i < col->ngeoms; i++)
{
- lwerror("%s [%d] found duplicate geometry in collection %p == %p", __FILE__, __LINE__, col->geoms[i], geom);
- LWDEBUGF(4, "Found duplicate geometry in collection %p == %p", col->geoms[i], geom);
- return col;
+ if (col->geoms[i] == geom)
+ {
+ lwerror("%s [%d] found duplicate geometry in collection %p == %p", __FILE__, __LINE__, col->geoms[i], geom);
+ return col;
+ }
}
}
- }
#endif
col->geoms[col->ngeoms] = (LWGEOM*)geom;
@@ -232,6 +232,20 @@
return col;
}
+/**
+ * Appends all geometries from col2 to col1 in place.
+ * Caller is responsible to release col2.
+ */
+LWCOLLECTION *
+lwcollection_concat_in_place(LWCOLLECTION *col1, const LWCOLLECTION *col2)
+{
+ uint32_t i;
+ if (!col1 || !col2) return NULL;
+ for (i = 0; i < col2->ngeoms; i++)
+ col1 = lwcollection_add_lwgeom(col1, col2->geoms[i]);
+ return col1;
+}
+
LWCOLLECTION*
lwcollection_segmentize2d(const LWCOLLECTION* col, double dist)
{
Modified: trunk/liblwgeom/lwgeom_geos.c
===================================================================
--- trunk/liblwgeom/lwgeom_geos.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/lwgeom_geos.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -491,7 +491,11 @@
inline static int32_t
get_result_srid(const LWGEOM* geom1, const LWGEOM* geom2, const char* funcname)
{
- if (!geom1) lwerror("%s: First argument is null pointer", funcname);
+ if (!geom1)
+ {
+ lwerror("%s: First argument is null pointer", funcname);
+ return SRID_INVALID;
+ }
if (geom2 && (geom1->srid != geom2->srid))
{
lwerror("%s: Operation on mixed SRID geometries (%d != %d)", funcname, geom1->srid, geom2->srid);
@@ -1206,8 +1210,8 @@
return result;
}
-LWGEOM*
-lwgeom_offsetcurve(const LWLINE* lwline, double size, int quadsegs, int joinStyle, double mitreLimit)
+static LWGEOM *
+lwline_offsetcurve(const LWLINE *lwline, double size, int quadsegs, int joinStyle, double mitreLimit)
{
LWGEOM* result;
LWGEOM* geom = lwline_as_lwgeom(lwline);
@@ -1223,13 +1227,116 @@
g3 = GEOSOffsetCurve(g1, size, quadsegs, joinStyle, mitreLimit);
- if (!g3) return geos_clean_and_fail(g1, NULL, NULL, __func__);
+ if (!g3)
+ {
+ geos_clean(g1, NULL, NULL);
+ return NULL;
+ }
if (!output_geos_as_lwgeom(&g3, &result, srid, is3d, __func__))
return geos_clean_and_fail(g1, NULL, g3, __func__);
geos_clean(g1, NULL, g3);
+ return result;
+}
+static LWGEOM *
+lwcollection_offsetcurve(const LWCOLLECTION *col, double size, int quadsegs, int joinStyle, double mitreLimit)
+{
+ const LWGEOM *geom = lwcollection_as_lwgeom(col);
+ int32_t srid = get_result_srid(geom, NULL, __func__);
+ uint8_t is3d = FLAGS_GET_Z(col->flags);
+ LWCOLLECTION *result;
+ LWGEOM *tmp;
+ uint32_t i;
+ if (srid == SRID_INVALID) return NULL;
+
+ result = lwcollection_construct_empty(MULTILINETYPE, srid, is3d, LW_FALSE);
+
+ for (i = 0; i < col->ngeoms; i++)
+ {
+ tmp = lwgeom_offsetcurve(col->geoms[i], size, quadsegs, joinStyle, mitreLimit);
+
+ if (!tmp)
+ {
+ lwcollection_free(result);
+ return NULL;
+ }
+
+ if (!lwgeom_is_empty(tmp))
+ {
+ if (lwgeom_is_collection(tmp))
+ result = lwcollection_concat_in_place(result, lwgeom_as_lwcollection(tmp));
+ else
+ result = lwcollection_add_lwgeom(result, tmp);
+
+ if (!result)
+ {
+ lwgeom_free(tmp);
+ return NULL;
+ }
+ }
+ }
+
+ if (result->ngeoms == 1)
+ {
+ tmp = result->geoms[0];
+ lwcollection_release(result);
+ return tmp;
+ }
+ else
+ return lwcollection_as_lwgeom(result);
+}
+
+LWGEOM*
+lwgeom_offsetcurve(const LWGEOM* geom, double size, int quadsegs, int joinStyle, double mitreLimit)
+{
+ int32_t srid = get_result_srid(geom, NULL, __func__);
+ LWGEOM *result = NULL;
+ LWGEOM *noded = NULL;
+ if (srid == SRID_INVALID) return NULL;
+
+ if (lwgeom_dimension(geom) != 1)
+ {
+ lwerror("%s: input is not linear", __func__, lwtype_name(geom->type));
+ return NULL;
+ }
+
+ while (!result)
+ {
+ switch (geom->type)
+ {
+ case LINETYPE:
+ result = lwline_offsetcurve(lwgeom_as_lwline(geom), size, quadsegs, joinStyle, mitreLimit);
+ break;
+ case COLLECTIONTYPE:
+ case MULTILINETYPE:
+ result = lwcollection_offsetcurve(lwgeom_as_lwcollection(geom), size, quadsegs, joinStyle, mitreLimit);
+ break;
+ default:
+ lwerror("%s: unsupported geometry type: %s", __func__, lwtype_name(geom->type));
+ return NULL;
+ }
+
+ if (result)
+ return result;
+ else if (!noded)
+ {
+ noded = lwgeom_node(geom);
+ if (!noded)
+ {
+ lwfree(noded);
+ lwerror("lwgeom_offsetcurve: cannot node input");
+ return NULL;
+ }
+ geom = noded;
+ }
+ else
+ {
+ lwerror("lwgeom_offsetcurve: noded geometry cannot be offset");
+ return NULL;
+ }
+ }
return result;
}
@@ -1334,19 +1441,17 @@
}
/* shuffle */
+ n = sample_height * sample_width;
+ if (n > 1)
{
- n = sample_height * sample_width;
- if (n > 1)
+ for (i = 0; i < n - 1; ++i)
{
- for (i = 0; i < n - 1; ++i)
- {
- size_t rnd = (size_t)rand();
- size_t j = i + rnd / (RAND_MAX / (n - i) + 1);
+ size_t rnd = (size_t)rand();
+ size_t j = i + rnd / (RAND_MAX / (n - i) + 1);
- memcpy(tmp, (char*)cells + j * stride, size);
- memcpy((char*)cells + j * stride, (char*)cells + i * stride, size);
- memcpy((char*)cells + i * stride, tmp, size);
- }
+ memcpy(tmp, (char *)cells + j * stride, size);
+ memcpy((char *)cells + j * stride, (char *)cells + i * stride, size);
+ memcpy((char *)cells + i * stride, tmp, size);
}
}
Modified: trunk/liblwgeom/lwgeom_geos.h
===================================================================
--- trunk/liblwgeom/lwgeom_geos.h 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/lwgeom_geos.h 2018-03-05 16:54:13 UTC (rev 16444)
@@ -35,13 +35,14 @@
GEOSGeometry* LWGEOM2GEOS(const LWGEOM* g, uint8_t autofix);
GEOSGeometry* GBOX2GEOS(const GBOX* g);
GEOSGeometry* LWGEOM_GEOS_buildArea(const GEOSGeometry* geom_in);
+GEOSGeometry* LWGEOM_GEOS_makeValid(const GEOSGeometry*);
GEOSGeometry* make_geos_point(double x, double y);
GEOSGeometry* make_geos_segment(double x1, double y1, double x2, double y2);
-int cluster_intersecting(GEOSGeometry** geoms, uint32_t num_geoms, GEOSGeometry*** clusterGeoms, uint32_t* num_clusters);
-int cluster_within_distance(LWGEOM** geoms, uint32_t num_geoms, double tolerance, LWGEOM*** clusterGeoms, uint32_t* num_clusters);
-int union_dbscan(LWGEOM** geoms, uint32_t num_geoms, UNIONFIND* uf, double eps, uint32_t min_points, char** is_in_cluster_ret);
+int cluster_intersecting(GEOSGeometry **geoms, uint32_t num_geoms, GEOSGeometry ***clusterGeoms, uint32_t *num_clusters);
+int cluster_within_distance(LWGEOM **geoms, uint32_t num_geoms, double tolerance, LWGEOM ***clusterGeoms, uint32_t *num_clusters);
+int union_dbscan(LWGEOM **geoms, uint32_t num_geoms, UNIONFIND *uf, double eps, uint32_t min_points, char **is_in_cluster_ret);
POINTARRAY* ptarray_from_GEOSCoordSeq(const GEOSCoordSequence* cs, uint8_t want3d);
Modified: trunk/liblwgeom/lwgeom_geos_clean.c
===================================================================
--- trunk/liblwgeom/lwgeom_geos_clean.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/lwgeom_geos_clean.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -321,34 +321,28 @@
LWGEOM_GEOS_nodeLines(const GEOSGeometry* lines)
{
GEOSGeometry* noded;
- GEOSGeometry* point;
- /*
- * Union with first geometry point, obtaining full noding
- * and dissolving of duplicated repeated points
- *
- * TODO: substitute this with UnaryUnion?
- */
+ /* first, try just to node the line */
+ noded = GEOSNode(lines);
+ if (!noded) noded = (GEOSGeometry *)lines;
- point = LWGEOM_GEOS_getPointN(lines, 0);
- if (!point) return NULL;
+ /* GEOS3.7 UnaryUnion fails on regression tests, cannot be used here */
- LWDEBUGF(3, "Boundary point: %s", lwgeom_to_ewkt(GEOS2LWGEOM(point, 0)));
-
- noded = GEOSUnion(lines, point);
- if (NULL == noded)
+ /* fall back to union of first point with geometry */
+ if (!GEOSisValid(noded))
{
- GEOSGeom_destroy(point);
- return NULL;
+ GEOSGeometry *unioned, *point;
+ point = LWGEOM_GEOS_getPointN(lines, 0);
+ if (!point) return NULL;
+ unioned = GEOSUnion(noded, point);
+ if (!unioned)
+ return NULL;
+ else
+ {
+ GEOSGeom_destroy(noded);
+ return unioned;
+ }
}
-
- GEOSGeom_destroy(point);
-
- LWDEBUGF(3,
- "LWGEOM_GEOS_nodeLines: in[%s] out[%s]",
- lwgeom_to_ewkt(GEOS2LWGEOM(lines, 0)),
- lwgeom_to_ewkt(GEOS2LWGEOM(noded, 0)));
-
return noded;
}
@@ -712,8 +706,6 @@
return gout;
}
-static GEOSGeometry* LWGEOM_GEOS_makeValid(const GEOSGeometry*);
-
/*
* We expect initGEOS being called already.
* Will return NULL on error (expect error handler being called by then)
@@ -770,7 +762,7 @@
return gout;
}
-static GEOSGeometry*
+GEOSGeometry*
LWGEOM_GEOS_makeValid(const GEOSGeometry* gin)
{
GEOSGeometry* gout;
@@ -919,7 +911,7 @@
initGEOS(lwgeom_geos_error, lwgeom_geos_error);
lwgeom_out = lwgeom_in;
- geosgeom = LWGEOM2GEOS(lwgeom_out, 0);
+ geosgeom = LWGEOM2GEOS(lwgeom_out, 1);
if (!geosgeom)
{
LWDEBUGF(4,
Modified: trunk/liblwgeom/lwgeom_geos_node.c
===================================================================
--- trunk/liblwgeom/lwgeom_geos_node.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/lwgeom_geos_node.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -244,7 +244,7 @@
lwgeom_free(ep);
lwcollection_free(col);
- lines->srid = lwgeom_in->srid;
+ lwgeom_set_srid(lines, lwgeom_in->srid);
return (LWGEOM*)lines;
}
Modified: trunk/liblwgeom/lwlinearreferencing.c
===================================================================
--- trunk/liblwgeom/lwlinearreferencing.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/liblwgeom/lwlinearreferencing.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -822,7 +822,7 @@
else if ( type == LINETYPE )
{
/* lwgeom_offsetcurve(line, offset, quadsegs, joinstyle (round), mitrelimit) */
- LWGEOM *lwoff = lwgeom_offsetcurve(lwgeom_as_lwline(out_col->geoms[i]), offset, 8, 1, 5.0);
+ LWGEOM *lwoff = lwgeom_offsetcurve(out_col->geoms[i], offset, 8, 1, 5.0);
if ( ! lwoff )
{
lwerror("lwgeom_offsetcurve returned null");
Modified: trunk/postgis/lwgeom_geos.c
===================================================================
--- trunk/postgis/lwgeom_geos.c 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/postgis/lwgeom_geos.c 2018-03-05 16:54:13 UTC (rev 16444)
@@ -1112,13 +1112,6 @@
gser_input = PG_GETARG_GSERIALIZED_P(0);
size = PG_GETARG_FLOAT8(1);
- /* Check for a useable type */
- if ( gserialized_get_type(gser_input) != LINETYPE )
- {
- lwpgerror("ST_OffsetCurve only works with LineStrings");
- PG_RETURN_NULL();
- }
-
/*
* For distance == 0, just return the input.
* Note that due to a bug, GEOS 3.3.0 would return EMPTY.
@@ -1207,7 +1200,7 @@
pfree(paramstr); /* alloc'ed in text_to_cstring */
}
- lwgeom_result = lwgeom_offsetcurve(lwgeom_as_lwline(lwgeom_input), size, quadsegs, joinStyle, mitreLimit);
+ lwgeom_result = lwgeom_offsetcurve(lwgeom_input, size, quadsegs, joinStyle, mitreLimit);
if (!lwgeom_result)
lwpgerror("ST_OffsetCurve: lwgeom_offsetcurve returned NULL");
Modified: trunk/regress/offsetcurve.sql
===================================================================
--- trunk/regress/offsetcurve.sql 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/regress/offsetcurve.sql 2018-03-05 16:54:13 UTC (rev 16444)
@@ -51,3 +51,11 @@
'LINESTRING(0 0,0 20, 10 20, 10 10, 0 10)', -2,
''
));
+SELECT 't15', ST_AsEWKT(ST_OffsetCurve(
+ 'GEOMETRYCOLLECTION(LINESTRING(0 0,0 20, 10 20, 10 10, 0 10),MULTILINESTRING((2 0,2 20, 12 20, 12 10, 2 10),(3 0,3 20, 13 20, 13 10, 3 10)))', -2,
+ ''
+));
+select '#2508', ST_IsValid(ST_OffsetCurve(
+ '0102000020BB0B000010000000FBB019D1AD1537414A733C4E5333534167CE8F06B815374151F4926C4D335341C4899405B61537413DB009254A335341513EE234AD1537413689A27947335341E38CCA31AB1537415D00E28E44335341951F7F0BB315374104E4CA2441335341A581F041BF153741D46F9F8A3F33534100C27968CD153741C6CAAFE83F335341493DB10CDA1537418919897142335341FCA312FCE01537415D1A1F8045335341C62D3822DD153741554B118E483353411B98FE61D1153741FC35CEE14A33534106DCFDA5C5153741573BD3584B33534167CE8F06B815374151F4926C4D335341FBB019D1AD1537414A733C4E533353414AEB33644E153741595A854786335341',
+ 10
+));
Modified: trunk/regress/offsetcurve_expected
===================================================================
--- trunk/regress/offsetcurve_expected 2018-03-05 14:14:49 UTC (rev 16443)
+++ trunk/regress/offsetcurve_expected 2018-03-05 16:54:13 UTC (rev 16444)
@@ -1,4 +1,4 @@
-ERROR: ST_OffsetCurve only works with LineStrings
+ERROR: lwgeom_offsetcurve: input is not linear
t0|SRID=42;LINESTRING(0 0,10 0)
t1|SRID=42;LINESTRING(0 10,10 10)
t2|SRID=42;LINESTRING(10 -10,0 -10)
@@ -16,3 +16,5 @@
t12|LINESTRING(57.4 31,53.4 30.2,51.2 26,45.8 26,43.6 30.4,41 31.2,40 32.2,36.8 33.4,34.4 36.8)
t13|LINESTRING(-2 0,-2 22,12 22,12 8,2 8)
t14|MULTILINESTRING((2 12,8 12,8 18,2 18,2 12),(2 8,2 0))
+t15|MULTILINESTRING((2 12,8 12,8 18,2 18,2 12),(2 8,2 0),(4 12,10 12,10 18,4 18,4 12),(4 8,4 0),(5 12,11 12,11 18,5 18,5 12),(5 8,5 0))
+#2508|t
More information about the postgis-tickets
mailing list