Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

intersects on 0-length linestring returns incorrect result #345

Open
mukoki opened this issue Nov 10, 2018 · 12 comments
Open

intersects on 0-length linestring returns incorrect result #345

mukoki opened this issue Nov 10, 2018 · 12 comments

Comments

@mukoki
Copy link
Contributor

mukoki commented Nov 10, 2018

Intersecting a 0-length linestring should either throw an exception or returns the same result as if it was a point.
test case :
line = wktreader.read("LINESTRING(10 20,10 20)");
line.intersects(line) ==> returns false !!
line.intersects(line.buffer(1)) ==> returns false !!

RelateOp is quite complex, and I did not find an easy way to fix it. I noticed that :

  • when the linestring is added to the graph, the algo removes repeated points and set the single coord into the invalidPoint variable.
  • while calculating the IntersectionMatrix, it still considers that input geomery has dimension 1, which may be a problem

One solution is to throw an exception, but I'd rather process the relateOp as if input geometry was a Point. I don't know if it is possible to substitute input geometry by a point somewhere in the algorithm.
Any thought about it ?

@mukoki
Copy link
Contributor Author

mukoki commented Nov 10, 2018

As a side note - I firstly found this strange behaviour in postgis (ST_Intersects), so geos is probably also concerned.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 10, 2018

The short answer to this is that JTS considers 0-length linestrings to be invalid, so the result of operations on it is undefined.

I did this originally because I thought I read the OCG SFS specification ( 99-009 ) to say that Curves and thus LineStrings were not allowed to be zero-length. (See section 2.1.5). But reading it now I can't see anything that implies that. So perhaps the JTS semantics are fundamentally wrong in this respect!

What the specification does say is that a LineString is closed if the endpoints are equal, and that a closed LineString has no boundary (only an interior). So this means that LINESTRING( x y, x y) is topologically equal to POINT (x y) - as you would expect. So perhaps this means that zero-length linestrings can simple be changed into points internally. This can possibly be done in GeometryGraph.addLineString by detecting this and calling addPoint instead.

Can you try that out and see what happens?

For consistency, fixing this also requires a change in the isValid semantics as well. And associated unit tests. I can't think of anywhere else affected - but that's not a 100% guarantee.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 10, 2018

By the way, in general JTS operations do not throw for invalid inputs, since that could require expensive validity checks.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 10, 2018

Actually allowing zero-length lines leads to another nasty question. Topologically they are equivalent to Points, which have dimension = 0. But the spec states that "Curves are dimension-1 geometries". And in JTS LineStrings are assigned dimension 1 statically. So this might lead to some oddness in the IntersectionMatrix calculations.

@mukoki
Copy link
Contributor Author

mukoki commented Nov 11, 2018

Hi,
Thanks for answering. I was also convinced that 0-length linestring was invalid with respect to specification.
Maybe it depends on how we interpret the statement "Linestring is a one-dimensional geometric object". An inclusive interpretation may accept point (as it already accepts the concept of empty geometry). An more strict interpretation may exclude 0-dimensional geometry which is a kind of degeneracy case for a 1-dimension geometry. An inclusive interpretation may have different consequences and in case one accept 0-length linstring, it would be difficult to justify why we exclude 0-area polygons...
IMHO, we should not change the semantic of isValid which has been here for a long time, but all operations should always return a consistent result or an exception rather than an undefined (possibly inconsistent) result.
I'l try to addPoint instead of addLinestring in the graph in this case as you suggested.
I think it should not change the returned IntersectionMatrix but considering that input is a 0-dimension or a 1-dimension geometry may change how the IM is mapped to to the named predicates.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 13, 2018

I agree that returning a consistent result or an exception is a worth goal, but as I mentioned, this would require expensive validity checks. So I don't think that's practical.

But it's possible to widen the scope of what results are consistent where this doesn't incur too much overhead. Handling zero-length linestrings is likely one of those cases.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 13, 2018

Perhaps it would be possible to handle zero-area polygons in a similar way? (I.e. reducing them to a point).

Of course then the question is whether polygons which collapse to a line should be handled too. That's substantially more expensive to test, however.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 13, 2018

On a different tack, intersects (and possibly covers) are the most useful predicates, and also ones that can have simpler implementations than the full-blown relate computation currently used in JTS. Such an algorithm would almost certainly be able handle degenerate geometries in a more graceful way. So that's another way forward to cope with this issue.

In fact, PreparedGeometry.intersects() already provides such an implementation, and it does return the correct answer for degenerate lines and polygons.

@dr-jts dr-jts changed the title intersects 0-length linestring returns unexpected result intersects 0-length linestring returns incorrect result Nov 13, 2018
@mukoki
Copy link
Contributor Author

mukoki commented Nov 13, 2018

Polygon is probably more difficult to handle. Would it be possible to consider that polygons with a 0-length boundary have dimension 0 and polygons with a boundary > 0 but an area = 0 have dimension 1 ? Or length/area are not strict enough to make such conclusion ?

I did not know about PreparedGeometry.intersects ;-) Interesting. I will test it. Any reason why geometry.intersects use relate instead of PreparedGeometry.intersects in this case ?

@dr-jts
Copy link
Contributor

dr-jts commented Nov 13, 2018

It is probably better to avoid tying subtle relationship logic to length and area, because they are subject to precision issues. Also, that logic is getting a bit complex. Perhaps it's enough to detect polygons with only a single point and handle that in the same way as LineStrings.

@dr-jts
Copy link
Contributor

dr-jts commented Nov 13, 2018

PeparedGeometry uses a different algorithm which allows caching and fast evaluation of the simpler predicates (intersects and covers - which conveniently happen to be the most useful ones).

Also, that code was written some time after the original relate code. I haven't had time to work on wiring it up for the geometry predicates yet.

@dr-jts dr-jts changed the title intersects 0-length linestring returns incorrect result intersects on 0-length linestring returns incorrect result Dec 7, 2018
@dr-jts
Copy link
Contributor

dr-jts commented May 13, 2024

This will be fixed by the forthcoming RelateNG.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants