]> granicus.if.org Git - postgis/commitdiff
Impose min number of segments per arc during linearization
authorDaniel Baston <dbaston@gmail.com>
Thu, 8 Nov 2018 12:14:54 +0000 (12:14 +0000)
committerDaniel Baston <dbaston@gmail.com>
Thu, 8 Nov 2018 12:14:54 +0000 (12:14 +0000)
This commit sets a fixed minimum of two segments per non-circular arc and three
segments per circular arc.

Funded by City of Helsinki.

Fixes #3719
Closes https://github.com/postgis/postgis/pull/320

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

doc/introduction.xml
doc/reference_processing.xml
liblwgeom/cunit/cu_lwstroke.c
liblwgeom/lwstroke.c
regress/core/sql-mm-circularstring_expected
regress/core/sql-mm-compoundcurve_expected
regress/core/sql-mm-multicurve_expected
regress/core/tickets.sql
regress/core/tickets_expected

index 7befb18cf4e4192b220076847f73875032672d8c..e7831f4dd666c54860ed39a9b7a0202418176886 100644 (file)
                                <listitem><simpara><ulink url="https://www.camptocamp.com">Camptocamp</ulink></simpara></listitem>
                                <listitem><simpara><ulink url="https://carto.com">Carto</ulink></simpara></listitem>
                                <listitem><simpara><ulink url="https://www.boston.gov">City of Boston (DND)</ulink></simpara></listitem>
+                               <listitem><simpara><ulink url="https://www.hel.fi">City of Helsinki</ulink></simpara></listitem>
                                <listitem><simpara><ulink url="https://blog.cleverelephant.ca">Clever Elephant Solutions</ulink></simpara></listitem>
                                <listitem><simpara><ulink url="https://www.alveo.coop">Cooperativa Alveo</ulink></simpara></listitem>
                                <listitem><simpara><ulink url="http://www.elecnor-deimos.com">Deimos Space</ulink></simpara></listitem>
index fd6828e3520d001bdf6a0c0c11f1a4b6b02bd608..7bdba7b43ac3e86bdc66056270b128e4c8b01dab 100644 (file)
@@ -976,6 +976,7 @@ Supported bits are:
 
                <para>Availability: 1.3.0</para>
     <para>Enhanced: 2.4.0 added support for max-deviation and max-angle tolerance, and for symmetric output.</para>
+    <para>Enhanced: 3.0.0 implemented a minimum number of segments per linearized arc to prevent topological collapse.</para>
 
                <para>&sfs_compliant;</para>
                <para>&sqlmm_compliant; SQL-MM 3: 7.1.7</para>
@@ -3027,13 +3028,13 @@ select ST_WrapX(the_geom, -30, 360);
                  <refsection>
                        <title>Examples</title>
                        <para>A circle simplified too much becomes a triangle, medium an octagon, </para>
-                               <programlisting>SELECT ST_Npoints(the_geom) AS np_before, 
-       ST_NPoints(ST_Simplify(the_geom,0.1)) AS np01_notbadcircle, 
+                               <programlisting>SELECT ST_Npoints(the_geom) AS np_before,
+       ST_NPoints(ST_Simplify(the_geom,0.1)) AS np01_notbadcircle,
        ST_NPoints(ST_Simplify(the_geom,0.5)) AS np05_notquitecircle,
-       ST_NPoints(ST_Simplify(the_geom,1)) AS np1_octagon, 
+       ST_NPoints(ST_Simplify(the_geom,1)) AS np1_octagon,
        ST_NPoints(ST_Simplify(the_geom,10)) AS np10_triangle,
        (ST_Simplify(the_geom,100) is null) AS  np100_geometrygoesaway
-  FROM 
+  FROM
     (SELECT ST_Buffer('POINT(1 3)', 10,12) As the_geom) AS foo;
 
  np_before | np01_notbadcircle | np05_notquitecircle | np1_octagon | np10_triangle | np100_geometrygoesaway
index ebe93b02ac4ff7b8363df1a683a2126d41b171b5..96d5413a20571cd3ef9feb82e3029678f9935d0e 100644 (file)
@@ -231,7 +231,7 @@ static void test_lwcurve_linearize(void)
         */
        out = lwcurve_linearize(in, 500, toltype, LW_LINEARIZE_FLAG_SYMMETRIC);
        str = lwgeom_to_text(out, 2);
