[postgis-tickets] r14457 - #2232, avoid accumulated error in SVG rounding

Paul Ramsey pramsey at cleverelephant.ca
Mon Nov 30 08:31:18 PST 2015


Author: pramsey
Date: 2015-11-30 08:31:18 -0800 (Mon, 30 Nov 2015)
New Revision: 14457

Modified:
   trunk/liblwgeom/lwout_svg.c
   trunk/regress/tickets.sql
   trunk/regress/tickets_expected
Log:
#2232, avoid accumulated error in SVG rounding



Modified: trunk/liblwgeom/lwout_svg.c
===================================================================
--- trunk/liblwgeom/lwout_svg.c	2015-11-30 16:31:08 UTC (rev 14456)
+++ trunk/liblwgeom/lwout_svg.c	2015-11-30 16:31:18 UTC (rev 14457)
@@ -547,54 +547,78 @@
 {
 	int i, end;
 	char *ptr;
-	char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
-	char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
-	POINT2D pt, lpt;
+	char sx[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
+	char sy[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
+	const POINT2D *pt;
 
+	double f = 1.0;
+	double dx, dy, x, y, accum_x, accum_y;
+
 	ptr = output;
 
+	if (precision >= 0) 
+	{
+		f = pow(10, precision);
+	}
+
 	if (close_ring) end = pa->npoints;
 	else end = pa->npoints - 1;
 
 	/* Starting point */
-	getPoint2d_p(pa, 0, &pt);
+	pt = getPoint2d_cp(pa, 0);
 
-	if (fabs(pt.x) < OUT_MAX_DOUBLE)
-		sprintf(x, "%.*f", precision, pt.x);
+	x = round(pt->x*f)/f;
+	y = round(pt->y*f)/f;
+
+	if (fabs(x) < OUT_MAX_DOUBLE)
+		sprintf(sx, "%.*f", precision, x);
 	else
-		sprintf(x, "%g", pt.x);
-	trim_trailing_zeros(x);
+		sprintf(sx, "%g", x);
+	trim_trailing_zeros(sx);
 
-	if (fabs(pt.y) < OUT_MAX_DOUBLE)
-		sprintf(y, "%.*f", precision, fabs(pt.y) ? pt.y * -1 : pt.y);
+	if (fabs(y) < OUT_MAX_DOUBLE)
+		sprintf(sy, "%.*f", precision, fabs(y) ? y * -1 : y);
 	else
-		sprintf(y, "%g", fabs(pt.y) ? pt.y * -1 : pt.y);
-	trim_trailing_zeros(y);
+		sprintf(sy, "%g", fabs(y) ? y * -1 : y);
+	trim_trailing_zeros(sy);
 
-	ptr += sprintf(ptr,"%s %s l", x, y);
+	ptr += sprintf(ptr,"%s %s l", sx, sy);
+	
+	/* accum */
+	accum_x = x;
+	accum_y = y;
 
 	/* All the following ones */
 	for (i=1 ; i < end ; i++)
 	{
-		lpt = pt;
+		// lpt = pt;
 
-		getPoint2d_p(pa, i, &pt);
-		if (fabs(pt.x -lpt.x) < OUT_MAX_DOUBLE)
-			sprintf(x, "%.*f", precision, pt.x -lpt.x);
+		pt = getPoint2d_cp(pa, i);
+		
+		x = round(pt->x*f)/f;
+		y = round(pt->y*f)/f;
+		dx = x - accum_x;
+		dy = y - accum_y;
+		
+		if (fabs(dx) < OUT_MAX_DOUBLE)
+			sprintf(sx, "%.*f", precision, dx);
 		else
-			sprintf(x, "%g", pt.x -lpt.x);
-		trim_trailing_zeros(x);
+			sprintf(sx, "%g", dx);
+		trim_trailing_zeros(sx);
 
 		/* SVG Y axis is reversed, an no need to transform 0 into -0 */
-		if (fabs(pt.y -lpt.y) < OUT_MAX_DOUBLE)
-			sprintf(y, "%.*f", precision,
-			        fabs(pt.y -lpt.y) ? (pt.y - lpt.y) * -1: (pt.y - lpt.y));
+		if (fabs(dy) < OUT_MAX_DOUBLE)
+			sprintf(sy, "%.*f", precision,
+			        fabs(dy) ? dy * -1: dy);
 		else
-			sprintf(y, "%g",
-			        fabs(pt.y -lpt.y) ? (pt.y - lpt.y) * -1: (pt.y - lpt.y));
-		trim_trailing_zeros(y);
+			sprintf(sy, "%g",
+			        fabs(dy) ? dy * -1: dy);
+		trim_trailing_zeros(sy);
+		
+		accum_x += dx;
+		accum_y += dy;
 
-		ptr += sprintf(ptr," %s %s", x, y);
+		ptr += sprintf(ptr," %s %s", sx, sy);
 	}
 
 	return (ptr-output);

Modified: trunk/regress/tickets.sql
===================================================================
--- trunk/regress/tickets.sql	2015-11-30 16:31:08 UTC (rev 14456)
+++ trunk/regress/tickets.sql	2015-11-30 16:31:18 UTC (rev 14457)
@@ -822,6 +822,8 @@
 SELECT '#2145',
 round(ST_Length(St_Segmentize(ST_GeographyFromText('LINESTRING(-89.3000030518 28.2000007629,-89.1999969482 89.1999969482,-89.1999969482 89.1999969482)'), 10000))::numeric,0);
 
+SELECT '#2232', ST_AsSVG('LINESTRING(0 0, 0.4 0, 0.8 0, 1.2 0,1.6 0, 2 0)'::geometry,1,0);
+
 -- #2307 --
 SELECT '#2307', ST_AsText(ST_SnapToGrid(ST_MakeValid('0106000020E6100000010000000103000000010000000A0000004B7DA956B99844C0DB0790FE8B4D1DC010BA74A9AF9444C049AFFC5B8C4D1DC03FC6CC690D9844C0DD67E5628C4D1DC07117B56B0D9844C0C80ABA67C45E1DC0839166ABAF9444C0387D4568C45E1DC010BA74A9AF9444C049AFFC5B8C4D1DC040C3CD74169444C0362EC0608C4D1DC07C1A3B77169444C0DC3ADB40B2641DC03AAE5F68B99844C0242948DEB1641DC04B7DA956B99844C0DB0790FE8B4D1DC0'::geometry),0.0001));
 

Modified: trunk/regress/tickets_expected
===================================================================
--- trunk/regress/tickets_expected	2015-11-30 16:31:08 UTC (rev 14456)
+++ trunk/regress/tickets_expected	2015-11-30 16:31:18 UTC (rev 14457)
@@ -244,6 +244,7 @@
 #2110.2|t
 #2110.3|t
 #2145|6792004
+#2232|M 0 0 l 0 0 1 0 0 0 1 0 0 0
 #2307|MULTIPOLYGON(((-41.1932 -7.3257,-41.1616 -7.3257,-41.1569 -7.3257,-41.1569 -7.3483,-41.1932 -7.3483,-41.1932 -7.3257),(-41.1616 -7.3257,-41.1879 -7.3257,-41.1879 -7.3425,-41.1616 -7.3425,-41.1616 -7.3257)))
 #2409|GeometryCollection[B] with 2 elements
   MultiSurface[] with 2 elements



More information about the postgis-tickets mailing list