Skip to content

Commit 941f27d

Browse files
committed
Implement algorithm in intersection
1 parent ef0ad8a commit 941f27d

File tree

1 file changed

+62
-24
lines changed

1 file changed

+62
-24
lines changed

Diff for: src/methods/clipping/intersection.jl

+62-24
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,41 @@ GI.coordinates.(inter_points)
4040
```
4141
"""
4242
function intersection(
43-
geom_a, geom_b, ::Type{T}=Float64; target=nothing, kwargs...,
43+
alg::FosterHormannClipping, geom_a, geom_b, ::Type{T}=Float64; target=nothing, kwargs...
4444
) where {T<:AbstractFloat}
4545
return _intersection(
46-
TraitTarget(target), T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b;
46+
alg, TraitTarget(target), T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b;
4747
exact = True(), kwargs...,
4848
)
4949
end
5050

51+
# fallback definitions
52+
# if no manifold - assume planar (until we have best_manifold)
53+
function intersection(
54+
geom_a, geom_b, ::Type{T}=Float64; target=nothing, kwargs...
55+
) where {T<:AbstractFloat}
56+
return intersection(FosterHormannClipping(Planar()), geom_a, geom_b; target, kwargs...)
57+
end
58+
59+
# if manifold but no algorithm - assume FosterHormannClipping with provided manifold.
60+
function intersection(m::Manifold, geom_a, geom_b, ::Type{T}=Float64; target=nothing, kwargs...) where {T<:AbstractFloat}
61+
return intersection(FosterHormannClipping(m), geom_a, geom_b; target, kwargs...)
62+
end
63+
5164
# Curve-Curve Intersections with target Point
5265
_intersection(
53-
::TraitTarget{GI.PointTrait}, ::Type{T},
66+
alg::FosterHormannClipping, ::TraitTarget{GI.PointTrait}, ::Type{T},
5467
trait_a::Union{GI.LineTrait, GI.LineStringTrait, GI.LinearRingTrait}, geom_a,
5568
trait_b::Union{GI.LineTrait, GI.LineStringTrait, GI.LinearRingTrait}, geom_b;
5669
kwargs...,
57-
) where T = _intersection_points(T, trait_a, geom_a, trait_b, geom_b)
70+
) where T = _intersection_points(alg.manifold, alg.accelerator, T, trait_a, geom_a, trait_b, geom_b)
5871

5972
#= Polygon-Polygon Intersections with target Polygon
6073
The algorithm to determine the intersection was adapted from "Efficient clipping
6174
of efficient polygons," by Greiner and Hormann (1998).
6275
DOI: https://doi.org/10.1145/274363.274364 =#
6376
function _intersection(
64-
::TraitTarget{GI.PolygonTrait}, ::Type{T},
77+
alg::FosterHormannClipping, ::TraitTarget{GI.PolygonTrait}, ::Type{T},
6578
::GI.PolygonTrait, poly_a,
6679
::GI.PolygonTrait, poly_b;
6780
exact, kwargs...,
@@ -70,10 +83,10 @@ function _intersection(
7083
ext_a = GI.getexterior(poly_a)
7184
ext_b = GI.getexterior(poly_b)
7285
# Then we find the intersection of the exteriors
73-
a_list, b_list, a_idx_list = _build_ab_list(T, ext_a, ext_b, _inter_delay_cross_f, _inter_delay_bounce_f; exact)
74-
polys = _trace_polynodes(T, a_list, b_list, a_idx_list, _inter_step, poly_a, poly_b)
86+
a_list, b_list, a_idx_list = _build_ab_list(alg, T, ext_a, ext_b, _inter_delay_cross_f, _inter_delay_bounce_f; exact)
87+
polys = _trace_polynodes(alg, T, a_list, b_list, a_idx_list, _inter_step, poly_a, poly_b)
7588
if isempty(polys) # no crossing points, determine if either poly is inside the other
76-
a_in_b, b_in_a = _find_non_cross_orientation(a_list, b_list, ext_a, ext_b; exact)
89+
a_in_b, b_in_a = _find_non_cross_orientation(alg, a_list, b_list, ext_a, ext_b; exact)
7790
if a_in_b
7891
push!(polys, GI.Polygon([tuples(ext_a)]))
7992
elseif b_in_a
@@ -84,10 +97,10 @@ function _intersection(
8497
# If the original polygons had holes, take that into account.
8598
if GI.nhole(poly_a) != 0 || GI.nhole(poly_b) != 0
8699
hole_iterator = Iterators.flatten((GI.gethole(poly_a), GI.gethole(poly_b)))
87-
_add_holes_to_polys!(T, polys, hole_iterator, remove_idx; exact)
100+
_add_holes_to_polys!(alg, T, polys, hole_iterator, remove_idx; exact)
88101
end
89102
# Remove unneeded collinear points on same edge
90-
_remove_collinear_points!(polys, remove_idx, poly_a, poly_b)
103+
_remove_collinear_points!(alg, polys, remove_idx, poly_a, poly_b)
91104
return polys
92105
end
93106

@@ -112,7 +125,7 @@ _inter_step(x, _) = x ? 1 : (-1)
112125
Unless specified with `fix_multipoly = nothing`, `multipolygon_b` will be validated using
113126
the given (default is `UnionIntersectingPolygons()`) correction. =#
114127
function _intersection(
115-
target::TraitTarget{GI.PolygonTrait}, ::Type{T},
128+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
116129
::GI.PolygonTrait, poly_a,
117130
::GI.MultiPolygonTrait, multipoly_b;
118131
fix_multipoly = UnionIntersectingPolygons(), kwargs...,
@@ -122,7 +135,7 @@ function _intersection(
122135
end
123136
polys = Vector{_get_poly_type(T)}()
124137
for poly_b in GI.getpolygon(multipoly_b)
125-
append!(polys, intersection(poly_a, poly_b; target))
138+
append!(polys, intersection(alg, poly_a, poly_b; target))
126139
end
127140
return polys
128141
end
@@ -131,19 +144,19 @@ end
131144
polygon with the multipolygon and thus simply switches the order of operations and calls the
132145
above method. =#
133146
_intersection(
134-
target::TraitTarget{GI.PolygonTrait}, ::Type{T},
147+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
135148
::GI.MultiPolygonTrait, multipoly_a,
136149
::GI.PolygonTrait, poly_b;
137150
kwargs...,
138-
) where T = intersection(poly_b, multipoly_a; target , kwargs...)
151+
) where T = intersection(alg, poly_b, multipoly_a; target , kwargs...)
139152

140153
#= Multipolygon with multipolygon intersection - note that all intersection regions between
141154
any sub-polygons of `multipoly_a` and any of the sub-polygons of `multipoly_b` are counted
142155
as intersection polygons. Unless specified with `fix_multipoly = nothing`, both
143156
`multipolygon_a` and `multipolygon_b` will be validated using the given (default is
144157
`UnionIntersectingPolygons()`) correction. =#
145158
function _intersection(
146-
target::TraitTarget{GI.PolygonTrait}, ::Type{T},
159+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
147160
::GI.MultiPolygonTrait, multipoly_a,
148161
::GI.MultiPolygonTrait, multipoly_b;
149162
fix_multipoly = UnionIntersectingPolygons(), kwargs...,
@@ -155,21 +168,37 @@ function _intersection(
155168
end
156169
polys = Vector{_get_poly_type(T)}()
157170
for poly_a in GI.getpolygon(multipoly_a)
158-
append!(polys, intersection(poly_a, multipoly_b; target, fix_multipoly))
171+
append!(polys, intersection(alg, poly_a, multipoly_b; target, fix_multipoly))
159172
end
160173
return polys
161174
end
162175

176+
# catch-all method for multipolygontraits
177+
function intersection(
178+
alg::FosterHormannClipping, ::TraitTarget{GI.MultiPolygonTrait}, ::Type{T},
179+
trait_a::Union{GI.PolygonTrait, GI.MultiPolygonTrait}, polylike_a,
180+
trait_b::Union{GI.PolygonTrait, GI.MultiPolygonTrait}, polylike_b;
181+
fix_multipoly = UnionIntersectingPolygons(), kwargs...
182+
) where T
183+
polys = _intersection(alg, TraitTarget(GI.PolygonTrait()), T, trait_a, polylike_a, trait_b, polylike_b; kwargs...)
184+
if isnothing(fix_multipoly)
185+
return GI.MultiPolygon(polys)
186+
else
187+
return fix_multipoly(GI.MultiPolygon(polys))
188+
end
189+
end
190+
191+
163192
# Many type and target combos aren't implemented
164193
function _intersection(
165-
::TraitTarget{Target}, ::Type{T},
194+
alg::GeometryOpsCore.Algorithm, target::TraitTarget{Target}, ::Type{T},
166195
trait_a::GI.AbstractTrait, geom_a,
167196
trait_b::GI.AbstractTrait, geom_b;
168197
kwargs...,
169198
) where {Target, T}
170199
@assert(
171200
false,
172-
"Intersection between $trait_a and $trait_b with target $Target isn't implemented yet.",
201+
"Intersection between $trait_a and $trait_b with target $Target and algorithm $alg isn't implemented yet.",
173202
)
174203
return nothing
175204
end
@@ -193,13 +222,19 @@ inter_points = GO.intersection_points(line1, line2)
193222
1-element Vector{Tuple{Float64, Float64}}:
194223
(125.58375366067548, -14.83572303404496)
195224
"""
196-
intersection_points(geom_a, geom_b, ::Type{T} = Float64) where T <: AbstractFloat =
197-
_intersection_points(T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b)
225+
intersection_points(geom_a, geom_b, ::Type{T} = Float64) where T <: AbstractFloat = intersection_points(FosterHormannClipping(Planar()), geom_a, geom_b, T)
226+
function intersection_points(alg::FosterHormannClipping{M, A}, geom_a, geom_b, ::Type{T} = Float64) where {M, A, T <: AbstractFloat}
227+
return _intersection_points(alg.manifold, alg.accelerator, T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b)
228+
end
229+
230+
function intersection_points(m::Manifold, a::IntersectionAccelerator, geom_a, geom_b, ::Type{T} = Float64) where T <: AbstractFloat
231+
return _intersection_points(m, a, T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b)
232+
end
198233

199234

200235
#= Calculates the list of intersection points between two geometries, including line
201236
segments, line strings, linear rings, polygons, and multipolygons. =#
202-
function _intersection_points(::Type{T}, ::GI.AbstractTrait, a, ::GI.AbstractTrait, b; exact = True()) where T
237+
function _intersection_points(manifold::M, accelerator::A, ::Type{T}, ::GI.AbstractTrait, a, ::GI.AbstractTrait, b; exact = True()) where {M <: Manifold, A <: IntersectionAccelerator, T}
203238
# Initialize an empty list of points
204239
result = Tuple{T, T}[]
205240
# Check if the geometries extents even overlap
@@ -243,7 +278,7 @@ intersection point (x,y) while the second is the ratio along the initial lines (
243278
that point.
244279
245280
Calculation derivation can be found here: https://stackoverflow.com/questions/563198/ =#
246-
function _intersection_point(::Type{T}, (a1, a2)::Edge, (b1, b2)::Edge; exact) where T
281+
function _intersection_point(manifold::M, ::Type{T}, (a1, a2)::Edge, (b1, b2)::Edge; exact) where {M <: Manifold, T}
247282
# Default answer for no intersection
248283
line_orient = line_out
249284
intr1 = ((zero(T), zero(T)), (zero(T), zero(T)))
@@ -266,7 +301,7 @@ function _intersection_point(::Type{T}, (a1, a2)::Edge, (b1, b2)::Edge; exact) w
266301
# Determine intersection type and intersection point(s)
267302
if a1_orient == a2_orient == b1_orient == b2_orient == 0
268303
# Intersection is collinear if all endpoints lie on the same line
269-
line_orient, intr1, intr2 = _find_collinear_intersection(T, a1, a2, b1, b2, a_ext, b_ext, no_intr_result)
304+
line_orient, intr1, intr2 = _find_collinear_intersection(manifold, T, a1, a2, b1, b2, a_ext, b_ext, no_intr_result)
270305
elseif a1_orient == 0 || a2_orient == 0 || b1_orient == 0 || b2_orient == 0
271306
# Intersection is a hinge if the intersection point is an endpoint
272307
line_orient = line_hinge
@@ -279,13 +314,16 @@ function _intersection_point(::Type{T}, (a1, a2)::Edge, (b1, b2)::Edge; exact) w
279314
return line_orient, intr1, intr2
280315
end
281316

317+
# TODO: deprecate this
318+
_intersection_point(::Type{T}, (a1, a2)::Edge, (b1, b2)::Edge; exact) where T = _intersection_point(Planar(), T, (a1, a2), (b1, b2); exact)
319+
282320
#= If lines defined by (a1, a2) and (b1, b2) are collinear, find endpoints of overlapping
283321
region if they exist. This could result in three possibilities. First, there could be no
284322
overlapping region, in which case, the default 'no_intr_result' intersection information is
285323
returned. Second, the two regions could just meet at one shared endpoint, in which case it
286324
is a hinge intersection with one intersection point. Otherwise, it is a overlapping
287325
intersection defined by two of the endpoints of the line segments. =#
288-
function _find_collinear_intersection(::Type{T}, a1, a2, b1, b2, a_ext, b_ext, no_intr_result) where T
326+
function _find_collinear_intersection(manifold::M, ::Type{T}, a1, a2, b1, b2, a_ext, b_ext, no_intr_result) where {M <: Manifold, T}
289327
# Define default return for no intersection points
290328
line_orient, intr1, intr2 = no_intr_result
291329
# Determine collinear line overlaps

0 commit comments

Comments
 (0)