Skip to content

Commit 09a549b

Browse files
committed
Fix cut
1 parent f7485c8 commit 09a549b

File tree

3 files changed

+45
-34
lines changed

3 files changed

+45
-34
lines changed

src/methods/clipping/clipping_processor.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,7 +892,7 @@ or they are separate polygons with no intersection (other than an edge or point)
892892
Return two booleans that represent if a is inside b (potentially with shared edges / points)
893893
and visa versa if b is inside of a.
894894
=#
895-
function _find_non_cross_orientation(a_list, b_list, a_poly, b_poly; exact)
895+
function _find_non_cross_orientation(m::M, a_list, b_list, a_poly, b_poly; exact) where {M <: Manifold}
896896
non_intr_a_idx = findfirst(x -> !x.inter, a_list)
897897
non_intr_b_idx = findfirst(x -> !x.inter, b_list)
898898
#= Determine if non-intersection point is in or outside of polygon - if there isn't A
@@ -906,6 +906,9 @@ function _find_non_cross_orientation(a_list, b_list, a_poly, b_poly; exact)
906906
return a_in_b, b_in_a
907907
end
908908

909+
_find_non_cross_orientation(alg::FosterHormannClipping{M}, a_list, b_list, a_poly, b_poly; exact) where {M <: Manifold} =
910+
_find_non_cross_orientation(alg.manifold, a_list, b_list, a_poly, b_poly; exact)
911+
909912
#=
910913
_add_holes_to_polys!(::Type{T}, return_polys, hole_iterator, remove_poly_idx; exact)
911914