-       ASSERT_STRING_EQUAL(str, "LINESTRING(20 50,72 -66)");
+       ASSERT_STRING_EQUAL(str, "LINESTRING(20 50,22 -18,72 -66)");
        lwfree(str);
        lwgeom_free(out);
 
@@ -240,7 +240,7 @@ static void test_lwcurve_linearize(void)
        /*
         * ROBUSTNESS: big radius, small tolerance
         * See https://trac.osgeo.org/postgis/ticket/4058
-        * NOTE: we are really only interested in not enterying
+        * NOTE: we are really only interested in not entering
         *       an infinite loop here
         */
        toltype = LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION;
@@ -250,12 +250,12 @@ static void test_lwcurve_linearize(void)
                        "2695865.195999999996275 1125835.189000)");
        out = lwcurve_linearize(in, 0.0001, toltype, 0);
        str = lwgeom_to_text(out, 2);
-       ASSERT_STRING_EQUAL(str, "LINESTRING(2696000 1125700,2695866 1125836)");
+       ASSERT_STRING_EQUAL(str, "LINESTRING(2696000 1125700,2695932 1125768,2695866 1125836)");
        lwfree(str);
        lwgeom_free(out);
        out = lwcurve_linearize(in, 0.0001, toltype, LW_LINEARIZE_FLAG_SYMMETRIC);
        str = lwgeom_to_text(out, 2);
-       ASSERT_STRING_EQUAL(str, "LINESTRING(2696000 1125700,2695866 1125836)");
+       ASSERT_STRING_EQUAL(str, "LINESTRING(2696000 1125700,2695932 1125768,2695866 1125836)");
        lwfree(str);
        lwgeom_free(out);
 #ifndef SKIP_TEST_RETAIN_ANGLE
@@ -280,36 +280,36 @@ static void test_lwcurve_linearize(void)
 
        in = lwgeom_from_text("CIRCULARSTRING(0 0,100 100,200 0)");
 
-       /* Maximum of 45 degrees, asymmetric */
+       /* Maximum of 45 degrees per segment, asymmetric */
        out = lwcurve_linearize(in, M_PI / 4.0, toltype, 0);
        str = lwgeom_to_text(out, 2);
        ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,30 70,100 100,170 70,200 0)");
        lwfree(str);
        lwgeom_free(out);
-       /* Maximum of 0 degrees (invalid) */
+       /* Maximum of 0 degrees per segment (invalid) */
        cu_error_msg_reset();
        out = lwcurve_linearize(in, 0, toltype, 0);
        CU_ASSERT( out == NULL );
        ASSERT_STRING_EQUAL(cu_error_msg, "lwarc_linearize: max angle must be bigger than 0, got 0");
-       /* Maximum of -2 degrees (invalid) */
+       /* Maximum of -2 degrees per segment (invalid) */
        cu_error_msg_reset();
        out = lwcurve_linearize(in, -2, toltype, 0);
        CU_ASSERT( out == NULL );
        ASSERT_STRING_EQUAL(cu_error_msg, "lwarc_linearize: max angle must be bigger than 0, got -2");
-       /* Maximum of 360 degrees, just return endpoints... */
+       /* Maximum of 360 degrees per segment, just return minimum of two segments... */
        cu_error_msg_reset();
        out = lwcurve_linearize(in, M_PI*4, toltype, 0);
        str = lwgeom_to_text(out, 2);
-       ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,200 0)");
+       ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,100 100,200 0)");
        lwfree(str);
        lwgeom_free(out);
-       /* Maximum of 70 degrees, asymmetric */
+       /* Maximum of 70 degrees per segment, asymmetric */
        out = lwcurve_linearize(in, 70 * M_PI / 180, toltype, 0);
        str = lwgeom_to_text(out, 2);
        ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,66 94,176 64,200 0)");
        lwfree(str);
        lwgeom_free(out);
-       /* Maximum of 70 degrees, symmetric */
+       /* Maximum of 70 degrees per segment, symmetric */
        out = lwcurve_linearize(in, 70 * M_PI / 180, toltype, LW_LINEARIZE_FLAG_SYMMETRIC);
        str = lwgeom_to_text(out, 2);
        ASSERT_STRING_EQUAL(str, "LINESTRING(0 0,50 86,150 86,200 0)");
