@@ -33,19 +33,23 @@ GI.coordinates.(diff_poly)
33
33
```
34
34
"""
35
35
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... ,
37
37
) where {T<: AbstractFloat }
38
38
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;
40
40
exact = True (), kwargs... ,
41
41
)
42
42
end
43
+ # fallback definitions
44
+ difference (geom_a, geom_b, :: Type{T} = Float64; target= nothing , kwargs... ) where T = difference (FosterHormannClipping (Planar ()), geom_a, geom_b, T; target, kwargs... )
45
+ # if manifold but no algorithm - assume FosterHormannClipping with provided manifold.
46
+ 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... )
43
47
44
48
#= The 'difference' function returns the difference of two polygons as a list of polygons.
45
49
The algorithm to determine the difference was adapted from "Efficient clipping of efficient
46
50
polygons," by Greiner and Hormann (1998). DOI: https://doi.org/10.1145/274363.274364 =#
47
51
function _difference (
48
- :: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
52
+ alg :: FosterHormannClipping , target :: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
49
53
:: GI.PolygonTrait , poly_a,
50
54
:: GI.PolygonTrait , poly_b;
51
55
exact, kwargs...
@@ -54,11 +58,11 @@ function _difference(
54
58
ext_a = GI. getexterior (poly_a)
55
59
ext_b = GI. getexterior (poly_b)
56
60
# 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)
61
+ 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)
62
+ polys = _trace_polynodes (alg, T, a_list, b_list, a_idx_list, _diff_step, poly_a, poly_b)
59
63
# if no crossing points, determine if either poly is inside of the other
60
64
if isempty (polys)
61
- a_in_b, b_in_a = _find_non_cross_orientation (a_list, b_list, ext_a, ext_b; exact)
65
+ a_in_b, b_in_a = _find_non_cross_orientation (alg . manifold, a_list, b_list, ext_a, ext_b; exact)
62
66
# add case for if they polygons are the same (all intersection points!)
63
67
# add a find_first check to find first non-inter poly!
64
68
if b_in_a && ! a_in_b # b in a and can't be the same polygon
@@ -72,19 +76,19 @@ function _difference(
72
76
remove_idx = falses (length (polys))
73
77
# If the original polygons had holes, take that into account.
74
78
if GI. nhole (poly_a) != 0
75
- _add_holes_to_polys! (T, polys, GI. gethole (poly_a), remove_idx; exact)
79
+ _add_holes_to_polys! (alg, T, polys, GI. gethole (poly_a), remove_idx; exact)
76
80
end
77
81
if GI. nhole (poly_b) != 0
78
82
for hole in GI. gethole (poly_b)
79
83
hole_poly = GI. Polygon (StaticArrays. SVector (hole))
80
- new_polys = intersection (hole_poly, poly_a, T; target = GI. PolygonTrait)
84
+ new_polys = intersection (alg, hole_poly, poly_a, T; target = GI. PolygonTrait)
81
85
if length (new_polys) > 0
82
86
append! (polys, new_polys)
83
87
end
84
88
end
85
89
end
86
90
# Remove unneeded collinear points on same edge
87
- _remove_collinear_points! (polys, remove_idx, poly_a, poly_b)
91
+ _remove_collinear_points! (alg, polys, remove_idx, poly_a, poly_b)
88
92
return polys
89
93
end
90
94
@@ -110,15 +114,15 @@ _diff_step(x, y) = (x ⊻ y) ? 1 : (-1)
110
114
#= Polygon with multipolygon difference - note that all intersection regions between
111
115
`poly_a` and any of the sub-polygons of `multipoly_b` are removed from `poly_a`. =#
112
116
function _difference (
113
- target:: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
117
+ alg :: FosterHormannClipping , target:: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
114
118
:: GI.PolygonTrait , poly_a,
115
119
:: GI.MultiPolygonTrait , multipoly_b;
116
120
kwargs... ,
117
121
) where T
118
122
polys = [tuples (poly_a, T)]
119
123
for poly_b in GI. getpolygon (multipoly_b)
120
124
isempty (polys) && break
121
- polys = mapreduce (p -> difference (p, poly_b; target), append!, polys)
125
+ polys = mapreduce (p -> difference (alg, p, poly_b; target), append!, polys)
122
126
end
123
127
return polys
124
128
end
@@ -128,7 +132,7 @@ sub-polygons of `multipoly_a` and `poly_b` will be removed from the correspondin
128
132
sub-polygon. Unless specified with `fix_multipoly = nothing`, `multipolygon_a` will be
129
133
validated using the given (default is `UnionIntersectingPolygons()`) correction. =#
130
134
function _difference (
131
- target:: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
135
+ alg :: FosterHormannClipping , target:: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
132
136
:: GI.MultiPolygonTrait , multipoly_a,
133
137
:: GI.PolygonTrait , poly_b;
134
138
fix_multipoly = UnionIntersectingPolygons (), kwargs... ,
@@ -139,7 +143,7 @@ function _difference(
139
143
polys = Vector {_get_poly_type(T)} ()
140
144
sizehint! (polys, GI. npolygon (multipoly_a))
141
145
for poly_a in GI. getpolygon (multipoly_a)
142
- append! (polys, difference (poly_a, poly_b; target))
146
+ append! (polys, difference (alg, poly_a, poly_b; target))
143
147
end
144
148
return polys
145
149
end
@@ -150,7 +154,7 @@ corresponding sub-polygon of `multipoly_a`. Unless specified with `fix_multipoly
150
154
`multipolygon_a` will be validated using the given (default is `UnionIntersectingPolygons()`)
151
155
correction. =#
152
156
function _difference (
153
- target:: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
157
+ alg :: FosterHormannClipping , target:: TraitTarget{GI.PolygonTrait} , :: Type{T} ,
154
158
:: GI.MultiPolygonTrait , multipoly_a,
155
159
:: GI.MultiPolygonTrait , multipoly_b;
156
160
fix_multipoly = UnionIntersectingPolygons (), kwargs... ,
@@ -165,26 +169,39 @@ function _difference(
165
169
pieces of `multipolygon_a`` are removed, continue to take difference with new shape
166
170
`polys` =#
167
171
polys = if i == 1
168
- difference (multipoly_a, poly_b; target, fix_multipoly)
172
+ difference (alg, multipoly_a, poly_b; target, fix_multipoly)
169
173
else
170
- difference (GI. MultiPolygon (polys), poly_b; target, fix_multipoly)
174
+ difference (alg, GI. MultiPolygon (polys), poly_b; target, fix_multipoly)
171
175
end
172
176
#= One multipoly_a has been completely covered (and thus removed) there is no need to
173
177
continue taking the difference =#
174
178
isempty (polys) && break
175
179
end
176
180
return polys
177
181
end
178
-
182
+ function _difference (
183
+ alg:: FosterHormannClipping , :: TraitTarget{GI.MultiPolygonTrait} , :: Type{T} ,
184
+ trait_a:: Union{GI.PolygonTrait, GI.MultiPolygonTrait} , polylike_a,
185
+ trait_b:: Union{GI.PolygonTrait, GI.MultiPolygonTrait} , polylike_b;
186
+ fix_multipoly = UnionIntersectingPolygons (), kwargs...
187
+ ) where T
188
+ polys = _difference (alg, TraitTarget (GI. PolygonTrait ()), T, trait_a, polylike_a, trait_b, polylike_b; kwargs... )
189
+ if isnothing (fix_multipoly)
190
+ return GI. MultiPolygon (polys)
191
+ else
192
+ return fix_multipoly (GI. MultiPolygon (polys))
193
+ end
194
+ end
179
195
# Many type and target combos aren't implemented
180
196
function _difference (
181
- :: TraitTarget{Target} , :: Type{T} ,
197
+ alg :: GeometryOpsCore.Algorithm , target :: TraitTarget{Target} , :: Type{T} ,
182
198
trait_a:: GI.AbstractTrait , geom_a,
183
199
trait_b:: GI.AbstractTrait , geom_b,
200
+ kw...
184
201
) where {Target, T}
185
202
@assert (
186
203
false ,
187
- " Difference between $trait_a and $trait_b with target $Target isn't implemented yet." ,
204
+ " Difference between $trait_a and $trait_b with target $Target and algorithm $alg isn't implemented yet." ,
188
205
)
189
206
return nothing
190
207
end
0 commit comments