[postgis-tickets] r16998 - Impose min number of segments per arc during linearization
Daniel Baston
dbaston at gmail.com
Thu Nov 8 04:14:54 PST 2018
Author: dbaston
Date: 2018-11-08 04:14:54 -0800 (Thu, 08 Nov 2018)
New Revision: 16998
Modified:
trunk/doc/introduction.xml
trunk/doc/reference_processing.xml
trunk/liblwgeom/cunit/cu_lwstroke.c
trunk/liblwgeom/lwstroke.c
trunk/regress/core/sql-mm-circularstring_expected
trunk/regress/core/sql-mm-compoundcurve_expected
trunk/regress/core/sql-mm-multicurve_expected
trunk/regress/core/tickets.sql
trunk/regress/core/tickets_expected
Log:
Impose min number of segments per arc during linearization
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
Modified: trunk/doc/introduction.xml
===================================================================
--- trunk/doc/introduction.xml 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/doc/introduction.xml 2018-11-08 12:14:54 UTC (rev 16998)
@@ -317,6 +317,7 @@
<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>
Modified: trunk/doc/reference_processing.xml
===================================================================
--- trunk/doc/reference_processing.xml 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/doc/reference_processing.xml 2018-11-08 12:14:54 UTC (rev 16998)
@@ -976,6 +976,7 @@
<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 @@
<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
Modified: trunk/liblwgeom/cunit/cu_lwstroke.c
===================================================================
--- trunk/liblwgeom/cunit/cu_lwstroke.c 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/liblwgeom/cunit/cu_lwstroke.c 2018-11-08 12:14:54 UTC (rev 16998)
@@ -231,7 +231,7 @@
*/
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 @@
/*
* 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 @@
"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 @@
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)");
Modified: trunk/liblwgeom/lwstroke.c
===================================================================
--- trunk/liblwgeom/lwstroke.c 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/liblwgeom/lwstroke.c 2018-11-08 12:14:54 UTC (rev 16998)
@@ -20,6 +20,7 @@
*
* Copyright (C) 2001-2006 Refractions Research Inc.
* Copyright (C) 2017 Sandro Santilli <strk at kbt.io>
+ * Copyright (C) 2018 Daniel Baston <dbaston at gmail.com>
*
**********************************************************************/
@@ -114,6 +115,101 @@
}
}
+/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
- }}
+ }
+ else
+ {
+ /* Append points directly to the output POINTARRAY,
+ * starting with p1. */
+ pa = to;
- /* Sweep from a1 to a3 */
- if ( ! reverse )
- {
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 @@
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 ) {{
Modified: trunk/regress/core/sql-mm-circularstring_expected
===================================================================
--- trunk/regress/core/sql-mm-circularstring_expected 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/regress/core/sql-mm-circularstring_expected 2018-11-08 12:14:54 UTC (rev 16998)
@@ -44,13 +44,13 @@
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)
Modified: trunk/regress/core/sql-mm-compoundcurve_expected
===================================================================
--- trunk/regress/core/sql-mm-compoundcurve_expected 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/regress/core/sql-mm-compoundcurve_expected 2018-11-08 12:14:54 UTC (rev 16998)
@@ -30,10 +30,10 @@
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)
Modified: trunk/regress/core/sql-mm-multicurve_expected
===================================================================
--- trunk/regress/core/sql-mm-multicurve_expected 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/regress/core/sql-mm-multicurve_expected 2018-11-08 12:14:54 UTC (rev 16998)
@@ -14,10 +14,10 @@
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))
Modified: trunk/regress/core/tickets.sql
===================================================================
--- trunk/regress/core/tickets.sql 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/regress/core/tickets.sql 2018-11-08 12:14:54 UTC (rev 16998)
@@ -1007,6 +1007,10 @@
-- #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;
Modified: trunk/regress/core/tickets_expected
===================================================================
--- trunk/regress/core/tickets_expected 2018-11-08 06:57:59 UTC (rev 16997)
+++ trunk/regress/core/tickets_expected 2018-11-08 12:14:54 UTC (rev 16998)
@@ -305,6 +305,9 @@
#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)
More information about the postgis-tickets
mailing list