Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/methods/geom_relations/crosses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ import GeoInterface as GI, GeometryOps as GO
# TODO: Add working example
```
"""
crosses(g1, g2)::Bool = crosses(trait(g1), g1, trait(g2), g2)::Bool

crosses(::MultiPointTrait, g1, ::LineStringTrait, g2)::Bool = multipoint_crosses_line(g1, g2)
crosses(::MultiPointTrait, g1, ::PolygonTrait, g2)::Bool = multipoint_crosses_poly(g1, g2)
crosses(::LineStringTrait, g1, ::MultiPointTrait, g2)::Bool = multipoint_crosses_lines(g2, g1)
crosses(::LineStringTrait, g1, ::PolygonTrait, g2)::Bool = line_crosses_poly(g1, g2)
crosses(::LineStringTrait, g1, ::LineStringTrait, g2)::Bool = line_crosses_line(g1, g2)
crosses(::PolygonTrait, g1, ::MultiPointTrait, g2)::Bool = multipoint_crosses_poly(g2, g1)
crosses(::PolygonTrait, g1, ::LineStringTrait, g2)::Bool = line_crosses_poly(g2, g1)
crosses(g1, g2)::Bool = _crosses(GI.trait(g1), g1, GI.trait(g2), g2)::Bool

_crosses(::GI.MultiPointTrait, g1, ::GI.LineStringTrait, g2)::Bool = multipoint_crosses_line(g1, g2)
_crosses(::GI.MultiPointTrait, g1, ::GI.PolygonTrait, g2)::Bool = multipoint_crosses_poly(g1, g2)
_crosses(::GI.LineStringTrait, g1, ::GI.MultiPointTrait, g2)::Bool = multipoint_crosses_lines(g2, g1)
_crosses(::GI.LineStringTrait, g1, ::GI.PolygonTrait, g2)::Bool = line_crosses_poly(g1, g2)
_crosses(::GI.LineStringTrait, g1, ::GI.LineStringTrait, g2)::Bool = line_crosses_line(g1, g2)
_crosses(::GI.PolygonTrait, g1, ::GI.MultiPointTrait, g2)::Bool = multipoint_crosses_poly(g2, g1)
_crosses(::GI.PolygonTrait, g1, ::GI.LineStringTrait, g2)::Bool = line_crosses_poly(g2, g1)

"""
crosses(g1)
Expand Down
41 changes: 22 additions & 19 deletions src/methods/geom_relations/overlaps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ GO.overlaps(poly1, poly2)
true
```
"""
overlaps(geom1, geom2)::Bool = overlaps(
overlaps(geom1, geom2)::Bool = _overlaps(
GI.trait(geom1),
geom1,
GI.trait(geom2),
Expand All @@ -84,22 +84,22 @@ This is equivalent to `x -> overlaps(x, g1)`.
overlaps(g1) = Base.Fix2(overlaps, g1)

"""
overlaps(::GI.AbstractTrait, geom1, ::GI.AbstractTrait, geom2)::Bool
_overlaps(::GI.AbstractTrait, geom1, ::GI.AbstractTrait, geom2)::Bool

