Skip to content

Commit af1057c

Browse files
committed
Pass algorithm through difference + union
1 parent 1d7ba10 commit af1057c

File tree

3 files changed

+124
-47
lines changed

3 files changed

+124
-47
lines changed

src/methods/clipping/cut.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ function _cut(alg::FosterHormannClipping{M, A}, ::Type{T}, ::GI.PolygonTrait, po
8383
cut_polys = [GI.Polygon([c]) for c in cut_coords]
8484
# Add original polygon holes back in
8585
remove_idx = falses(length(cut_polys))
86-
_add_holes_to_polys!(T, cut_polys, GI.gethole(poly), remove_idx; exact)
86+
_add_holes_to_polys!(alg, T, cut_polys, GI.gethole(poly), remove_idx; exact)
8787
return cut_polys
8888
end
8989

@@ -100,10 +100,10 @@ end
100100
of cut geometry in Vector{Vector{Tuple}} format.
101101
102102
Note: degenerate cases where intersection points are vertices do not work right now. =#
103-
function _cut(::Type{T}, geom, line, geom_list, intr_list, n_intr_pts; exact) where T
103+
function _cut(alg::FosterHormannClipping{M, A}, ::Type{T}, geom, line, geom_list, intr_list, n_intr_pts; exact) where {T, M, A}
104104
# Sort and categorize the intersection points
105105
sort!(intr_list, by = x -> geom_list[x].fracs[2])
106-
_flag_ent_exit!(GI.LineTrait(), line, geom_list; exact)
106+
_flag_ent_exit!(alg, GI.LineTrait(), line, geom_list; exact)
107107
# Add first point to output list
108108
return_coords = [[geom_list[1].point]]
109109
cross_backs = [(T(Inf),T(Inf))]

src/methods/clipping/difference.jl

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,24 @@ GI.coordinates.(diff_poly)
3333
```
3434
"""
3535
function difference(
36-
geom_a, geom_b, ::Type{T} = Float64; target=nothing, kwargs...,
36+
alg::FosterHormannClipping, geom_a, geom_b, ::Type{T} = Float64; target=nothing, kwargs...,
3737
) where {T<:AbstractFloat}
3838
return _difference(
39-
TraitTarget(target), T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b;
39+
alg, TraitTarget(target), T, GI.trait(geom_a), geom_a, GI.trait(geom_b), geom_b;
4040
exact = True(), kwargs...,
4141
)
4242
end
4343

44+
# fallback definitions
45+
difference(geom_a, geom_b, ::Type{T} = Float64; target=nothing, kwargs...) where T = difference(FosterHormannClipping(Planar()), geom_a, geom_b, T; target, kwargs...)
46+
# if manifold but no algorithm - assume FosterHormannClipping with provided manifold.
47+
difference(m::Manifold, geom_a, geom_b, ::Type{T} = Float64; target=nothing, kwargs...) where T = difference(FosterHormannClipping(m), geom_a, geom_b, T; target, kwargs...)
48+
4449
#= The 'difference' function returns the difference of two polygons as a list of polygons.
4550
The algorithm to determine the difference was adapted from "Efficient clipping of efficient
4651
polygons," by Greiner and Hormann (1998). DOI: https://doi.org/10.1145/274363.274364 =#
4752
function _difference(
48-
::TraitTarget{GI.PolygonTrait}, ::Type{T},
53+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
4954
::GI.PolygonTrait, poly_a,
5055
::GI.PolygonTrait, poly_b;
5156
exact, kwargs...
@@ -54,11 +59,11 @@ function _difference(
5459
ext_a = GI.getexterior(poly_a)
5560
ext_b = GI.getexterior(poly_b)
5661
# Find the difference of the exterior of the polygons
57-
a_list, b_list, a_idx_list = _build_ab_list(T, ext_a, ext_b, _diff_delay_cross_f, _diff_delay_bounce_f; exact)
58-
polys = _trace_polynodes(T, a_list, b_list, a_idx_list, _diff_step, poly_a, poly_b)
62+
a_list, b_list, a_idx_list = _build_ab_list(alg, T, ext_a, ext_b, _diff_delay_cross_f, _diff_delay_bounce_f; exact)
63+
polys = _trace_polynodes(alg, T, a_list, b_list, a_idx_list, _diff_step, poly_a, poly_b)
5964
# if no crossing points, determine if either poly is inside of the other
6065
if isempty(polys)
61-
a_in_b, b_in_a = _find_non_cross_orientation(a_list, b_list, ext_a, ext_b; exact)
66+
a_in_b, b_in_a = _find_non_cross_orientation(alg.manifold, a_list, b_list, ext_a, ext_b; exact)
6267
# add case for if they polygons are the same (all intersection points!)
6368
# add a find_first check to find first non-inter poly!
6469
if b_in_a && !a_in_b # b in a and can't be the same polygon
@@ -72,19 +77,19 @@ function _difference(
7277
remove_idx = falses(length(polys))
7378
# If the original polygons had holes, take that into account.
7479
if GI.nhole(poly_a) != 0
75-
_add_holes_to_polys!(T, polys, GI.gethole(poly_a), remove_idx; exact)
80+
_add_holes_to_polys!(alg, T, polys, GI.gethole(poly_a), remove_idx; exact)
7681
end
7782
if GI.nhole(poly_b) != 0
7883
for hole in GI.gethole(poly_b)
7984
hole_poly = GI.Polygon(StaticArrays.SVector(hole))
80-
new_polys = intersection(hole_poly, poly_a, T; target = GI.PolygonTrait)
85+
new_polys = intersection(alg, hole_poly, poly_a, T; target = GI.PolygonTrait)
8186
if length(new_polys) > 0
8287
append!(polys, new_polys)
8388
end
8489
end
8590
end
8691
# Remove unneeded collinear points on same edge
87-
_remove_collinear_points!(polys, remove_idx, poly_a, poly_b)
92+
_remove_collinear_points!(alg, polys, remove_idx, poly_a, poly_b)
8893
return polys
8994
end
9095

@@ -110,15 +115,15 @@ _diff_step(x, y) = (x ⊻ y) ? 1 : (-1)
110115
#= Polygon with multipolygon difference - note that all intersection regions between
111116
`poly_a` and any of the sub-polygons of `multipoly_b` are removed from `poly_a`. =#
112117
function _difference(
113-
target::TraitTarget{GI.PolygonTrait}, ::Type{T},
118+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
114119
::GI.PolygonTrait, poly_a,
115120
::GI.MultiPolygonTrait, multipoly_b;
116121
kwargs...,
117122
) where T
118123
polys = [tuples(poly_a, T)]
119124
for poly_b in GI.getpolygon(multipoly_b)
120125
isempty(polys) && break
121-
polys = mapreduce(p -> difference(p, poly_b; target), append!, polys)
126+
polys = mapreduce(p -> difference(alg, p, poly_b; target), append!, polys)
122127
end
123128
return polys
124129
end
@@ -128,7 +133,7 @@ sub-polygons of `multipoly_a` and `poly_b` will be removed from the correspondin
128133
sub-polygon. Unless specified with `fix_multipoly = nothing`, `multipolygon_a` will be
129134
validated using the given (default is `UnionIntersectingPolygons()`) correction. =#
130135
function _difference(
131-
target::TraitTarget{GI.PolygonTrait}, ::Type{T},
136+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
132137
::GI.MultiPolygonTrait, multipoly_a,
133138
::GI.PolygonTrait, poly_b;
134139
fix_multipoly = UnionIntersectingPolygons(), kwargs...,
@@ -139,7 +144,7 @@ function _difference(
139144
polys = Vector{_get_poly_type(T)}()
140145
sizehint!(polys, GI.npolygon(multipoly_a))
141146
for poly_a in GI.getpolygon(multipoly_a)
142-
append!(polys, difference(poly_a, poly_b; target))
147+
append!(polys, difference(alg, poly_a, poly_b; target))
143148
end
144149
return polys
145150
end
@@ -150,7 +155,7 @@ corresponding sub-polygon of `multipoly_a`. Unless specified with `fix_multipoly
150155
`multipolygon_a` will be validated using the given (default is `UnionIntersectingPolygons()`)
151156
correction. =#
152157
function _difference(
153-
target::TraitTarget{GI.PolygonTrait}, ::Type{T},
158+
alg::FosterHormannClipping, target::TraitTarget{GI.PolygonTrait}, ::Type{T},
154159
::GI.MultiPolygonTrait, multipoly_a,
155160
::GI.MultiPolygonTrait, multipoly_b;
156161
fix_multipoly = UnionIntersectingPolygons(), kwargs...,
@@ -165,9 +170,9 @@ function _difference(
165170
pieces of `multipolygon_a`` are removed, continue to take difference with new shape
166171
`polys` =#
167172
polys = if i == 1
168-
difference(multipoly_a, poly_b; target, fix_multipoly)
173+
difference(alg, multipoly_a, poly_b; target, fix_multipoly)
169174
else
170-
difference(GI.MultiPolygon(polys), poly_b; target, fix_multipoly)
175+
difference(alg, GI.MultiPolygon(polys), poly_b; target, fix_multipoly)
171176
end
172177
#= One multipoly_a has been completely covered (and thus removed) there is no need to
173178
continue taking the difference =#
@@ -176,15 +181,30 @@ function _difference(
176181
return polys
177182
end
178183

184+
function _difference(
185+
alg::FosterHormannClipping, ::TraitTarget{GI.MultiPolygonTrait}, ::Type{T},
186+
trait_a::Union{GI.PolygonTrait, GI.MultiPolygonTrait}, polylike_a,
187+
trait_b::Union{GI.PolygonTrait, GI.MultiPolygonTrait}, polylike_b;
188+
fix_multipoly = UnionIntersectingPolygons(), kwargs...
189+
) where T
190+
polys = _difference(alg, TraitTarget(GI.PolygonTrait()), T, trait_a, polylike_a, trait_b, polylike_b; kwargs...)
191+
if isnothing(fix_multipoly)
192+
return GI.MultiPolygon(polys)
193+
else
194+
return fix_multipoly(GI.MultiPolygon(polys))
195+
end
196+
end
197+
179198
# Many type and target combos aren't implemented
180199
function _difference(
181-
::TraitTarget{Target}, ::Type{T},
200+
alg::GeometryOpsCore.Algorithm, target::TraitTarget{Target}, ::Type{T},
182201
trait_a::GI.AbstractTrait, geom_a,
183202
trait_b::GI.AbstractTrait, geom_b,
203+
kw...
184204
) where {Target, T}
185205
@assert(
186206
false,
187-
"Difference between $trait_a and $trait_b with target $Target isn't implemented yet.",
207+
"Difference between $trait_a and $trait_b with target $Target and algorithm $alg isn't implemented yet.",
188208
)
189209
return nothing
190210
end

0 commit comments

Comments
 (0)