#1641 closed defect (fixed)
TopoGeo_addLineString: SQL/MM Spatial exception - geometry crosses an edge
Reported by: | lrssvt | Owned by: | strk |
---|---|---|---|
Priority: | medium | Milestone: | PostGIS 2.0.0 |
Component: | topology | Version: | 2.0.x |
Keywords: | Cc: |
Description
Running SQL script (attached file polyTopo) I get the following error for my layer (attached file layerPoly).
ERROR: SQL/MM Spatial exception - geometry crosses an edge CONTEXT: PL/pgSQL function "topogeo_addlinestring" line 143 at assignment SQL statement "SELECT array_cat(edges, array_agg(x)) FROM ( select topology.TopoGeo_addLinestring(atopology, rec.geom, tolerance) as x ) as foo" PL/pgSQL function "topogeo_addpolygon" line 23 at assignment SQL statement "INSERT INTO poly_topo.relation(topogeo_id, layer_id, element_type, element_id) SELECT 2, 1, 3, topogeo_addPolygon('poly_topo', '0103000020BC0B0000010000000A000000640FEAD1CAC0DABFA8D653CFF82FE43F807A7AC40C63C9BF0CABC1DC9906E43FB8E2E5B7779ECCBF751D41DFF25ADE3F6084AF11173FC23FF783D649EFFDD93F803B8CFD12DBABBFAE520CA6A8F4C43F785AF3A726AEC93FA0F9F2CB618885BF00B612B697557ABFB4386EE1F850B9BF00CEDC644808873FFF54F94ABD5AC6BF18995CCF8903C0BF3A9BD621CEC4C3BF640FEAD1CAC0DABFA8D653CFF82FE43F'::geometry, 0);" PL/pgSQL function "totopogeom" line 125 at EXECUTE statement
Attachments (6)
Change History (27)
Changed 6 years ago by
Attachment: | polyTopo.sql added |
---|
Changed 6 years ago by
Attachment: | layerPoly.sql added |
---|
comment:1 follow-up: 6 Changed 6 years ago by
comment:2 Changed 6 years ago by
I suspect the default "0" tolerance should be taken as "float8" tolerance which is an expanding grid starting from EPSILON at the origin. This is what I've implemented in the last two cases.
Anyway there's not yet a well-defined semantic for such "tolerance". Research topic: wiki:ToleranceDiscussion
comment:3 Changed 6 years ago by
2 lines o two vertexes:
'LINESTRING(-0.223586 0.474301, 0.142550 0.406124)' 'LINESTRING(0.095989 0.113619, -0.064646 0.470149)'
Add them in sequence to an empty topology, using TopoGeo_addLineString. Reproduces the problem.
Changed 6 years ago by
Attachment: | geomcrossedge.png added |
---|
comment:5 Changed 6 years ago by
Alright in this case noding of the two lines results in the line being added (the semi-vertical one) being split in two. Then first point is added as a node (the lowest) and when last point is added as a note the code fails to find this second node _on_the_ existing line.
The query is in the form: ST_Dwithin(intersection_node, existing_line, 0)
Well, it fails. Using a tolerance of 1e-17 still fails. 1e-16 succeeds in finding it. This part of the code isn't attempting to do any tolerance. We could add that.
But still, what GEOS does is completely out of our control as GEOS uses its own heuristic to get to a result, responding to topology exceptions by reducing precision (for example). So it could still be possible for us to use a too low tolerance to account for what GEOS did.
comment:6 Changed 6 years ago by
Replying to lrssvt:
How do I determine the correct tolerance?
So to answer this again (I didn't really answer before). I suggest you use the value that you do tollerate in your topology. Millimeter precision is enough and your units are meters ? Use 1e-3 !
There is support for specifying a topology-wide tolerance (it's an argument to CreateTopology?) but no funtion currently really uses it at the moment. You can surely use it as a reference.
comment:7 Changed 6 years ago by
Using tolarance of 0.03 works (0.03, in map units, is the length of the short segment of the line sub vertical).
Changed 6 years ago by
Attachment: | toleranceimage.png added |
---|
comment:10 Changed 6 years ago by
comment:11 follow-up: 12 Changed 6 years ago by
Milestone: | PostGIS 2.0.0 → PostGIS 2.1.0 |
---|---|
Summary: | SQL/MM Spatial exception - geometry crosses an edge → TopoGeo_addLineString: SQL/MM Spatial exception - geometry crosses an edge |
Not a 2.0 task, needs a lot more thinking than you can have during closeup
comment:12 Changed 6 years ago by
Replying to strk:
Not a 2.0 task, needs a lot more thinking than you can have during closeup
I know, I am confident in your future success! ;-)
comment:13 follow-up: 15 Changed 6 years ago by
With r9374 I've "exported" the "min-tolerance-for-given-extent" function into its own function. The function is tagged as "internal" and I was thinking it could be used when the functions accepting a tolerance are passed a tolerance value of 0.
BUT, if we had to do that, your toTopoGeom calls would each have a different tolerance value in that each new geometry you'd be adding to the topology would have a different extent. The problem with that is that a short edge closer to the origin may create two very close nodes in the topology and such "vicinity" would be below the tolerance computed when adding a longer edge, resulting in an ambiguity about which node ("hot-pixel") intersections should be snapped to.
So, "global" tolerance is still a much better approach. Tolerance-taking functions could then check topology.tolerance and use that. But if topology.tolerance is till zero you'll need something and you won't know what the max extent of the topology would be.
I start thinking that's why GRASS wants you to create those "locations" before use :P
comment:14 Changed 6 years ago by
Why I not get error, using this (without tolerance):
'LINESTRING(-0.2668 0.5357,-0.2536 0.1239,-0.2536 0.1239)' 'LINESTRING(-0.4582 0.4565,0.05253 0.5806,0.0525 0.5806)'
Good question!
comment:15 Changed 6 years ago by
Replying to strk:
I start thinking that's why GRASS wants you to create those "locations" before use :P
ESRI also, in topology builder, use a default tolerance [1] to 0.0001! I think for the same reason, perhaps!
[1] - http://jiangsuimage.com/ArcGIS/Manager/Help/index.htm#geodatabases/topology_in_arcgis.htm
Do you think you can follow the same approach?
comment:16 Changed 6 years ago by
Milestone: | PostGIS 2.1.0 → PostGIS 2.0.0 |
---|---|
Resolution: | → fixed |
Status: | new → closed |
With r9395 I added a different handing of 0-tolerance. That is, if you pass 0, which is the default, the code goes looking up topology.topology.precision (the tolerance you pass to CreateTopology?) and if that's also zero ends up computing the minimum tolerance required to represent changes in the largest coordinate in input.
There's no automated testing for the topology.precision use or lookup. Well, works fine with the cases we have so far. See #785 for more discussion about this.
comment:17 follow-up: 18 Changed 6 years ago by
@lrssvt : if you want to relaunch the whole import I'll be happy to have a report about what happens now. Also you may want to create the topology with a precision that really reflects your data precision (cm? mm?) and see how that affects further toTopoGeom calls (they should be using the precision you specified at CreateTopology? time as a tolerance).
Changed 6 years ago by
Attachment: | CreateTopologyTolerance.png added |
---|
Changed 6 years ago by
Attachment: | toTopoGeomTolerance.png added |
---|
comment:18 Changed 6 years ago by
Replying to strk:
@lrssvt : if you want to relaunch the whole import I'll be happy to have a report about what happens now. Also you may want to create the topology with a precision that really reflects your data precision (cm? mm?) and see how that affects further toTopoGeom calls (they should be using the precision you specified at CreateTopology? time as a tolerance).
well, I did some tests and now it looks better, but I have a doubt!
I tested the demo attached and the end result will change if I define tolerance in CreateTopology? (see image) or toTopoGeom (see image).
Is that correct?
comment:19 follow-up: 20 Changed 6 years ago by
comment:20 Changed 6 years ago by
comment:21 Changed 6 years ago by
In that case it sounds like a bug, or a missing upgrade on your side. Note that the _order_ in which you add geometries matters. Do you have a short self-contained example reproducing the problem ? Actually, best if attached to another ticket, thanks.
Yes, passing a tolerance to toTopoGeom works:
How do I determine the correct tolerance? Must I necessarily pass it in the function toTopoGeom?