[postgis-tickets] r15623 - Ensure direction neutrality in symmetric arc linearization

Sandro Santilli strk at kbt.io
Tue Sep 5 02:37:56 PDT 2017


Author: strk
Date: 2017-09-05 02:37:56 -0700 (Tue, 05 Sep 2017)
New Revision: 15623

Modified:
   trunk/liblwgeom/cunit/cu_lwstroke.c
   trunk/liblwgeom/lwstroke.c
Log:
Ensure direction neutrality in symmetric arc linearization

Includes test.
This is a followup to #3772

Modified: trunk/liblwgeom/cunit/cu_lwstroke.c
===================================================================
--- trunk/liblwgeom/cunit/cu_lwstroke.c	2017-09-04 17:55:05 UTC (rev 15622)
+++ trunk/liblwgeom/cunit/cu_lwstroke.c	2017-09-05 09:37:56 UTC (rev 15623)
@@ -50,7 +50,7 @@
 static void test_lwcurve_linearize(void)
 {
 	LWGEOM *in;
-	LWGEOM *out;
+	LWGEOM *out, *out2;
 	char *str;
 	int toltype;
 
@@ -286,9 +286,37 @@
 
 	lwgeom_free(in);
 
+	/***********************************************************
+	 *
+	 *  Direction neutrality
+	 *
+	 ***********************************************************/
+
+	in = lwgeom_from_text("CIRCULARSTRING(71.96 -65.64,22.2 -18.52,20 50)");
+	out = lwcurve_linearize(in, M_PI/4.0,
+													 LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE,
+													 LW_LINEARIZE_FLAG_SYMMETRIC);
+	lwgeom_reverse(in);
+	out2 = lwcurve_linearize(in, M_PI/4.0,
+													 LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE,
+													 LW_LINEARIZE_FLAG_SYMMETRIC);
+	lwgeom_reverse(out2);
+	if ( ! lwgeom_same(out, out2) )
+	{
+		fprintf(stderr, "linearization is not direction neutral:\n");
+		str = lwgeom_to_wkt(out, WKT_ISO, 18, NULL);
+		fprintf(stderr, "OUT1: %s\n", str);
+		lwfree(str);
+		str = lwgeom_to_wkt(out2, WKT_ISO, 18, NULL);
+		fprintf(stderr, "OUT2: %s\n", str);
+		lwfree(str);
+	}
+	CU_ASSERT( lwgeom_same(out, out2) );
+	lwgeom_free(out2);
+	lwgeom_free(out);
+	lwgeom_free(in);
 }
 
-
 /*
 ** Used by the test harness to register the tests in this file.
 */

Modified: trunk/liblwgeom/lwstroke.c
===================================================================
--- trunk/liblwgeom/lwstroke.c	2017-09-04 17:55:05 UTC (rev 15622)
+++ trunk/liblwgeom/lwstroke.c	2017-09-05 09:37:56 UTC (rev 15623)
@@ -114,6 +114,8 @@
 /**
  * Segmentize an arc
  *
+ * Does not add the final vertex
+ *
  * @param to POINTARRAY to append segmentized vertices to
  * @param p1 first point defining the arc
  * @param p2 second point defining the arc
@@ -124,6 +126,7 @@
  *
  * @return number of points appended (0 if collinear),
  *         or -1 on error (lwerror would be called).
+ *
  */
 static int
 lwarc_linearize(POINTARRAY *to,
@@ -145,12 +148,26 @@
 	POINTARRAY *pa = to;
 	int is_circle = LW_FALSE;
 	int points_added = 0;
+	int reverse = 0;
 
 	LWDEBUG(2, "lwarc_linearize called.");
 
+	p2_side = lw_segment_side(t1, t3, t2);
+
+	/* Force counterclockwise scan if SYMMETRIC operation is requsested */
+	if ( p2_side == -1 && flags & LW_LINEARIZE_FLAG_SYMMETRIC )
+	{
+		/* swap p1-p3 */
+		t1 = (POINT2D*)p3;
+		t3 = (POINT2D*)p1;
+		p1 = (POINT4D*)t1;
+		p3 = (POINT4D*)t3;
+		p2_side = 1;
+		reverse = 1;
+	}
+
 	radius = lw_arc_center(t1, t2, t3, &center);
 	LWDEBUGF(2, " center is POINT(%.15g %.15g) - radius:%g", center.x, center.y, radius);
-	p2_side = lw_segment_side(t1, t3, t2);
 
 	/* Matched start/end points imply circle */
 	if ( p1->x == p3->x && p1->y == p3->y )
@@ -289,8 +306,16 @@
 	LWDEBUGF(2, "lwarc_linearize angle_shift:%g, increment:%g",
 		angle_shift * 180/M_PI, increment * 180/M_PI);
 
+	if ( reverse ) {{
+		const int capacity = 8; /* TODO: compute exactly ? */
+		pa = ptarray_construct_empty(ptarray_has_z(to), ptarray_has_m(to), capacity);
+	}}
+
 	/* Sweep from a1 to a3 */
-	ptarray_append_point(pa, p1, LW_FALSE);
+	if ( ! reverse )
+	{
+		ptarray_append_point(pa, p1, LW_FALSE);
+	}
 	++points_added;
 	if ( angle_shift ) angle_shift -= increment;
 	LWDEBUGF(2, "a1:%g (%g deg), a3:%g (%g deg), inc:%g, shi:%g, cw:%d",
@@ -306,6 +331,17 @@
 		++points_added;
 		angle_shift = 0;
 	}
+
+	if ( reverse ) {{
+		int i;
+		ptarray_append_point(to, p3, LW_FALSE);
+		for ( i=pa->npoints; i>0; i-- ) {
+			getPoint4d_p(pa, i-1, &pt);
+			ptarray_append_point(to, &pt, LW_FALSE);
+		}
+		ptarray_free(pa);
+	}}
+
 	return points_added;
 }
 



More information about the postgis-tickets mailing list