[postgis-tickets] r17677 - lwarc_linearize: Iterate over the number of segments

Raul raul at rmr.ninja
Tue Aug 6 08:59:22 PDT 2019


Author: algunenano
Date: 2019-08-06 08:59:22 -0700 (Tue, 06 Aug 2019)
New Revision: 17677

Modified:
   trunk/NEWS
   trunk/liblwgeom/lwstroke.c
Log:
lwarc_linearize: Iterate over the number of segments

Closes https://github.com/postgis/postgis/pull/458
Closes #4407
References #3719



Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2019-08-04 12:01:32 UTC (rev 17676)
+++ trunk/NEWS	2019-08-06 15:59:22 UTC (rev 17677)
@@ -195,8 +195,10 @@
            ones faster. (Darafei Praliaskouski)
   - #4403, Support for shp2pgsql ability to reproject with copy mode (-D) (Regina Obe)
   - #4410, More descriptive error messages about SRID mismatch (Darafei Praliaskouski)
-  - #4399, TIN and Triangle output support in all output functions (Darafei 
+  - #4399, TIN and Triangle output support in all output functions (Darafei
            Praliaskouski)
+  - #3719, Impose minimun number of segments per arc during linearization
+           (Dan Baston / City of Helsinki, Raúl Marín)
 
 * Fixes *
   - #4342, Move deprecated functions into legacy.sql file

Modified: trunk/liblwgeom/lwstroke.c
===================================================================
--- trunk/liblwgeom/lwstroke.c	2019-08-04 12:01:32 UTC (rev 17676)
+++ trunk/liblwgeom/lwstroke.c	2019-08-06 15:59:22 UTC (rev 17677)
@@ -251,11 +251,12 @@
 	double radius; /* Arc radius */
 	double increment; /* Angle per segment */
 	double angle_shift = 0;
-	double a1, a2, a3, angle;
+	double a1, a2, a3;
 	POINTARRAY *pa;
 	int is_circle = LW_FALSE;
 	int points_added = 0;
 	int reverse = 0;
+	int segments = 0;
 
 	LWDEBUG(2, "lwarc_linearize called.");
 
@@ -339,8 +340,10 @@
 	 * we want shrink the increment enough so that we get two segments
 	 * for a standard arc, or three segments for a complete circle. */
 	int min_segs = is_circle ? 3 : 2;
-	if ( ceil(total_angle / increment) < min_segs)
+	segments = ceil(total_angle / increment);
+	if (segments < min_segs)
 	{
+		segments = min_segs;
 		increment = total_angle / min_segs;
 	}
 
@@ -351,12 +354,12 @@
 		if ( flags & LW_LINEARIZE_FLAG_RETAIN_ANGLE )
 		{
 			/* Number of complete steps */
-			int steps = trunc(total_angle / increment);
+			segments = trunc(total_angle / increment);
 
 			/* Figure out the angle remainder, i.e. the amount of the angle
 			 * that is left after we can take no more complete angle
 			 * increments. */
-			double angle_remainder = total_angle - ( increment * steps );
+			double angle_remainder = total_angle - (increment * segments);
 
 			/* Shift the starting angle by half of the remainder. This
 			 * will have the effect of evenly distributing the remainder
@@ -363,22 +366,33 @@
 			 * among the first and last segments in the arc. */
 			angle_shift = angle_remainder / 2.0;
 
-			LWDEBUGF(2, "lwarc_linearize RETAIN_ANGLE operation requested - "
-			         "total angle %g, steps %d, increment %g, remainder %g",
-			         total_angle * 180 / M_PI, steps, increment * 180 / M_PI,
-			         angle_remainder * 180 / M_PI);
+			LWDEBUGF(2,
+				 "lwarc_linearize RETAIN_ANGLE operation requested - "
+				 "total angle %g, steps %d, increment %g, remainder %g",
+				 total_angle * 180 / M_PI,
+				 segments,
+				 increment * 180 / M_PI,
+				 angle_remainder * 180 / M_PI);
 		}
 		else
 		{
 			/* Number of segments in output */
-			int segs = ceil(total_angle / increment);
+			segments = ceil(total_angle / increment);
 			/* Tweak increment to be regular for all the arc */
-			increment = total_angle/segs;
+			increment = total_angle / segments;
 
-			LWDEBUGF(2, "lwarc_linearize SYMMETRIC operation requested - "
-							"total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d -   I:%g",
-							total_angle*180/M_PI, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
-							segs, increment*180/M_PI);
+			LWDEBUGF(2,
+				 "lwarc_linearize SYMMETRIC operation requested - "
+				 "total angle %g degrees - LINESTRING(%g %g,%g %g,%g %g) - S:%d -   I:%g",
+				 total_angle * 180 / M_PI,
+				 p1->x,
+				 p1->y,
+				 center.x,
+				 center.y,
+				 p3->x,
+				 p3->y,
+				 segments,
+				 increment * 180 / M_PI);
 		}
 	}
 
@@ -409,9 +423,16 @@
 	if( is_circle )
 	{
 		increment = fabs(increment);
+		segments = ceil(total_angle / increment);
+		if (segments < 3)
+		{
+			segments = 3;
+			increment = total_angle / 3;
+		}
 		a3 = a1 + 2.0 * M_PI;
 		a2 = a1 + M_PI;
 		clockwise = LW_FALSE;
+		angle_shift = 0.0;
 	}
 
 	LWDEBUGF(2, "lwarc_linearize angle_shift:%g, increment:%g",
@@ -435,11 +456,20 @@
 	}
 
 	/* Sweep from a1 to a3 */
-	if ( angle_shift ) angle_shift -= increment;
+	int seg_start = 1; /* First point is added manually */
+	int seg_end = segments;
+	if (angle_shift != 0.0)
+	{
+		/* When we have extra angles we need to add the extra segments at the
+		 * start and end that cover those parts of the arc */
+		seg_start = 0;
+		seg_end = segments + 1;
+	}
 	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 )
+	for (int s = seg_start; s < seg_end; s++)
 	{
+		double angle = a1 + increment * s + angle_shift;
 		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);
@@ -544,7 +574,7 @@
                       int flags)
 {
 	LWGEOM *geom;
-	POINTARRAY *ptarray = NULL, *ptarray_out = NULL;
+	POINTARRAY *ptarray = NULL;
 	LWLINE *tmp = NULL;
 	uint32_t i, j;
 	POINT4D p;
@@ -581,9 +611,9 @@
 			return NULL;
 		}
 	}
-	ptarray_out = ptarray_remove_repeated_points(ptarray, 0.0);
-	ptarray_free(ptarray);
-	return lwline_construct(icompound->srid, NULL, ptarray_out);
+
+	ptarray_remove_repeated_points_in_place(ptarray, 0.0, 2);
+	return lwline_construct(icompound->srid, NULL, ptarray);
 }
 
 



More information about the postgis-tickets mailing list