]> granicus.if.org Git - postgis/commitdiff
Do not print more digits than available from lwgeom_to_geojson
authorSandro Santilli <strk@keybit.net>
Wed, 17 Oct 2012 11:43:47 +0000 (11:43 +0000)
committerSandro Santilli <strk@keybit.net>
Wed, 17 Oct 2012 11:43:47 +0000 (11:43 +0000)
See http://trac.osgeo.org/postgis/ticket/2051
Adds tests for the ticket cases.

git-svn-id: http://svn.osgeo.org/postgis/trunk@10451 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/cunit/cu_out_geojson.c
liblwgeom/lwout_geojson.c
liblwgeom/lwutil.c

index a3141a0cac33682ae289e1a64414986567ce53b3..8a13782de2707906cf8579d94c664f02d84276e2 100644 (file)
@@ -88,6 +88,23 @@ static void out_geojson_test_precision(void)
            "{\"type\":\"Point\",\"coordinates\":[1,2]}",
            NULL, 100, 0);
 
+       /* double precision, see http://trac.osgeo.org/postgis/ticket/2051 */
+       do_geojson_test(
+           "POINT(59.99 -59.99)",
+           "{\"type\":\"Point\",\"coordinates\":[59.99,-59.99]}",
+           NULL, 15, 0);
+
+       /* small numbers */
+  /* NOTE: precision of 300 will be converted to max precision (15) 
+   *       and being there no significant digit within that range
+   *       only zeroes will be returned
+   * See http://trac.osgeo.org/postgis/ticket/2051#comment:11
+   */
+       do_geojson_test(
+           "POINT(1E-300 -2E-200)",
+           "{\"type\":\"Point\",\"coordinates\":[0,-0]}",
+           NULL, 300, 0);
+
 }
 
 
index 3542d8a613ea6dfe6df9277cb3c3e6b6469d2876..015dc8bc6237d71d09681042c50ecccf58dc95e3 100644 (file)
@@ -659,20 +659,61 @@ asgeojson_geom_buf(const LWGEOM *geom, char *output, GBOX *bbox, int precision)
        return (ptr-output);
 }
 
+/*
+ * Print an ordinate value using at most the given number of decimal digits
+ *
+ * The actual number of printed decimal digits may be less than the
+ * requested ones if out of significant digits.
+ *
+ * The function will not write more than maxsize bytes, including the
+ * terminating NULL. Returns the number of bytes that would have been
+ * written if there was enough space (excluding terminating NULL).
+ * So a return of ``bufsize'' or more means that the string was
+ * truncated and misses a terminating NULL.
+ *
+ * TODO: export ?
+ *
+ */
+static int
+lwprint_double(double d, int maxdd, char *buf, size_t bufsize)
+{
+  double ad = fabs(d);
+  int ndd = ad < 1 ? 0 : floor(log10(ad))+1; /* non-decimal digits */
+  if (fabs(d) < OUT_MAX_DOUBLE)
+  {
+    if ( maxdd > (OUT_MAX_DOUBLE_PRECISION - ndd) )  maxdd -= ndd;
+    return snprintf(buf, bufsize, "%.*f", maxdd, d);
+  }
+  else
+  {
+    return snprintf(buf, bufsize, "%g", d);
+  }
+}
+
+
 
 static size_t
 pointArray_to_geojson(POINTARRAY *pa, char *output, int precision)
 {
        int i;
        char *ptr;
-       char x[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
-       char y[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
-       char z[OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION+1];
+#define BUFSIZE OUT_MAX_DIGS_DOUBLE+OUT_MAX_DOUBLE_PRECISION
+       char x[BUFSIZE+1];
+       char y[BUFSIZE+1];
+       char z[BUFSIZE+1];
 
        assert ( precision <= OUT_MAX_DOUBLE_PRECISION );
 
+  /* Ensure a terminating NULL at the end of buffers
+   * so that we don't need to check for truncation
+   * inprint_double */
+  x[BUFSIZE] = '\0';
+  y[BUFSIZE] = '\0';
+  z[BUFSIZE] = '\0';
+
        ptr = output;
 
+  /* TODO: rewrite this loop to be simpler and possibly quicker */
        if (!FLAGS_GET_Z(pa->flags))
        {
                for (i=0; i<pa->npoints; i++)
@@ -680,17 +721,10 @@ pointArray_to_geojson(POINTARRAY *pa, char *output, int precision)
                        POINT2D pt;
                        getPoint2d_p(pa, i, &pt);
 
-                       if (fabs(pt.x) < OUT_MAX_DOUBLE)
-                               sprintf(x, "%.*f", precision, pt.x);
-                       else
-                               sprintf(x, "%g", pt.x);
-                       trim_trailing_zeros(x);
-
-                       if (fabs(pt.y) < OUT_MAX_DOUBLE)
-                               sprintf(y, "%.*f", precision, pt.y);
-                       else
-                               sprintf(y, "%g", pt.y);
-                       trim_trailing_zeros(y);
+      lwprint_double(pt.x, precision, x, BUFSIZE);
+      trim_trailing_zeros(x);
+      lwprint_double(pt.y, precision, y, BUFSIZE);
+      trim_trailing_zeros(y);
 
                        if ( i ) ptr += sprintf(ptr, ",");
                        ptr += sprintf(ptr, "[%s,%s]", x, y);
@@ -703,23 +737,12 @@ pointArray_to_geojson(POINTARRAY *pa, char *output, int precision)
                        POINT4D pt;
                        getPoint4d_p(pa, i, &pt);
 
-                       if (fabs(pt.x) < OUT_MAX_DOUBLE)
-                               sprintf(x, "%.*f", precision, pt.x);
-                       else
-                               sprintf(x, "%g", pt.x);
-                       trim_trailing_zeros(x);
-
-                       if (fabs(pt.y) < OUT_MAX_DOUBLE)
-                               sprintf(y, "%.*f", precision, pt.y);
-                       else
-                               sprintf(y, "%g", pt.y);
-                       trim_trailing_zeros(y);
-
-                       if (fabs(pt.z) < OUT_MAX_DOUBLE)
-                               sprintf(z, "%.*f", precision, pt.z);
-                       else
-                               sprintf(z, "%g", pt.z);
-                       trim_trailing_zeros(z);
+      lwprint_double(pt.x, precision, x, BUFSIZE);
+      trim_trailing_zeros(x);
+      lwprint_double(pt.y, precision, y, BUFSIZE);
+      trim_trailing_zeros(y);
+      lwprint_double(pt.z, precision, z, BUFSIZE);
+      trim_trailing_zeros(z);
 
                        if ( i ) ptr += sprintf(ptr, ",");
                        ptr += sprintf(ptr, "[%s,%s,%s]", x, y, z);
index f09de91fcf9ae376799f9f44a2df43625f56b108..549e095dc78924eed0e6b733dd2d8dfc9b396c70 100644 (file)
@@ -271,7 +271,6 @@ trim_trailing_zeros(char *str)
        LWDEBUGF(3, "output: %s", str);
 }
 
-
 /*
  * Returns a new string which contains a maximum of maxlength characters starting
  * from startpos and finishing at endpos (0-based indexing). If the string is