Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

In JTS (or GEOS) you can't tell if two linestrings really cross each other. The result is exactly the same whether the lines simply have a point in common but don't cross or if they really cross.

Is there an easy way to differentiate these cases ? thanks

share|improve this question
1  
I don't know about JTS but in postgis there's st_touches (postgis.org/docs/ST_Touches.html) -> Returns TRUE if the geometries have at least one point in common, but their interiors do not intersect. You can use it to eliminate the case you don't call "real" intersection. –  diciu May 30 '12 at 10:06
add comment

2 Answers

I would perform both a left and right single-sided offset buffer on one of the linestrings and test if the other linestring crosses both sides of the offset buffer. You would need to use a suitable small buffer distance for your analysis.

For example, using Shapely:

from shapely.wkt import loads

def actually_crosses(A, B, precis=0.0001):
    """A hybrid spatial predicate that determines if two geometries cross on both sides"""
    return (B.crosses(A) and
            B.crosses(A.parallel_offset(precis, 'left')) and
            B.crosses(A.parallel_offset(precis, 'right')))

# Geometry A: a horizontal line
A = loads('LINESTRING (100 200, 300 200)')
# Geometry Bt: a line that only touches A, but does not actually cross A
Bt = loads('LINESTRING (100 300, 200 200, 300 300)')
# Geometry Bc: a line that actually crosses A
Bc = loads('LINESTRING (100 300, 300 100)')

actually_crosses(A, Bt) # False
actually_crosses(A, Bc) # True

# JTS Validation Suite: Run 4: Test RelateLL
# Case 33: L/L.2-4-4: two LineStrings crossing on one side
A = loads('LINESTRING (60 110, 150 110, 200 160, 250 110, 360 110, 360 210)')
B = loads('LINESTRING (60 110, 110 160, 250 160, 310 160, 360 210)')
A.crosses(B) # True
actually_crosses(A, B) # False

# Case 34: L/L.2-4-5: two LineStrings crossing at two points
A = loads('LINESTRING (130 160, 160 110, 220 110, 250 160, 250 210)')
B = loads('LINESTRING (60 110, 110 160, 250 160, 310 160, 360 210)')
A.crosses(B) # True
actually_crosses(A, B) # True

A similar actually_crosses function could be whipped up in C++ for GEOS or Java for JTS.

share|improve this answer
    
that's a nice answer. But I finally did it by using the angles formed by segments at intersection. Your solution could be faster though. –  undu May 31 '12 at 8:01
    
I just realized there could be some robustness problems with this algorithm, for example if linestring B touches both sides of A, but never actually crosses it. –  Mike T May 31 '12 at 23:15
add comment

You could use the crosses method which should give the information you want.

share|improve this answer
3  
crosses doesn't tell you if line cross (it sounds a little stupid, yes). if you look at the validation suite vividsolutions.com/jts/jtshome.htm run4 (relate LL) cases 33 and 34 illustrate what i mean –  undu May 30 '12 at 9:56
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.