index 29582136b6f27a8f9ab44560b36813ec7ab7416a..b89802c0673a8083ab41273b8559dafc71f6fc9c 100644 (file)
@@ -20,6 +20,7 @@
  *
  * Copyright (C) 2001-2006 Refractions Research Inc.
  * Copyright (C) 2017      Sandro Santilli <strk@kbt.io>
+ * Copyright (C) 2018      Daniel Baston <dbaston@gmail.com>
  *
  **********************************************************************/
 
@@ -114,6 +115,101 @@ static double interpolate_arc(double angle, double a1, double a2, double a3, dou
        }
 }
 
+/* Compute the angle covered by a single segment such that
+ * a given number of segments per quadrant is achieved. */
+static double angle_increment_using_segments_per_quad(double tol)
+{
+       double increment;
+       int perQuad = rint(tol);
+       // error out if tol != perQuad ? (not-round)
+       if ( perQuad != tol )
+       {
+               lwerror("lwarc_linearize: segments per quadrant must be an integer value, got %.15g", tol, perQuad);
+               return -1;
+       }
+       if ( perQuad < 1 )
+       {
+               lwerror("lwarc_linearize: segments per quadrant must be at least 1, got %d", perQuad);
+               return -1;
+       }
+       increment = fabs(M_PI_2 / perQuad);
+       LWDEBUGF(2, "lwarc_linearize: perQuad:%d, increment:%g (%g degrees)", perQuad, increment, increment*180/M_PI);
+
+       return increment;
+}
+
+/* Compute the angle covered by a single quadrant such that
+ * the segment deviates from the arc by no more than a given
+ * amount. */
+static double angle_increment_using_max_deviation(double max_deviation, double radius)
+{
+       double increment, halfAngle, maxErr;
+       if ( max_deviation <= 0 )
+       {
+               lwerror("lwarc_linearize: max deviation must be bigger than 0, got %.15g", max_deviation);
+               return -1;
+       }
+
+       /*
+        * Ref: https://en.wikipedia.org/wiki/Sagitta_(geometry)
+        *
+        * An arc "sagitta" (distance between middle point of arc and
+        * middle point of corresponding chord) is defined as:
+        *
+        *   sagitta = radius * ( 1 - cos( angle ) );
+        *
+        * We want our sagitta to be at most "tolerance" long,
+        * and we want to find out angle, so we use the inverse
+        * formula:
+        *
+        *   tol = radius * ( 1 - cos( angle ) );
+        *   1 - cos( angle ) =  tol/radius
+        *   - cos( angle ) =  tol/radius - 1
+        *   cos( angle ) =  - tol/radius + 1
+        *   angle = acos( 1 - tol/radius )
+        *
+        * Constraints: 1.0 - tol/radius must be between -1 and 1
+        * which means tol must be between 0 and 2 times
+        * the radius, which makes sense as you cannot have a
+        * sagitta bigger than twice the radius!
+        *
+        */
+       maxErr = max_deviation;
+       if ( maxErr > radius * 2 )
+       {
+               maxErr = radius * 2;
+               LWDEBUGF(2, "lwarc_linearize: tolerance %g is too big, "
+                           "using arc-max 2 * radius == %g", tol, maxErr);
+       }
+       do {
+               halfAngle = acos( 1.0 - maxErr / radius );
+               /* TODO: avoid a loop here, going rather straight to
+                *       a minimum angle value */
+               if ( halfAngle != 0 ) break;
+               LWDEBUGF(2, "lwarc_linearize: tolerance %g is too small for this arc"
+                                                               " to compute approximation angle, doubling it", maxErr);
+               maxErr *= 2;
+       } while(1);
+       increment = 2 * halfAngle;
+       LWDEBUGF(2, "lwarc_linearize: maxDiff:%g, radius:%g, halfAngle:%g, increment:%g (%g degrees)", tol, radius, halfAngle, increment, increment*180/M_PI);
+
+       return increment;
+}
+
+/* Check that a given angle is positive and, if so, take
+ * it to be the angle covered by a single segment. */
+static double angle_increment_using_max_angle(double tol)
+{
+       if ( tol <= 0 )
+       {
+               lwerror("lwarc_linearize: max angle must be bigger than 0, got %.15g", tol);
+               return -1;
+       }
+
+       return tol;
+}
+
+
 /**
  * Segmentize an arc
  *
@@ -148,7 +244,7 @@ lwarc_linearize(POINTARRAY *to,
        double increment; /* Angle per segment */
        double angle_shift = 0;
        double a1, a2, a3, angle;
