[postgis-tickets] r15465 - Fix angle reminder computation

Sandro Santilli strk at kbt.io
Tue Jun 27 05:37:07 PDT 2017


Author: strk
Date: 2017-06-27 05:37:07 -0700 (Tue, 27 Jun 2017)
New Revision: 15465

Modified:
   trunk/liblwgeom/cunit/cu_lwstroke.c
   trunk/liblwgeom/lwstroke.c
   trunk/regress/curvetoline_expected
Log:
Fix angle reminder computation

Closes #3772 again (see comment:6)
Add specific testcase

Modified: trunk/liblwgeom/cunit/cu_lwstroke.c
===================================================================
--- trunk/liblwgeom/cunit/cu_lwstroke.c	2017-06-26 20:56:28 UTC (rev 15464)
+++ trunk/liblwgeom/cunit/cu_lwstroke.c	2017-06-27 12:37:07 UTC (rev 15465)
@@ -20,7 +20,9 @@
 #include "liblwgeom_internal.h"
 #include "cu_tester.h"
 
+/* #define SKIP_TEST_RETAIN_ANGLE 1 */
 
+
 static LWGEOM* lwgeom_from_text(const char *str)
 {
 	LWGEOM_PARSER_RESULT r;
@@ -108,21 +110,25 @@
 	ASSERT_STRING_EQUAL(str, "LINESTRING(30 70,74 96,126 96,170 70,196 26,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+
 	/* 3 segment per quadrant - symmetric */
 	out = lwcurve_linearize(in, 3, toltype, LW_LINEARIZE_FLAG_SYMMETRIC);
 	str = lwgeom_to_text(out, 2);
 	ASSERT_STRING_EQUAL(str, "LINESTRING(30 70,70 96,116 98,158 80,190 46,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+
+#ifndef SKIP_TEST_RETAIN_ANGLE
 	/* 3 segment per quadrant - symmetric/retain_angle */
 	out = lwcurve_linearize(in, 3, toltype,
 		LW_LINEARIZE_FLAG_SYMMETRIC |
 		LW_LINEARIZE_FLAG_RETAIN_ANGLE
 	);
 	str = lwgeom_to_text(out, 2);
-	ASSERT_STRING_EQUAL(str, "LINESTRING(30 70,62 92,114 100,160 80,192 38,200 0)");
+	ASSERT_STRING_EQUAL(str, "LINESTRING(30 70,40 80,86 100,138 92,180 60,200 14,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+#endif /* SKIP_TEST_RETAIN_ANGLE */
 
 	lwgeom_free(in);
 
@@ -170,18 +176,39 @@
 	ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,50 86,150 86,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+
+#ifndef SKIP_TEST_RETAIN_ANGLE
 	/* Maximum of 20 units of difference, symmetric/retain angle */
 	out = lwcurve_linearize(in, 20, toltype,
 		LW_LINEARIZE_FLAG_SYMMETRIC |
 		LW_LINEARIZE_FLAG_RETAIN_ANGLE
 	);
 	str = lwgeom_to_text(out, 2);
-	ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,40 80,160 80,200 0)");
+	ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,4 28,100 100,196 28,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+#endif /* SKIP_TEST_RETAIN_ANGLE */
 
 	lwgeom_free(in);
 
+	/*
+	 * Clockwise ~90 degrees south-west to north-west quadrants
+	 * starting at ~22 degrees west of vertical line
+	 *
+	 * See https://trac.osgeo.org/postgis/ticket/3772
+	 */
+	toltype = LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION;
+	in = lwgeom_from_text("CIRCULARSTRING(71.96 -65.64,22.2 -18.52,20 50)");
+
+	/* 4 units of max deviation - symmetric */
+	out = lwcurve_linearize(in, 4, toltype, LW_LINEARIZE_FLAG_SYMMETRIC);
+	str = lwgeom_to_text(out, 2);
+	ASSERT_STRING_EQUAL(str, "LINESTRING(72 -66,34 -38,16 4,20 50)");
+	lwfree(str);
+	lwgeom_free(out);
+
+	lwgeom_free(in);
+
 	/***********************************************************
 	 *
 	 *  Maximum angle tolerance type
@@ -227,15 +254,18 @@
 	ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,50 86,150 86,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+
+#ifndef SKIP_TEST_RETAIN_ANGLE
 	/* Maximum of 70 degrees, symmetric/retain angle */
 	out = lwcurve_linearize(in, 70 * M_PI / 180, toltype,
 		LW_LINEARIZE_FLAG_SYMMETRIC |
 		LW_LINEARIZE_FLAG_RETAIN_ANGLE
 	);
 	str = lwgeom_to_text(out, 2);
-	ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,42 82,158 82,200 0)");
+	ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,6 34,100 100,194 34,200 0)");
 	lwfree(str);
 	lwgeom_free(out);
+#endif /* SKIP_TEST_RETAIN_ANGLE */
 
 	lwgeom_free(in);
 

Modified: trunk/liblwgeom/lwstroke.c
===================================================================
--- trunk/liblwgeom/lwstroke.c	2017-06-26 20:56:28 UTC (rev 15464)
+++ trunk/liblwgeom/lwstroke.c	2017-06-27 12:37:07 UTC (rev 15465)
@@ -31,7 +31,7 @@
 
 #include "liblwgeom_internal.h"
 
-/* #define POSTGIS_DEBUG_LEVEL 4 */
+/*#define POSTGIS_DEBUG_LEVEL 3*/
 
 #include "lwgeom_log.h"
 
@@ -147,6 +147,7 @@
 	LWDEBUG(2, "lwarc_linearize called.");
 
 	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 */
@@ -179,7 +180,7 @@
 			return -1;
 		}
 		increment = fabs(M_PI_2 / perQuad);