src/methods/clipping/cut.jl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,29 +58,32 @@ GI.coordinates.(cut_polys)
5858
[[[5.0, 0.0], [10.0, 0.0], [10.0, 10.0], [5.0, 10.0], [5.0, 0.0]]]
5959
```
6060
"""
61-
cut(geom, line, ::Type{T} = Float64) where {T <: AbstractFloat} =
62-
_cut(T, GI.trait(geom), geom, GI.trait(line), line; exact = _True())
61+
cut(geom, line, ::Type{T} = Float64) where {T <: AbstractFloat} = cut(FosterHormannClipping(), geom, line, T)
62+
cut(m::Manifold, geom, line, ::Type{T} = Float64) where {T <: AbstractFloat} = cut(FosterHormannClipping(m), geom, line, T)
63+
64+
cut(alg::FosterHormannClipping{M, A}, geom, line, ::Type{T} = Float64) where {T <: AbstractFloat, M, A} =
65+
_cut(alg, T, GI.trait(geom), geom, GI.trait(line), line; exact = _True())
6366

6467
#= Cut a given polygon by given line. Add polygon holes back into resulting pieces if there
6568
are any holes. =#
66-
function _cut(::Type{T}, ::GI.PolygonTrait, poly, ::GI.LineTrait, line; exact) where T
69+
function _cut(alg::FosterHormannClipping{M, A}, ::Type{T}, ::GI.PolygonTrait, poly, ::GI.LineTrait, line; exact) where {T, M, A}
6770
ext_poly = GI.getexterior(poly)
68-
poly_list, intr_list = _build_a_list(T, ext_poly, line; exact)
71+
poly_list, intr_list = _build_a_list(alg, T, ext_poly, line; exact)
6972
n_intr_pts = length(intr_list)
7073
# If an impossible number of intersection points, return original polygon
7174
if n_intr_pts < 2 || isodd(n_intr_pts)
7275
return [tuples(poly)]
7376
end
7477
# Cut polygon by line
75-
cut_coords = _cut(T, ext_poly, line, poly_list, intr_list, n_intr_pts; exact)
78+
cut_coords = _cut(alg, T, ext_poly, line, poly_list, intr_list, n_intr_pts; exact)
7679
# Close coords and create polygons
7780
for c in cut_coords
7881
push!(c, c[1])
7982
end
8083
cut_polys = [GI.Polygon([c]) for c in cut_coords]
8184
# Add original polygon holes back in
8285
remove_idx = falses(length(cut_polys))
83-
_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)
8487
return cut_polys
8588
end
8689

@@ -97,10 +100,10 @@ end
97100
of cut geometry in Vector{Vector{Tuple}} format.
98101
99102
Note: degenerate cases where intersection points are vertices do not work right now. =#
100-
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}
101104
# Sort and categorize the intersection points
102105
sort!(intr_list, by = x -> geom_list[x].fracs[2])
103-
_flag_ent_exit!(GI.LineTrait(), line, geom_list; exact)
106+
_flag_ent_exit!(alg, GI.LineTrait(), line, geom_list; exact)
104107
# Add first point to output list
105108
return_coords = [[geom_list[1].point]]
106109
cross_backs = [(T(Inf),T(Inf))]

test/methods/clipping/polygon_clipping.jl

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ test_pairs = [
166166
const ϵ = 1e-10
167167
# Compare clipping results from GeometryOps and LibGEOS
168168
function compare_GO_LG_clipping(GO_f, LG_f, p1, p2)
169-
GO_result_list = GO_f(p1, p2; target = GI.PolygonTrait())
169+
170170
LG_result_geom = LG_f(p1, p2)
171171
if LG_result_geom isa LG.GeometryCollection
172172
poly_list = LG.Polygon[]
@@ -175,38 +175,43 @@ function compare_GO_LG_clipping(GO_f, LG_f, p1, p2)
175175
end
176176
LG_result_geom = LG.MultiPolygon(poly_list)
177177
end
178-
# Check if nothing is returned
179-
if isempty(GO_result_list) && (LG.isEmpty(LG_result_geom) || LG.area(LG_result_geom) == 0)
180-
return true
181-
end
182-
# Check for unnecessary points
183-
if sum(GI.npoint, GO_result_list; init = 0.0) > GI.npoint(LG_result_geom)
184-
return false
185-
end
186-
# Make sure last point is repeated
187-
for poly in GO_result_list
188-
for ring in GI.getring(poly)
189-
GI.getpoint(ring, 1) != GI.getpoint(ring, GI.npoint(ring)) && return false
178+
179+
for _accelerator in (GO.AutoAccelerator(), GO.NestedLoop(), GO.SingleSTRtree(), GO.DoubleSTRtree())
180+
@testset let accelerator = _accelerator # this is a ContextTestSet that is otherwise invisible but adds context to the testset
181+
GO_result_list = GO_f(GO.FosterHormannClipping(accelerator), p1, p2; target = GI.PolygonTrait())
182+
# Check if nothing is returned
183+
if isempty(GO_result_list) && (LG.isEmpty(LG_result_geom) || LG.area(LG_result_geom) == 0)
184+
@test true
185+
continue
186+
end
187+
# Check for unnecessary points
188+
@test !(sum(GI.npoint, GO_result_list; init = 0.0) > GI.npoint(LG_result_geom))
189+
# Make sure last point is repeated
190+
for poly in GO_result_list
191+
for ring in GI.getring(poly)
192+
@test !(GI.getpoint(ring, 1) != GI.getpoint(ring, GI.npoint(ring)))
193+
end
190194
end
191-
end
192195

193-
# Check if polygons cover the same area
194-
local GO_result_geom
195-
if length(GO_result_list) == 1
196-
GO_result_geom = GO_result_list[1]
197-
else
198-
GO_result_geom = GI.MultiPolygon(GO_result_list)
199-
end
200-
diff_1_area = LG.area(LG.difference(GO_result_geom, LG_result_geom))
201-
diff_2_area = LG.area(LG.difference(LG_result_geom, GO_result_geom))
202-
return diff_1_area ϵ && diff_2_area ϵ
196+
# Check if polygons cover the same area
197+
local GO_result_geom
198+
if length(GO_result_list) == 1
199+
GO_result_geom = GO_result_list[1]
200+
else
201+
GO_result_geom = GI.MultiPolygon(GO_result_list)
202+
end
203+
diff_1_area = LG.area(LG.difference(GO_result_geom, LG_result_geom))
204+
diff_2_area = LG.area(LG.difference(LG_result_geom, GO_result_geom))
205+
@test diff_1_area ϵ && diff_2_area ϵ
206+
end # testset
207+
end # loop
203208
end
204209

205210
# Test clipping functions and print error message if tests fail
206211
function test_clipping(GO_f, LG_f, f_name)
207212
for (p1, p2, sg1, sg2, sdesc) in test_pairs
208213
@testset_implementations "$sg1 $f_name $sg2 - $sdesc" begin
209-
@test compare_GO_LG_clipping(GO_f, LG_f, $p1, $p2)
214+
compare_GO_LG_clipping(GO_f, LG_f, $p1, $p2) # this executes tests internally
210215
end
211216
end
212217
return

0 commit comments

Comments
 (0)