[postgis-tickets] r16701 - ST_Segmentize: split geometry proportionally.
Darafei
komzpa at gmail.com
Thu Aug 23 02:56:37 PDT 2018
Author: komzpa
Date: 2018-08-23 02:56:36 -0700 (Thu, 23 Aug 2018)
New Revision: 16701
Modified:
trunk/NEWS
trunk/doc/reference_editor.xml
trunk/liblwgeom/cunit/cu_measures.c
trunk/liblwgeom/ptarray.c
Log:
ST_Segmentize: split geometry proportionally.
This helps avoid situations when 52 meter long segment is split into 50 and 2 meter long ones,
and split into 26 and 26 meter long ones. It is crucial for good interpolating M and Z values.
Thanks Andrew Shadoura for supporting me on Patreon: https://www.patreon.com/komzpa
Closes https://github.com/postgis/postgis/pull/287
Closes #4153
Modified: trunk/NEWS
===================================================================
--- trunk/NEWS 2018-08-19 22:16:29 UTC (rev 16700)
+++ trunk/NEWS 2018-08-23 09:56:36 UTC (rev 16701)
@@ -1,3 +1,10 @@
+PostGIS 3.0.0
+2019/xx/xx
+* Enhancements *
+ - #4153, ST_Segmentize now splits segments proportionally (Darafei
+ Praliaskouski).
+
+
PostGIS 2.5.0rc1
2018/08/19
New since PostGIS 2.5.0beta2
Modified: trunk/doc/reference_editor.xml
===================================================================
--- trunk/doc/reference_editor.xml 2018-08-19 22:16:29 UTC (rev 16700)
+++ trunk/doc/reference_editor.xml 2018-08-23 09:56:36 UTC (rev 16701)
@@ -1556,6 +1556,7 @@
given <varname>max_segment_length</varname>. Distance computation is performed in 2d
only. For geometry, length units are in units of spatial reference. For geography, units are in meters.</para>
<para>Availability: 1.2.2</para>
+ <para>Enhanced: 3.0.0 Segmentize geometry now uses equal length segments</para>
<para>Enhanced: 2.3.0 Segmentize geography now uses equal length segments</para>
<para>Enhanced: 2.1.0 support for geography was introduced.</para>
<para>Changed: 2.1.0 As a result of the introduction of geography support: The construct <code>SELECT ST_Segmentize('LINESTRING(1 2, 3 4)',0.5);</code> will result in ambiguous function error. You need to have properly typed object e.g. a geometry/geography column, use ST_GeomFromText, ST_GeogFromText or
Modified: trunk/liblwgeom/cunit/cu_measures.c
===================================================================
--- trunk/liblwgeom/cunit/cu_measures.c 2018-08-19 22:16:29 UTC (rev 16700)
+++ trunk/liblwgeom/cunit/cu_measures.c 2018-08-23 09:56:36 UTC (rev 16701)
@@ -518,6 +518,15 @@
lwgeom_free(linein);
lwgeom_free(lineout);
+ /* test that segmentize is proportional - request every 6, get every 5 */
+ linein = lwgeom_from_wkt("LINESTRING(0 0, 20 0)", LW_PARSER_CHECK_NONE);
+ lineout = lwgeom_segmentize2d(linein, 6);
+ strout = lwgeom_to_ewkt(lineout);
+ ASSERT_STRING_EQUAL(strout, "LINESTRING(0 0,5 0,10 0,15 0,20 0)");
+ lwfree(strout);
+ lwgeom_free(linein);
+ lwgeom_free(lineout);
+
/* test interruption */
linein = lwgeom_from_wkt("LINESTRING(0 0,10 0)", LW_PARSER_CHECK_NONE);
Modified: trunk/liblwgeom/ptarray.c
===================================================================
--- trunk/liblwgeom/ptarray.c 2018-08-19 22:16:29 UTC (rev 16700)
+++ trunk/liblwgeom/ptarray.c 2018-08-23 09:56:36 UTC (rev 16701)
@@ -402,22 +402,21 @@
}
}
-
/**
* @brief Returns a modified #POINTARRAY so that no segment is
* longer than the given distance (computed using 2d).
*
* Every input point is kept.
- * Z and M values for added points (if needed) are set to 0.
+ * Z and M values for added points (if needed) are set proportionally.
*/
POINTARRAY *
ptarray_segmentize2d(const POINTARRAY *ipa, double dist)
{
- double segdist;
+ double segdist;
POINT4D p1, p2;
POINT4D pbuf;
POINTARRAY *opa;
- uint32_t ipoff=0; /* input point offset */
+ uint32_t i, j, nseg;
int hasz = FLAGS_GET_Z(ipa->flags);
int hasm = FLAGS_GET_M(ipa->flags);
@@ -427,12 +426,11 @@
opa = ptarray_construct_empty(hasz, hasm, ipa->npoints);
/* Add first point */
- getPoint4d_p(ipa, ipoff, &p1);
+ getPoint4d_p(ipa, 0, &p1);
ptarray_append_point(opa, &p1, LW_FALSE);
- ipoff++;
-
- while (ipoff<ipa->npoints)
+ /* Loop on all other input points */
+ for (i = 1; i < ipa->npoints; i++)
{
/*
* We use these pointers to avoid
@@ -442,32 +440,29 @@
* It looks that casting a variable address (also
* referred to as "type-punned pointer")
* breaks those "strict" rules.
- *
*/
POINT4D *p1ptr=&p1, *p2ptr=&p2;
- getPoint4d_p(ipa, ipoff, &p2);
+ getPoint4d_p(ipa, i, &p2);
segdist = distance2d_pt_pt((POINT2D *)p1ptr, (POINT2D *)p2ptr);
+ /* Split input segment into shorter even chunks */
+ nseg = ceil(segdist / dist);
- if (segdist > dist) /* add an intermediate point */
+ for (j = 1; j < nseg; j++)
{
- pbuf.x = p1.x + (p2.x-p1.x)/segdist * dist;
- pbuf.y = p1.y + (p2.y-p1.y)/segdist * dist;
- if( hasz )
- pbuf.z = p1.z + (p2.z-p1.z)/segdist * dist;
- if( hasm )
- pbuf.m = p1.m + (p2.m-p1.m)/segdist * dist;
+ pbuf.x = p1.x + (p2.x - p1.x) * j / nseg;
+ pbuf.y = p1.y + (p2.y - p1.y) * j / nseg;
+ if (hasz)
+ pbuf.z = p1.z + (p2.z - p1.z) * j / nseg;
+ if (hasm)
+ pbuf.m = p1.m + (p2.m - p1.m) * j / nseg;
ptarray_append_point(opa, &pbuf, LW_FALSE);
- p1 = pbuf;
+ LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
}
- else /* copy second point */
- {
- ptarray_append_point(opa, &p2, (ipa->npoints==2)?LW_TRUE:LW_FALSE);
- p1 = p2;
- ipoff++;
- }
+ ptarray_append_point(opa, &p2, (ipa->npoints == 2) ? LW_TRUE : LW_FALSE);
+ p1 = p2;
LW_ON_INTERRUPT(ptarray_free(opa); return NULL);
}
More information about the postgis-tickets
mailing list