Ticket #1855 (assigned defect)

Opened 12 months ago

Last modified 2 months ago

'SQL/MM Spatial exception - curve not simple' exception at adding two polygons

Reported by: wimned Owned by: strk
Priority: medium Milestone: PostGIS 2.1.0
Component: topology Version: 2.0.x
Keywords: Cc:

Description

The code:

CREATE OR REPLACE FUNCTION testerror0()
 returns void AS
$$
    declare geom0 geometry;
    declare geom1 geometry;
BEGIN
    perform CreateTopology('wimpy', 4326, 0.00001);

    geom0 = ST_GeometryFromText(
        'POLYGON((76.26727 9.85751,76.29001 9.90026,
                76.29942 9.86257,76.26727 9.85751))' , 4326);
    geom1 = ST_GeometryFromText(
        'POLYGON((76.31988 9.89696,76.30482 9.88391,
                76.2941 9.88391,76.29409 9.88391,76.29409 9.88392,
                76.29001 9.90026,76.31988 9.89696))' , 4326);
    perform topogeo_AddPolygon('wimpy', geom0);
    perform topogeo_AddPolygon('wimpy', geom1);
END
$$
LANGUAGE plpgsql;

Raises the exception mentioned in the title.

The curve is:

LINESTRING(76.2940920774741 9.88391,76.29409 9.88391,76.2940920774741 9.88391)

Probable cause is a small triangular shaped overlap of the two polygons, about the size of the tolerance. Snapping leads to an edge of 3 points, begin and end point being the same.

I'm using a nightly build from launchpad on my ubuntu box:

deb  http://ppa.launchpad.net/sharpie/postgis-nightly/ubuntu precise main

I managed to edit a workaround in /usr/share/postgresql/9.1/contrib/postgis-2.1/topology.sql:

In function ST_AddEdgeModFace() at the test of the curve being simple

  IF NOT ST_IsSimple(acurve) THEN
    IF ST_NPoints(acurve) = 3 AND   ST_Equals(ST_PointN(acurve,1),ST_PointN(acurve,1))
    THEN
	return 0; -- skip spike
    END IF;
    RAISE EXCEPTION 'SQL/MM Spatial exception - curve not simple %', ST_AsText(acurve);
  END IF;

Inspecting the code calling ST_AddEdgeModFace the return value must be checked, e.g. in TopoGeo?_addLineString():

    IF id IS NULL THEN
      id := topology.ST_AddEdgeModFace(atopology,start_node, end_node,
                                       snapped);
    ELSE
    END IF;

    if id != 0
    then
    	RETURN NEXT id; --value 0 means invalid curve to be skipped
    end if;

These code changes result in the polygons to be entered into the topology properly. (though there is a small face between the two polygons).

The change doesn't break much, the conversion would have been stopped anyhow by the exception

Change History

Changed 12 months ago by strk

Those functions are expected to split whatever you pass in input and always succeed. An exception is a bug. Robustness related, most likely. Changes are this was already fixed with GEOS-3.3.4. Can you show your postgis_full_version() ?

Changed 12 months ago by wimned

output is:

NOTICE:  version: POSTGIS="2.1.0SVN" GEOS="3.3.3-CAPI-1.7.4" PROJ="Rel. 4.7.1, 23 September 2009" LIBXML="2.7.8" LIBJSON="UNKNOWN" (core procs from "2.1.0SVN" need upgrade) TOPOLOGY (topology procs from "2.1.0SVN" need upgrade)

So I'll wait for geos 3.3.4

Changed 12 months ago by strk

GEOS-3.3.4 is out already, nothing to wait for, just go get it. Also, note that "needs upgrade" messages. They want you to load postgis_upgrade_20_minor.sql and topology_upgrade_20_minor.sql

Let me know if it works after all the upgrades.

Changed 12 months ago by strk

  • status changed from new to assigned

Ok, I just tested your functions and could reproduce the problem. This is with POSTGIS="2.0.1SVN r9850" GEOS="3.4.0dev-CAPI-1.8.0 r3670"

Changed 12 months ago by strk

Line 954 of topology/sql/populate.sql contains a comment about code that seems to be there specifically to handle this case, just evidently in the wrong way (ST_MakeValid doesn't clean non-simple lines)

Changed 12 months ago by strk

That line was there to fix #1650. In that case the snapping made the line collapse to a point. In this one it's still a line but non-simple. Will need to add the new testcase into topology/test/regress/topogeo_addlinestring.sql and then fix...

Changed 12 months ago by strk

Extremely simplified case exposing the bug:

SELECT CreateTopology('wimpy');
SELECT topogeo_AddLinestring('wimpy', 'LINESTRING(0 0, 10 0, 0 1)', 2);

Changed 12 months ago by strk

so, after fixing the simplicity of the line next problem is that this cleanup operation changes first and last point, so that you can't call ST_AddEdgeModFace relying on the previously added start/endpoints. In the above scenario the cleanup to (0 0, 10 0) will introduce a new node (10 0) which wasn't known before cleaning up. Sounds like a possibly iterative process in that we could still add (10 0) as the new endpoint but then would need to re-snap possibly introducing more troubles.

As seen in many other cases, a predictable snapping strategy would greatly help all of this.

Changed 12 months ago by strk

Another example simpler to understand, and harder to fix:

SELECT CreateTopology('t');
SELECT topogeo_AddLinestring('t', 'LINESTRING(0 0, 0 100)');
SELECT topogeo_AddLinestring('t', 'LINESTRING(10 51, -100 50, 10 49)', 2);

The intersection points are closer than the tolerance. The code fails at consistently merging them into a single node.

Changed 11 months ago by strk

  • milestone changed from PostGIS 2.0.1 to PostGIS 2.0.2

won't be working on this in time for 2.0.1 (and not even sure it'll ever work in the 2.0 branch)

Changed 6 months ago by strk

  • milestone changed from PostGIS 2.0.2 to PostGIS 2.0.3

Changed 2 months ago by strk

  • milestone changed from PostGIS 2.0.4 to PostGIS 2.1.0
Note: See TracTickets for help on using tickets.