For any non-specified pair, all have non-matching dimensions, return false.
"""
overlaps(::GI.AbstractTrait, geom1, ::GI.AbstractTrait, geom2) = false
_overlaps(::GI.AbstractTrait, geom1, ::GI.AbstractTrait, geom2) = false

"""
overlaps(
_overlaps(
::GI.MultiPointTrait, points1,
::GI.MultiPointTrait, points2,
)::Bool

If the multipoints overlap, meaning some, but not all, of the points within the
multipoints are shared, return true.
"""
function overlaps(
function _overlaps(
::GI.MultiPointTrait, points1,
::GI.MultiPointTrait, points2,
)
Expand All @@ -121,24 +121,27 @@ function overlaps(
end

"""
overlaps(::GI.LineTrait, line1, ::GI.LineTrait, line)::Bool
_overlaps(::GI.LineTrait, line1, ::GI.LineTrait, line2)::Bool

If the lines overlap, meaning that they are collinear but each have one endpoint
outside of the other line, return true. Else false.
"""
overlaps(::GI.LineTrait, line1, ::GI.LineTrait, line) =
_overlaps((a1, a2), (b1, b2))
function _overlaps(::GI.LineTrait, line1, ::GI.LineTrait, line2)
a1, a2 = GI.getpoint(line1, 1), GI.getpoint(line1, 2)
b1, b2 = GI.getpoint(line2, 1), GI.getpoint(line2, 2)
return _overlaps((a1, a2), (b1, b2))
end

"""
overlaps(
_overlaps(
::Union{GI.LineStringTrait, GI.LinearRing}, line1,
::Union{GI.LineStringTrait, GI.LinearRing}, line2,
)::Bool

If the curves overlap, meaning that at least one edge of each curve overlaps,
return true. Else false.
"""
function overlaps(
function _overlaps(
::Union{GI.LineStringTrait, GI.LinearRing}, line1,
::Union{GI.LineStringTrait, GI.LinearRing}, line2,
)
Expand All @@ -152,15 +155,15 @@ function overlaps(
end

"""
overlaps(
_overlaps(
trait_a::GI.PolygonTrait, poly_a,
trait_b::GI.PolygonTrait, poly_b,
)::Bool

If the two polygons intersect with one another, but are not equal, return true.
Else false.
"""
function overlaps(
function _overlaps(
trait_a::GI.PolygonTrait, poly_a,
trait_b::GI.PolygonTrait, poly_b,
)
Expand All @@ -170,15 +173,15 @@ function overlaps(
end

"""
overlaps(
_overlaps(
::GI.PolygonTrait, poly1,
::GI.MultiPolygonTrait, polys2,
)::Bool

Return true if polygon overlaps with at least one of the polygons within the
multipolygon. Else false.
"""
function overlaps(
function _overlaps(
::GI.PolygonTrait, poly1,
::GI.MultiPolygonTrait, polys2,
)
Expand All @@ -189,27 +192,27 @@ function overlaps(
end

"""
overlaps(
_overlaps(
::GI.MultiPolygonTrait, polys1,
::GI.PolygonTrait, poly2,
)::Bool

Return true if polygon overlaps with at least one of the polygons within the
multipolygon. Else false.
"""
overlaps(trait1::GI.MultiPolygonTrait, polys1, trait2::GI.PolygonTrait, poly2) =
overlaps(trait2, poly2, trait1, polys1)
_overlaps(trait1::GI.MultiPolygonTrait, polys1, trait2::GI.PolygonTrait, poly2) =
_overlaps(trait2, poly2, trait1, polys1)

"""
overlaps(
_overlaps(
::GI.MultiPolygonTrait, polys1,
::GI.MultiPolygonTrait, polys2,
)::Bool

Return true if at least one pair of polygons from multipolygons overlap. Else
false.
"""
function overlaps(
function _overlaps(
::GI.MultiPolygonTrait, polys1,
::GI.MultiPolygonTrait, polys2,
)
Expand Down
110 changes: 104 additions & 6 deletions test/methods/geom_relations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -301,21 +301,67 @@ end
@test GO.overlaps($p1, $p2) == LG.overlaps($p1, $p2)
@test !GO.overlaps($p1, (1, 1))
@test !GO.overlaps((1, 1), $p2)

# Test basic polygons that overlap
@test GO.overlaps($p1, $p3) == LG.overlaps($p1, $p3)

# Test one polygon within the other
@test GO.overlaps($p2, $p4) == GO.overlaps($p4, $p2) == LG.overlaps($p2, $p4)

# Test equal polygons
@test GO.overlaps($p5, $p5) == LG.overlaps($p5, $p5)

# Test polygon that overlaps with multipolygon
@test GO.overlaps($m1, $p3) == LG.overlaps($m1, $p3)
# Test polygon in hole of multipolygon, doesn't overlap
@test GO.overlaps($m1, $p4) == LG.overlaps($m1, $p4)
end

# Test Line × Line overlaps (GI.Line, not LineString)
@testset "Line × Line overlaps" begin
# Overlapping collinear lines
line1 = GI.Line([(0.0, 0.0), (2.0, 0.0)])
line2 = GI.Line([(1.0, 0.0), (3.0, 0.0)])
@test GO.overlaps(line1, line2) == true

# Non-overlapping collinear lines
line3 = GI.Line([(0.0, 0.0), (1.0, 0.0)])
line4 = GI.Line([(2.0, 0.0), (3.0, 0.0)])
@test GO.overlaps(line3, line4) == false

# One line fully contains the other
line5 = GI.Line([(0.0, 0.0), (4.0, 0.0)])
line6 = GI.Line([(1.0, 0.0), (2.0, 0.0)])
@test GO.overlaps(line5, line6) == false

# Non-collinear lines
line7 = GI.Line([(0.0, 0.0), (1.0, 0.0)])
line8 = GI.Line([(0.0, 0.0), (0.0, 1.0)])
@test GO.overlaps(line7, line8) == false
end

# Test MultiPolygon × MultiPolygon overlaps
@testset "MultiPolygon × MultiPolygon overlaps" begin
# Create two multipolygons that overlap
mp1 = GI.MultiPolygon([
[[[0.0, 0.0], [2.0, 0.0], [2.0, 2.0], [0.0, 2.0], [0.0, 0.0]]],
[[[5.0, 5.0], [7.0, 5.0], [7.0, 7.0], [5.0, 7.0], [5.0, 5.0]]]
])
mp2 = GI.MultiPolygon([
[[[1.0, 1.0], [3.0, 1.0], [3.0, 3.0], [1.0, 3.0], [1.0, 1.0]]],
[[[6.0, 6.0], [8.0, 6.0], [8.0, 8.0], [6.0, 8.0], [6.0, 6.0]]]
])
@test GO.overlaps(mp1, mp2) == true

# Create two multipolygons that don't overlap
mp3 = GI.MultiPolygon([
[[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]]
])
mp4 = GI.MultiPolygon([
[[[5.0, 5.0], [6.0, 5.0], [6.0, 6.0], [5.0, 6.0], [5.0, 5.0]]]
])
@test GO.overlaps(mp3, mp4) == false
end
end

@testset "Crosses" begin
Expand Down Expand Up @@ -348,7 +394,7 @@ end
@testset "Features, Table rows and Extents" begin
feature1 = GI.Feature(pt1; properties=Dict{Symbol, Any}())
feature2 = GI.Feature(pt2; properties=Dict{Symbol, Any}())

# Test NamedTuple
named_tuple1 = (; geometry=pt1)
named_tuple2 = (; geometry=pt2)
Expand All @@ -368,7 +414,7 @@ end
@test GO.disjoint(feature1, feature2) == GO.disjoint(pt1, pt2)
@test GO.coveredby(feature1, ext1) == GO.coveredby(pt1, ext1)
@test GO.within(feature1, ext1) == GO.within(pt1, ext1)

# Test mixed types
@test GO.disjoint(feature1, named_tuple2) == GO.disjoint(pt1, pt2)
@test GO.coveredby(feature1, ext1) == GO.coveredby(pt1, ext1)
Expand All @@ -377,4 +423,56 @@ end
# Test extents
@test GO.disjoint(ext1, ext3) == Extents.disjoint(ext1, ext3)
@test GO.coveredby(ext1, ext1) == Extents.coveredby(ext1, ext1)

# Test crosses with Features
line_a = GI.LineString([(-2.0, 2.0), (4.0, 2.0)])
line_b = GI.LineString([(1.0, 1.0), (1.0, 2.0), (1.0, 3.0), (1.0, 4.0)])
poly_c = GI.Polygon([[(-1.0, 2.0), (3.0, 2.0), (3.0, 3.0), (-1.0, 3.0), (-1.0, 2.0)]])
line_d = GI.LineString([(0.5, 2.5), (1.0, 1.0)])
mpt_e = GI.MultiPoint([(1.0, 2.0), (12.0, 12.0)])

feature_line_a = GI.Feature(line_a; properties=Dict{Symbol, Any}())
feature_line_b = GI.Feature(line_b; properties=Dict{Symbol, Any}())
feature_poly_c = GI.Feature(poly_c; properties=Dict{Symbol, Any}())
feature_line_d = GI.Feature(line_d; properties=Dict{Symbol, Any}())
feature_mpt_e = GI.Feature(mpt_e; properties=Dict{Symbol, Any}())

# Test crosses with both geometries as Features
@test GO.crosses(feature_line_a, feature_line_b) == GO.crosses(line_a, line_b)
@test GO.crosses(feature_line_d, feature_poly_c) == GO.crosses(line_d, poly_c)
@test GO.crosses(feature_mpt_e, feature_line_b) == GO.crosses(mpt_e, line_b)

# Test crosses with one Feature and one raw geometry
@test GO.crosses(feature_line_a, line_b) == GO.crosses(line_a, line_b)
@test GO.crosses(line_a, feature_line_b) == GO.crosses(line_a, line_b)
@test GO.crosses(feature_line_d, poly_c) == GO.crosses(line_d, poly_c)
@test GO.crosses(line_d, feature_poly_c) == GO.crosses(line_d, poly_c)

# Test overlaps with Features
poly_overlap1 = GI.Polygon([[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]]])
poly_overlap2 = GI.Polygon([[[0.5, 0.5], [1.5, 0.5], [1.5, 1.5], [0.5, 1.5], [0.5, 0.5]]])
poly_disjoint = GI.Polygon([[[2.0, 2.0], [3.0, 2.0], [3.0, 3.0], [2.0, 3.0], [2.0, 2.0]]])

feature_overlap1 = GI.Feature(poly_overlap1; properties=Dict{Symbol, Any}())
feature_overlap2 = GI.Feature(poly_overlap2; properties=Dict{Symbol, Any}())
feature_disjoint = GI.Feature(poly_disjoint; properties=Dict{Symbol, Any}())

# Test overlaps with both geometries as Features
@test GO.overlaps(feature_overlap1, feature_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
@test GO.overlaps(feature_overlap1, feature_disjoint) == GO.overlaps(poly_overlap1, poly_disjoint)

# Test overlaps with one Feature and one raw geometry
@test GO.overlaps(feature_overlap1, poly_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
@test GO.overlaps(poly_overlap1, feature_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
@test GO.overlaps(feature_overlap1, poly_disjoint) == GO.overlaps(poly_overlap1, poly_disjoint)
@test GO.overlaps(poly_overlap1, feature_disjoint) == GO.overlaps(poly_overlap1, poly_disjoint)

# Test with NamedTuples for crosses and overlaps
nt_line_a = (; geometry=line_a)
nt_line_b = (; geometry=line_b)
nt_poly_overlap1 = (; geometry=poly_overlap1)
nt_poly_overlap2 = (; geometry=poly_overlap2)

@test GO.crosses(nt_line_a, nt_line_b) == GO.crosses(line_a, line_b)
@test GO.overlaps(nt_poly_overlap1, nt_poly_overlap2) == GO.overlaps(poly_overlap1, poly_overlap2)
end
Loading