]> granicus.if.org Git - postgis/commitdiff
#2232, avoid accumulated error in SVG rounding
authorPaul Ramsey <pramsey@cleverelephant.ca>
Mon, 30 Nov 2015 16:31:18 +0000 (16:31 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Mon, 30 Nov 2015 16:31:18 +0000 (16:31 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@14457 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/lwout_svg.c
regress/tickets.sql
regress/tickets_expected

index e2194da87f8c790fac3fb4941ffd8a5bd578ef8a..9674a4fbb6146d61cdd71c763721adc04b24a59a 100644 (file)
@@ -547,54 +547,78 @@ pointArray_svg_rel(POINTARRAY *pa, char *output, int close_ring, int precision)
 {
        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;
-
-               getPoint2d_p(pa, i, &pt);
-               if (fabs(pt.x -lpt.x) < OUT_MAX_DOUBLE)
-                       sprintf(x, "%.*f", precision, pt.x -lpt.x);
+               // lpt = pt;
+
+               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);
-
-               ptr += sprintf(ptr," %s %s", x, y);
+                       sprintf(sy, "%g",
+                               fabs(dy) ? dy * -1: dy);
+               trim_trailing_zeros(sy);
+               
+               accum_x += dx;
+               accum_y += dy;
+
+               ptr += sprintf(ptr," %s %s", sx, sy);
        }
 
        return (ptr-output);
index 7a5fdfeead037cc6ef67dd5c0cb059515694aa34..a9ced6e8a53c6fda9aba903aebdc593f731e589e 100644 (file)
@@ -822,6 +822,8 @@ SELECT '#2110.3', 'POINT(0 0)'::geometry = 'POINT(0 0)'::geometry;
 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));
 
index 2aed1ee1340704cc415ac8ddb10f4f5bb572366c..8a83aeb71fe6682e88b97bdc3e8202e2e2d6bc2a 100644 (file)
@@ -244,6 +244,7 @@ ERROR:  invalid GML representation
 #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