-		LWDEBUGF(2, "lwarc_linearize: perQuad:%d, increment:%g", perQuad, increment);
+		LWDEBUGF(2, "lwarc_linearize: perQuad:%d, increment:%g (%g degrees)", perQuad, increment, increment*180/M_PI);
 
 	}}
 	else if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION )
@@ -192,7 +193,7 @@
 		}
 		halfAngle = acos( -tol / radius + 1 );
 		increment = 2 * halfAngle;
-		LWDEBUGF(2, "lwarc_linearize: maxDiff:%g, radius:%g, halfAngle:%g, increment:%g", tol, radius, halfAngle, increment);
+		LWDEBUGF(2, "lwarc_linearize: maxDiff:%g, radius:%g, halfAngle:%g, increment:%g (%g degrees)", tol, radius, halfAngle, increment, increment*180/M_PI);
 	}}
 	else if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE )
 	{
@@ -214,42 +215,47 @@
 	a2 = atan2(p2->y - center.y, p2->x - center.x);
 	a3 = atan2(p3->y - center.y, p3->x - center.x);
 
+	LWDEBUGF(2, "lwarc_linearize A1:%g A2:%g A3:%g",
+		a1*180/M_PI, a2*180/M_PI, a3*180/M_PI);
+
 	if ( flags & LW_LINEARIZE_FLAG_SYMMETRIC )
-	{
+	{{
+		/* Calculate total arc angle, in radians */
+		double angle = a1 - a3;
+		if ( angle < 0 ) angle += M_PI * 2;
+		LWDEBUGF(2, "lwarc_linearize SYMMETRIC requested - total angle %g deg",
+			         angle * 180 / M_PI);
 		if ( flags & LW_LINEARIZE_FLAG_RETAIN_ANGLE )
 		{{
-			/* Total arc angle, in radians */
-			double angle = a3 - a1;
 			/* Number of steps */
-			int steps = floor(angle / increment);
+			int steps = trunc(angle / increment);
 			/* Angle reminder */
 			double angle_reminder = angle - ( increment * steps );
 			angle_shift = angle_reminder / 2.0;
 
-			LWDEBUGF(2, "lwarc_linearize SYMMETRIC/RETAIN_ANGLE operation requested - "
-			         "A:%g - LINESTRING(%g %g,%g %g,%g %g) - R:%g",
-			         angle, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
-			         angle_reminder);
+			LWDEBUGF(2, "lwarc_linearize RETAIN_ANGLE operation requested - "
+			         "total angle %g, steps %d, increment %g, reminder %g",
+			         angle * 180 / M_PI, steps, increment * 180 / M_PI,
+			         angle_reminder * 180 / M_PI);
 		}}
 		else
 		{{
-			/* Total arc angle, in radians */
-			double angle = fabs(a3 - a1);
 			/* Number of segments in output */
 			int segs = ceil(angle / increment);
 			/* Tweak increment to be regular for all the arc */
 			increment = angle/segs;
 
 			LWDEBUGF(2, "lwarc_linearize SYMMETRIC operation requested - "
-							"A:%g - LINESTRING(%g %g,%g %g,%g %g) - S:%d - I:%g",
-							angle, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
-							segs, increment);
+							"total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d -   I:%g",
+							angle*180/M_PI, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
+							segs, increment*180/M_PI);
 		}}
-	}
+	}}
 
 	/* p2 on left side => clockwise sweep */
 	if ( clockwise )
 	{
+		LWDEBUG(2, " Clockwise sweep");
 		increment *= -1;
 		angle_shift *= -1;
 		/* Adjust a3 down so we can decrement from a1 to a3 cleanly */
@@ -261,6 +267,7 @@
 	/* p2 on right side => counter-clockwise sweep */
 	else
 	{
+		LWDEBUG(2, " Counterclockwise sweep");
 		/* Adjust a3 up so we can increment from a1 to a3 cleanly */
 		if ( a3 < a1 )
 			a3 += 2.0 * M_PI;
@@ -277,11 +284,18 @@
 		clockwise = LW_FALSE;
 	}
 
+	LWDEBUGF(2, "lwarc_linearize angle_shift:%g, increment:%g",
+		angle_shift * 180/M_PI, increment * 180/M_PI);
+
 	/* Sweep from a1 to a3 */
 	ptarray_append_point(pa, p1, LW_FALSE);
 	++points_added;
-	for ( angle = a1 + increment - angle_shift; clockwise ? angle > a3 : angle < a3; angle += increment )
+	if ( angle_shift ) angle_shift -= increment;
+	LWDEBUGF(2, "a1:%g (%g deg), a3:%g (%g deg), inc:%g, shi:%g, cw:%d",
+		a1, a1 * 180 / M_PI, a3, a3 * 180 / M_PI, increment, angle_shift, clockwise);
+	for ( angle = a1 + increment + angle_shift; clockwise ? angle > a3 : angle < a3; angle += increment )
 	{
+		LWDEBUGF(2, " SA: %g ( %g deg )", angle, angle*180/M_PI);
 		pt.x = center.x + radius * cos(angle);
 		pt.y = center.y + radius * sin(angle);
 		pt.z = interpolate_arc(angle, a1, a2, a3, p1->z, p2->z, p3->z);

Modified: trunk/regress/curvetoline_expected
===================================================================
--- trunk/regress/curvetoline_expected	2017-06-26 20:56:28 UTC (rev 15464)
+++ trunk/regress/curvetoline_expected	2017-06-27 12:37:07 UTC (rev 15465)
@@ -3,6 +3,6 @@
 semicircle2.sym|LINESTRING(0 0,50 -86,150 -86,200 0)
 semicircle3|LINESTRING(0 0,24 -64,82 -98,150 -86,194 -34,200 0)
 semicircle3.sym|LINESTRING(0 0,20 -58,70 -96,130 -96,180 -58,200 0)
-semicircle3.sym.ret|LINESTRING(0 0,14 -50,66 -94,134 -94,186 -50,200 0)
+semicircle3.sym.ret|LINESTRING(0 0,2 -18,36 -76,100 -100,164 -76,198 -18,200 0)
 multiarc1|LINESTRING(0 0,30 -70,100 -100,170 -70,200 0,258 142,400 200,542 142,600 0)
 multiarc1.maxerr20.sym|LINESTRING(0 0,50 -86,150 -86,200 0,258 142,400 200,542 142,600 0)



More information about the postgis-tickets mailing list