-       POINTARRAY *pa = to;
+       POINTARRAY *pa;
        int is_circle = LW_FALSE;
        int points_added = 0;
        int reverse = 0;
@@ -162,7 +258,7 @@ lwarc_linearize(POINTARRAY *to,
 
        LWDEBUGF(2, " p2 side is %d", p2_side);
 
-       /* Force counterclockwise scan if SYMMETRIC operation is requsested */
+       /* Force counterclockwise scan if SYMMETRIC operation is requested */
        if ( p2_side == -1 && flags & LW_LINEARIZE_FLAG_SYMMETRIC )
        {
                /* swap p1-p3 */
@@ -181,7 +277,7 @@ lwarc_linearize(POINTARRAY *to,
        if ( p1->x == p3->x && p1->y == p3->y )
                is_circle = LW_TRUE;
 
-       /* Negative radius signals straight line, p1/p2/p3 are colinear */
+       /* Negative radius signals straight line, p1/p2/p3 are collinear */
        if ( (radius < 0.0 || p2_side == 0) && ! is_circle )
            return 0;
 
@@ -192,89 +288,30 @@ lwarc_linearize(POINTARRAY *to,
        else
                clockwise = LW_FALSE;
 
-       if ( tolerance_type == LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD )
-       {{
-               int perQuad = rint(tol);
-               // error out if tol != perQuad ? (not-round)
-               if ( perQuad != tol )
-               {
-                       lwerror("lwarc_linearize: segments per quadrant must be an integer value, got %.15g", tol, perQuad);
-                       return -1;
-               }
-               if ( perQuad < 1 )
-               {
-                       lwerror("lwarc_linearize: segments per quadrant must be at least 1, got %d", perQuad);
-                       return -1;
-               }
-               increment = fabs(M_PI_2 / perQuad);
-               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 )
-       {{
-               double halfAngle, maxErr;
-               if ( tol <= 0 )
-               {
-                       lwerror("lwarc_linearize: max deviation must be bigger than 0, got %.15g", tol);
-                       return -1;
-               }
-
-               /*
-                * Ref: https://en.wikipedia.org/wiki/Sagitta_(geometry)
-                *
-                * An arc "sagitta" (distance between middle point of arc and
-                * middle point of corresponding chord) is defined as:
-                *
-                *   sagitta = radius * ( 1 - cos( angle ) );
-                *
-                * We want our sagitta to be at most "tolerance" long,
-                * and we want to find out angle, so we use the inverse
-                * formula:
-                *
-                *   tol = radius * ( 1 - cos( angle ) );
-                *   1 - cos( angle ) =  tol/radius
-                *   - cos( angle ) =  tol/radius - 1
-                *   cos( angle ) =  - tol/radius + 1
-                *   angle = acos( 1 - tol/radius )
-                *
-                * Constraints: 1.0 - tol/radius must be between -1 and 1
-                * which means tol must be between 0 and 2 times
-                * the radius, which makes sense as you cannot have a
-                * sagitta bigger than twice the radius!
-                *
-                */
-               maxErr = tol;
-               if ( maxErr > radius * 2 )
-               {
-                       maxErr = radius * 2;
-                       LWDEBUGF(2, "lwarc_linearize: tolerance %g is too big, "
-                                   "using arc-max 2 * radius == %g", tol, maxErr);
-               }
-               do {
-                       halfAngle = acos( 1.0 - maxErr / radius );
-                       /* TODO: avoid a loop here, going rather straight to
-                        *       a minimum angle value */
-                       if ( halfAngle != 0 ) break;
-                       LWDEBUGF(2, "lwarc_linearize: tolerance %g is too small for this arc"
-                                                                       " to compute approximation angle, doubling it", maxErr);
-                       maxErr *= 2;
-               } while(1);
-               increment = 2 * halfAngle;
-               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 )
+       /* Compute the increment (angle per segment) depending on
+        * our tolerance type. */
+       switch(tolerance_type)
        {
-               increment = tol;
-               if ( increment <= 0 )
-               {
-                       lwerror("lwarc_linearize: max angle must be bigger than 0, got %.15g", tol);
+               case LW_LINEARIZE_TOLERANCE_TYPE_SEGS_PER_QUAD:
+                       increment = angle_increment_using_segments_per_quad(tol);
+                       break;
+               case LW_LINEARIZE_TOLERANCE_TYPE_MAX_DEVIATION:
+                       increment = angle_increment_using_max_deviation(tol, radius);
+                       break;
+               case LW_LINEARIZE_TOLERANCE_TYPE_MAX_ANGLE:
+                       increment = angle_increment_using_max_angle(tol);
+                       break;
+               default:
+                       lwerror("lwarc_linearize: unsupported tolerance type %d", tolerance_type);
                        return -1;
-               }
        }
-       else
+
+       if (increment < 0)
        {
-               lwerror("lwarc_linearize: unsupported tolerance type %d", tolerance_type);
-               return LW_FALSE;
+               /* Error occurred in increment calculation somewhere
+                * (lwerror already called)
+                */
+               return -1;
        }
 
        /* Angles of each point that defines the arc section */
@@ -285,36 +322,55 @@ lwarc_linearize(POINTARRAY *to,
        LWDEBUGF(2, "lwarc_linearize A1:%g (%g) A2:%g (%g) A3:%g (%g)",
                a1, a1*180/M_PI, a2, a2*180/M_PI, a3, a3*180/M_PI);
 
+       /* Calculate total arc angle, in radians */
+       double total_angle = clockwise ? a1 - a3 : a3 - a1;
+       if ( total_angle < 0 ) total_angle += M_PI * 2;
+
+       /* At extreme tolerance values (very low or very high, depending on
+        * the semantic) we may cause our arc to collapse. In this case,
+        * 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)
+       {
+               increment = total_angle / min_segs;
+       }
+
        if ( flags & LW_LINEARIZE_FLAG_SYMMETRIC )
        {{
-               /* Calculate total arc angle, in radians */
-               double angle = clockwise ? a1 - a3 : a3 - a1;
-               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 )
                {{
-                       /* Number of steps */
-                       int steps = trunc(angle / increment);
-                       /* Angle reminder */
-                       double angle_reminder = angle - ( increment * steps );
-                       angle_shift = angle_reminder / 2.0;
+                       /* Number of complete steps */
+                       int steps = 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 );
+
+                       /* Shift the starting angle by half of the remainder. This
+                        * will have the effect of evenly distributing the remainder
+                        * 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, reminder %g",
-                                angle * 180 / M_PI, steps, increment * 180 / M_PI,
-                                angle_reminder * 180 / M_PI);
+                                "total angle %g, steps %d, increment %g, remainder %g",
+                                total_angle * 180 / M_PI, steps, increment * 180 / M_PI,
+                                angle_remainder * 180 / M_PI);
                }}
                else
                {{
                        /* Number of segments in output */
-                       int segs = ceil(angle / increment);
+                       int segs = ceil(total_angle / increment);
                        /* Tweak increment to be regular for all the arc */
-                       increment = angle/segs;
+                       increment = total_angle/segs;
 
                        LWDEBUGF(2, "lwarc_linearize SYMMETRIC operation requested - "
                                                        "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,
+                                                       total_angle*180/M_PI, p1->x, p1->y, center.x, center.y, p3->x, p3->y,
                                                        segs, increment*180/M_PI);
                }}
        }}
@@ -354,17 +410,24 @@ lwarc_linearize(POINTARRAY *to,
        LWDEBUGF(2, "lwarc_linearize angle_shift:%g, increment:%g",
                angle_shift * 180/M_PI, increment * 180/M_PI);
 
-       if ( reverse ) {{
+       if ( reverse )
+       {
+               /* Append points in order to a temporary POINTARRAY and
+                * reverse them before writing to the output POINTARRAY. */
                const int capacity = 8; /* TODO: compute exactly ? */
                pa = ptarray_construct_empty(ptarray_has_z(to), ptarray_has_m(to), capacity);
-       }}
-
-       /* Sweep from a1 to a3 */
-       if ( ! reverse )
+       }
+       else
        {
+               /* Append points directly to the output POINTARRAY,
+                * starting with p1. */
+               pa = to;
+
                ptarray_append_point(pa, p1, LW_FALSE);
+               ++points_added;
        }
-       ++points_added;
+
+       /* Sweep from a1 to a3 */
        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);
@@ -377,7 +440,6 @@ lwarc_linearize(POINTARRAY *to,
                pt.m = interpolate_arc(angle, a1, a2, a3, p1->m, p2->m, p3->m);
                ptarray_append_point(pa, &pt, LW_FALSE);
                ++points_added;
-               angle_shift = 0;
        }
 
        if ( reverse ) {{
index 2ff3739950e77d5e2960138804f71387c4ebdbc5..8b42e1e08ba66ba993a308511a18330754852218 100644 (file)
@@ -44,13 +44,13 @@ asewkb03|01080000800300000000000000000000000000000000000000000000000000000056cd9
 asewkb03|01080000800500000000000000000014c00000000000000000000000000000000000000000000000000000000000001440000000000000f03f000000000000144000000000000000000000000000000040000000000000244000000000000014c000000000000008400000000000002e4000000000000000000000000000001040
 asewkb04|00c00000080000000300000000000000000000000000000000000000000000000000000000000000003fd126145e9ecd563ff00000000000004008000000000000c0000000000000003fe2bec3330188673ff6a09e667f3bcd3ff00000000000004000000000000000
 asewkb04|00c000000800000005c014000000000000000000000000000000000000000000004010000000000000000000000000000040140000000000003ff0000000000000400800000000000040140000000000000000000000000000400000000000000040000000000000004024000000000000c01400000000000040080000000000003ff0000000000000402e000000000000000000000000000040100000000000000000000000000000
-ST_CurveToLine-201|LINESTRING(0 0,0.58578644 1.41421356)
+ST_CurveToLine-201|LINESTRING(0 0,0.15224093 0.76536686,0.58578644 1.41421356)
 ST_CurveToLine-201|LINESTRING(-5 0,-3.53553391 3.53553391,0 5,3.53553391 3.53553391,5 0,6.46446609 -3.53553391,10 -5,13.53553391 -3.53553391,15 0)
-ST_CurveToLine-202|LINESTRINGM(0 0 0,0.58578644 1.41421356 2)
+ST_CurveToLine-202|LINESTRINGM(0 0 0,0.15224093 0.76536686 -1.5,0.58578644 1.41421356 2)
 ST_CurveToLine-202|LINESTRINGM(-5 0 4,-3.53553391 3.53553391 3.5,0 5 3,3.53553391 3.53553391 2.5,5 0 2,6.46446609 -3.53553391 1.5,10 -5 1,13.53553391 -3.53553391 0.5,15 0 0)
-ST_CurveToLine-203|LINESTRING(0 0 0,0.58578644 1.41421356 1)
+ST_CurveToLine-203|LINESTRING(0 0 0,0.15224093 0.76536686 2.25,0.58578644 1.41421356 1)
 ST_CurveToLine-203|LINESTRING(-5 0 0,-3.53553391 3.53553391 0.5,0 5 1,3.53553391 3.53553391 1.5,5 0 2,6.46446609 -3.53553391 2.5,10 -5 3,13.53553391 -3.53553391 3.5,15 0 4)
-ST_CurveToLine-204|LINESTRING(0 0 0 0,0.58578644 1.41421356 1 2)
+ST_CurveToLine-204|LINESTRING(0 0 0 0,0.15224093 0.76536686 2.25 -1.5,0.58578644 1.41421356 1 2)
 ST_CurveToLine-204|LINESTRING(-5 0 0 4,-3.53553391 3.53553391 0.5 3.5,0 5 1 3,3.53553391 3.53553391 1.5 2.5,5 0 2 2,6.46446609 -3.53553391 2.5 1.5,10 -5 3 1,13.53553391 -3.53553391 3.5 0.5,15 0 4 0)
 ST_CurveToLine-401|LINESTRING(0 0,0.15224093 0.76536686,0.58578644 1.41421356)
 ST_CurveToLine-401|LINESTRING(-5 0,-4.61939766 1.91341716,-3.53553391 3.53553391,-1.91341716 4.61939766,0 5,1.91341716 4.61939766,3.53553391 3.53553391,4.61939766 1.91341716,5 0,5.38060234 -1.91341716,6.46446609 -3.53553391,8.08658284 -4.61939766,10 -5,11.91341716 -4.61939766,13.53553391 -3.53553391,14.61939766 -1.91341716,15 0)
index f7bfc39aef43c59fe3a739c71967e518a61c81aa..d139c923a0c8d9246d7c072f722254046ae394c2 100644 (file)
@@ -30,10 +30,10 @@ asewkb01|0109000000020000000108000000030000000000000000000000000000000000000056c
 asewkb02|01090000400200000001080000400300000000000000000000000000000000000000000000000000000056cd9e5e1426d13f000000000000f03f00000000000000c067880133c3bee23fcd3b7f669ea0f63f000000000000004001020000400300000067880133c3bee23fcd3b7f669ea0f63f0000000000000040000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000
 asewkb03|01090000800200000001080000800300000000000000000000000000000000000000000000000000000056cd9e5e1426d13f000000000000f03f000000000000084067880133c3bee23fcd3b7f669ea0f63f000000000000f03f01020000800300000067880133c3bee23fcd3b7f669ea0f63f000000000000f03f000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000
 asewkb04|01090000c00200000001080000c003000000000000000000000000000000000000000000000000000000000000000000000056cd9e5e1426d13f000000000000f03f000000000000084000000000000000c067880133c3bee23fcd3b7f669ea0f63f000000000000f03f000000000000004001020000c00300000067880133c3bee23fcd3b7f669ea0f63f000000000000f03f000000000000004000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-ST_CurveToLine-201|LINESTRING(0 0,0.58578644 1.41421356,2 0,0 0)
-ST_CurveToLine-202|LINESTRINGM(0 0 0,0.58578644 1.41421356 2,2 0 0,0 0 0)
-ST_CurveToLine-203|LINESTRING(0 0 0,0.58578644 1.41421356 1,2 0 0,0 0 0)
-ST_CurveToLine-204|LINESTRING(0 0 0 0,0.58578644 1.41421356 1 2,2 0 0 0,0 0 0 0)
+ST_CurveToLine-201|LINESTRING(0 0,0.15224093 0.76536686,0.58578644 1.41421356,2 0,0 0)
+ST_CurveToLine-202|LINESTRINGM(0 0 0,0.15224093 0.76536686 -1.5,0.58578644 1.41421356 2,2 0 0,0 0 0)
+ST_CurveToLine-203|LINESTRING(0 0 0,0.15224093 0.76536686 2.25,0.58578644 1.41421356 1,2 0 0,0 0 0)
+ST_CurveToLine-204|LINESTRING(0 0 0 0,0.15224093 0.76536686 2.25 -1.5,0.58578644 1.41421356 1 2,2 0 0 0,0 0 0 0)
 ST_CurveToLine-401|LINESTRING(0 0,0.15224093 0.76536686,0.58578644 1.41421356,2 0,0 0)
 ST_CurveToLine-402|LINESTRINGM(0 0 0,0.15224093 0.76536686 -1.5,0.58578644 1.41421356 2,2 0 0,0 0 0)
 ST_CurveToLine-403|LINESTRING(0 0 0,0.15224093 0.76536686 2.25,0.58578644 1.41421356 1,2 0 0,0 0 0)
index 7c7f2c35f9f9b2d170896de44d9b915831d32a2c..fa6fad3eef91db9db88d6bc8b94a2cd619fc5346 100644 (file)
@@ -14,10 +14,10 @@ asewkb01|010b0000000200000001020000000400000000000000000014400000000000001440000
 asewkb02|004000000b00000002004000000200000004401400000000000040140000000000004008000000000000400800000000000040140000000000004000000000000000400800000000000040080000000000003ff0000000000000000000000000000040080000000000003ff00000000000000040000008000000030000000000000000000000000000000000000000000000003fd126145e9ecd563ff0000000000000c0000000000000003fe2bec3330188673ff6a09e667f3bcd4000000000000000
 asewkb03|010b0000800200000001020000800400000000000000000014400000000000001440000000000000f03f00000000000008400000000000001440000000000000004000000000000008400000000000000840000000000000084000000000000000000000000000000840000000000000f03f01080000800300000000000000000000000000000000000000000000000000000056cd9e5e1426d13f000000000000f03f000000000000084067880133c3bee23fcd3b7f669ea0f63f000000000000f03f
 asewkb04|00c000000b0000000200c000000200000004401400000000000040140000000000003ff0000000000000400800000000000040080000000000004014000000000000400000000000000040000000000000004008000000000000400800000000000040080000000000003ff0000000000000000000000000000040080000000000003ff00000000000003ff000000000000000c00000080000000300000000000000000000000000000000000000000000000000000000000000003fd126145e9ecd563ff00000000000004008000000000000c0000000000000003fe2bec3330188673ff6a09e667f3bcd3ff00000000000004000000000000000
-ST_CurveToLine-201|MULTILINESTRING((5 5,3 5,3 3,0 3),(0 0,0.58578644 1.41421356))
-ST_CurveToLine-202|MULTILINESTRINGM((5 5 3,3 5 2,3 3 1,0 3 1),(0 0 0,0.58578644 1.41421356 2))
-ST_CurveToLine-203|MULTILINESTRING((5 5 1,3 5 2,3 3 3,0 3 1),(0 0 0,0.58578644 1.41421356 1))
-ST_CurveToLine-204|MULTILINESTRING((5 5 1 3,3 5 2 2,3 3 3 1,0 3 1 1),(0 0 0 0,0.58578644 1.41421356 1 2))
+ST_CurveToLine-201|MULTILINESTRING((5 5,3 5,3 3,0 3),(0 0,0.15224093 0.76536686,0.58578644 1.41421356))
+ST_CurveToLine-202|MULTILINESTRINGM((5 5 3,3 5 2,3 3 1,0 3 1),(0 0 0,0.15224093 0.76536686 -1.5,0.58578644 1.41421356 2))
+ST_CurveToLine-203|MULTILINESTRING((5 5 1,3 5 2,3 3 3,0 3 1),(0 0 0,0.15224093 0.76536686 2.25,0.58578644 1.41421356 1))
+ST_CurveToLine-204|MULTILINESTRING((5 5 1 3,3 5 2 2,3 3 3 1,0 3 1 1),(0 0 0 0,0.15224093 0.76536686 2.25 -1.5,0.58578644 1.41421356 1 2))
 ST_CurveToLine-401|MULTILINESTRING((5 5,3 5,3 3,0 3),(0 0,0.15224093 0.76536686,0.58578644 1.41421356))
 ST_CurveToLine-402|MULTILINESTRINGM((5 5 3,3 5 2,3 3 1,0 3 1),(0 0 0,0.15224093 0.76536686 -1.5,0.58578644 1.41421356 2))
 ST_CurveToLine-403|MULTILINESTRING((5 5 1,3 5 2,3 3 3,0 3 1),(0 0 0,0.15224093 0.76536686 2.25,0.58578644 1.41421356 1))
index 3ae75f92cb135903be71b0d70f11d94d8a32ab2c..44f6792631da5ad41790bc46cea5e9400cb15e0f 100644 (file)
@@ -1007,6 +1007,10 @@ SELECT '#3704', ST_AsX3D('LINESTRING EMPTY') = '';
 -- #3709
 select '#3709', ST_SnapToGrid(ST_Project('SRID=4326;POINT(1 1)'::geography, 100000, 20)::geometry, 0.0001) = ST_SnapToGrid(ST_Project('SRID=4326;POINT(1 1)'::geography, -100000, 20+pi())::geometry, 0.0001);
 
+-- #3719
+select '#3719a', ST_IsValid('CURVEPOLYGON((25495445.625 6671632.625, 25495445.625 6671711.375, 25495555.375 6671711.375, 25495555.375 6671632.625, 25495445.625 6671632.625), COMPOUNDCURVE(CIRCULARSTRING(25495368.0441 6671726.9312,25495368.3959388 6671726.93601515,25495368.7478 6671726.9333), (25495368.7478 6671726.9333,25495368.0441 6671726.9312)))');
+select '#3719b', ST_IsValid('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(1.0441 2.9312,1.3959388 2.93601515,1.7478 2.9333), (1.7478 2.9333,1.0441 2.9312)))'::geometry);
+
 -- #3774
 select '#3774', abs(pi() + 2 - st_length('COMPOUNDCURVE(CIRCULARSTRING(0 0, 1 1, 2 0), (2 0, 4 0))'::geometry)) < 0.000000001;
 
index b31dc914d80bf8f945428960aec246c7fde72cc6..8e8677af031a7c85e48a31499f3cb0858e9e4059 100644 (file)
@@ -305,6 +305,9 @@ ERROR:  invalid KML representation
 #3627b|t
 #3704|t
 #3709|t
+NOTICE:  Hole lies outside shell at or near point 25495368.044100001 6671726.9312000005
+#3719a|f
+#3719b|t
 #3774|t
 #1014a|POINT(0 0)
 #1014a|POINT(0 0)