Skip to content

Commit 8601ec5

Browse files
committed
Pass algorithm through all functions in clipping_processor
1 parent 8435b07 commit 8601ec5

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

src/methods/clipping/clipping_processor.jl

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -140,20 +140,20 @@ returns are the fully updated vectors of PolyNodes that represent the rings 'pol
140140
'poly_b', respectively. This function also returns 'a_idx_list', which at its "ith" index
141141
stores the index in 'a_list' at which the "ith" intersection point lies.
142142
=#
143-
function _build_ab_list(::Type{T}, poly_a, poly_b, delay_cross_f::F1, delay_bounce_f::F2; exact) where {T, F1, F2}
143+
function _build_ab_list(alg::FosterHormannClipping, ::Type{T}, poly_a, poly_b, delay_cross_f::F1, delay_bounce_f::F2; exact) where {T, F1, F2}
144144
# Make a list for nodes of each polygon
145-
a_list, a_idx_list, n_b_intrs = _build_a_list(T, poly_a, poly_b; exact)
146-
b_list = _build_b_list(T, a_idx_list, a_list, n_b_intrs, poly_b)
145+
a_list, a_idx_list, n_b_intrs = _build_a_list(alg, T, poly_a, poly_b; exact)
146+
b_list = _build_b_list(alg, T, a_idx_list, a_list, n_b_intrs, poly_b)
147147

148148
# Flag crossings
149-
_classify_crossing!(T, a_list, b_list; exact)
149+
_classify_crossing!(alg, T, a_list, b_list; exact)
150150

151151
# Flag the entry and exits
152-
_flag_ent_exit!(T, GI.LinearRingTrait(), poly_b, a_list, delay_cross_f, Base.Fix2(delay_bounce_f, true); exact)
153-
_flag_ent_exit!(T, GI.LinearRingTrait(), poly_a, b_list, delay_cross_f, Base.Fix2(delay_bounce_f, false); exact)
152+
_flag_ent_exit!(alg, T, GI.LinearRingTrait(), poly_b, a_list, delay_cross_f, Base.Fix2(delay_bounce_f, true); exact)
153+
_flag_ent_exit!(alg, T, GI.LinearRingTrait(), poly_a, b_list, delay_cross_f, Base.Fix2(delay_bounce_f, false); exact)
154154

155155
# Set node indices and filter a_idx_list to just crossing points
156-
_index_crossing_intrs!(a_list, b_list, a_idx_list)
156+
_index_crossing_intrs!(alg, a_list, b_list, a_idx_list)
157157

158158
return a_list, b_list, a_idx_list
159159
end
@@ -172,7 +172,7 @@ not update the entry and exit flags for a_list.
172172
The a_idx_list is a list of the indices of intersection points in a_list. The value at
173173
index i of a_idx_list is the location in a_list where the ith intersection point lies.
174174
=#
175-
function _build_a_list(::Type{T}, poly_a, poly_b; exact) where T
175+
function _build_a_list(alg::FosterHormannClipping{M, A}, ::Type{T}, poly_a, poly_b; exact) where {T, M, A}
176176
n_a_edges = _nedge(poly_a)
177177
a_list = PolyNode{T}[] # list of points in poly_a
178178
sizehint!(a_list, n_a_edges)
@@ -273,7 +273,7 @@ is needed for clipping using the Greiner-Hormann clipping algorithm.
273273
Note: after calling this function, b_list is not fully updated. The entry/exit flags still
274274
need to be updated. However, the neighbor value in a_list is now updated.
275275
=#
276-
function _build_b_list(::Type{T}, a_idx_list, a_list, n_b_intrs, poly_b) where T
276+
function _build_b_list(alg::FosterHormannClipping{M, A}, ::Type{T}, a_idx_list, a_list, n_b_intrs, poly_b) where {T, M, A}
277277
# Sort intersection points by insertion order in b_list
278278
sort!(a_idx_list, by = x-> a_list[x].neighbor + a_list[x].fracs[2])
279279
# Initialize needed values and lists
@@ -333,7 +333,7 @@ chain is crossing and delayed otherwise and all middle points are marked as boun
333333
Additionally, the start and end points of the chain are marked as endpoints using the
334334
endpoints field.
335335
=#
336-
function _classify_crossing!(::Type{T}, a_list, b_list; exact) where T
336+
function _classify_crossing!(alg::FosterHormannClipping{M, A}, ::Type{T}, a_list, b_list; exact) where {T, M, A}
337337
napts = length(a_list)
338338
nbpts = length(b_list)
339339
# start centered on last point
@@ -357,7 +357,7 @@ function _classify_crossing!(::Type{T}, a_list, b_list; exact) where T
357357
a_next_is_b_prev = a_next.inter && equals(a_next, b_prev)
358358
a_next_is_b_next = a_next.inter && equals(a_next, b_next)
359359
# determine which side of a segments the p points are on
360-
b_prev_side, b_next_side = _get_sides(b_prev, b_next, a_prev, curr_pt, a_next,
360+
b_prev_side, b_next_side = _get_sides(#=TODO: alg.manifold, =#b_prev, b_next, a_prev, curr_pt, a_next,
361361
i, j, a_list, b_list; exact)
362362
# no sides overlap
363363
if !a_prev_is_b_prev && !a_prev_is_b_next && !a_next_is_b_prev && !a_next_is_b_next
@@ -499,7 +499,7 @@ all points are intersection points, find the first element that either is the en
499499
or a crossing point that isn't in a chain. Then take the midpoint of this point and the next
500500
point in the list and perform the in/out check. If none of these points exist, return
501501
a `next_idx` of `nothing`. =#
502-
function _pt_off_edge_status(::Type{T}, pt_list, poly, npts; exact) where T
502+
function _pt_off_edge_status(alg::FosterHormannClipping{M, A}, ::Type{T}, pt_list, poly, npts; exact) where {T, M, A}
503503
start_idx, is_non_intr_pt = findfirst(_is_not_intr, pt_list), true
504504
if isnothing(start_idx)
505505
start_idx, is_non_intr_pt = findfirst(_next_edge_off, pt_list), false
@@ -511,7 +511,7 @@ function _pt_off_edge_status(::Type{T}, pt_list, poly, npts; exact) where T
511511
else
512512
(pt_list[start_idx].point .+ pt_list[next_idx].point) ./ 2
513513
end
514-
start_status = !_point_filled_curve_orientation(start_pt, poly; in = true, on = false, out = false, exact)
514+
start_status = !_point_filled_curve_orientation(alg.manifold, start_pt, poly; in = true, on = false, out = false, exact)
515515
return next_idx, start_status
516516
end
517517
# Check if a PolyNode is an intersection point
@@ -537,10 +537,10 @@ bounce will be the same.
537537
538538
Used for clipping polygons by other polygons.
539539
=#
540-
function _flag_ent_exit!(::Type{T}, ::GI.LinearRingTrait, poly, pt_list, delay_cross_f, delay_bounce_f; exact) where T
540+
function _flag_ent_exit!(alg::FosterHormannClipping{M, A}, ::Type{T}, ::GI.LinearRingTrait, poly, pt_list, delay_cross_f, delay_bounce_f; exact) where {T, M, A}
541541
npts = length(pt_list)
542542
# Find starting index if there is one
543-
next_idx, status = _pt_off_edge_status(T, pt_list, poly, npts; exact)
543+
next_idx, status = _pt_off_edge_status(alg, T, pt_list, poly, npts; exact)
544544
isnothing(next_idx) && return
545545
start_idx = next_idx - 1
546546
# Loop over points and mark entry and exit status
@@ -560,7 +560,7 @@ function _flag_ent_exit!(::Type{T}, ::GI.LinearRingTrait, poly, pt_list, delay_c
560560
else # delayed bouncing
561561
next_idx = ii < npts ? (ii + 1) : 1
562562
next_val = (curr_pt.point .+ pt_list[next_idx].point) ./ 2
563-
pt_in_poly = _point_filled_curve_orientation(next_val, poly; in = true, on = false, out = false, exact)
563+
pt_in_poly = _point_filled_curve_orientation(alg.manifold, next_val, poly; in = true, on = false, out = false, exact)
564564
#= start and end crossing status are the same and depend on if adjacent
565565
edges of pt_list are within poly =#
566566
start_crossing = delay_bounce_f(pt_in_poly)
@@ -588,8 +588,8 @@ returns false. Used for cutting polygons by lines.
588588
589589
Assumes that the first point is outside of the polygon and not on an edge.
590590
=#
591-
function _flag_ent_exit!(::GI.LineTrait, poly, pt_list; exact)
592-
status = !_point_filled_curve_orientation(pt_list[1].point, poly; in = true, on = false, out = false, exact)
591+
function _flag_ent_exit!(alg::FosterHormannClipping{M, A}, ::GI.LineTrait, poly, pt_list; exact) where {M, A}
592+
status = !_point_filled_curve_orientation(#=TODO: alg.manifold=#pt_list[1].point, poly; in = true, on = false, out = false, exact)
593593
# Loop over points and mark entry and exit status
594594
for (ii, curr_pt) in enumerate(pt_list)
595595
if curr_pt.crossing
@@ -602,7 +602,7 @@ end
602602

603603
#= Filters a_idx_list to just include crossing points and sets the index of all crossing
604604
points (which element they correspond to within a_idx_list). =#
605-
function _index_crossing_intrs!(a_list, b_list, a_idx_list)
605+
function _index_crossing_intrs!(alg::FosterHormannClipping{M, A}, a_list, b_list, a_idx_list) where {M, A}
606606
filter!(x -> a_list[x].crossing, a_idx_list)
607607
for (i, a_idx) in enumerate(a_idx_list)
608608
curr_node = a_list[a_idx]
@@ -631,7 +631,7 @@ A list of GeoInterface polygons is returned from this function.
631631
Note: `poly_a` and `poly_b` are temporary inputs used for debugging and can be removed
632632
eventually.
633633
=#
634-
function _trace_polynodes(::Type{T}, a_list, b_list, a_idx_list, f_step, poly_a, poly_b) where T
634+
function _trace_polynodes(alg::FosterHormannClipping{M, A}, ::Type{T}, a_list, b_list, a_idx_list, f_step, poly_a, poly_b) where {T, M, A}
635635
n_a_pts, n_b_pts = length(a_list), length(b_list)
636636
total_pts = n_a_pts + n_b_pts
637637
n_cross_pts = length(a_idx_list)
@@ -707,7 +707,7 @@ or they are separate polygons with no intersection (other than an edge or point)
707707
Return two booleans that represent if a is inside b (potentially with shared edges / points)
708708
and visa versa if b is inside of a.
709709
=#
710-
function _find_non_cross_orientation(a_list, b_list, a_poly, b_poly; exact)
710+
function _find_non_cross_orientation(m::M, a_list, b_list, a_poly, b_poly; exact) where {M <: Manifold}
711711
non_intr_a_idx = findfirst(x -> !x.inter, a_list)
712712
non_intr_b_idx = findfirst(x -> !x.inter, b_list)
713713
#= Determine if non-intersection point is in or outside of polygon - if there isn't A
@@ -721,14 +721,17 @@ function _find_non_cross_orientation(a_list, b_list, a_poly, b_poly; exact)
721721
return a_in_b, b_in_a
722722
end
723723

724+
_find_non_cross_orientation(alg::FosterHormannClipping{M}, a_list, b_list, a_poly, b_poly; exact) where {M <: Manifold} =
725+
_find_non_cross_orientation(alg.manifold, a_list, b_list, a_poly, b_poly; exact)
726+
724727
#=
725728
_add_holes_to_polys!(::Type{T}, return_polys, hole_iterator, remove_poly_idx; exact)
726729
727730
The holes specified by the hole iterator are added to the polygons in the return_polys list.
728731
If this creates more polygons, they are added to the end of the list. If this removes
729732
polygons, they are removed from the list
730733
=#
731-
function _add_holes_to_polys!(::Type{T}, return_polys, hole_iterator, remove_poly_idx; exact) where T
734+
function _add_holes_to_polys!(alg::FosterHormannClipping{M, A}, ::Type{T}, return_polys, hole_iterator, remove_poly_idx; exact) where {T, M, A}
732735
n_polys = length(return_polys)
733736
remove_hole_idx = Int[]
734737
# Remove set of holes from all polygons
@@ -741,17 +744,17 @@ function _add_holes_to_polys!(::Type{T}, return_polys, hole_iterator, remove_pol
741744
curr_poly = return_polys[j]
742745
remove_poly_idx[j] && continue
743746
curr_poly_ext = GI.nhole(curr_poly) > 0 ? GI.Polygon(StaticArrays.SVector(GI.getexterior(curr_poly))) : curr_poly
744-
in_ext, on_ext, out_ext = _line_polygon_interactions(curr_hole, curr_poly_ext; exact, closed_line = true)
747+
in_ext, on_ext, out_ext = _line_polygon_interactions(#=TODO: alg.manifold=#curr_hole, curr_poly_ext; exact, closed_line = true)
745748
if in_ext # hole is at least partially within the polygon's exterior
746-
new_hole, new_hole_poly, n_new_pieces = _combine_holes!(T, curr_hole, curr_poly, return_polys, remove_hole_idx)
749+
new_hole, new_hole_poly, n_new_pieces = _combine_holes!(alg, T, curr_hole, curr_poly, return_polys, remove_hole_idx)
747750
if n_new_pieces > 0
748751
append!(remove_poly_idx, falses(n_new_pieces))
749752
n_new_per_poly += n_new_pieces
750753
end
751754
if !on_ext && !out_ext # hole is completely within exterior
752755
push!(curr_poly.geom, new_hole)
753756
else # hole is partially within and outside of polygon's exterior
754-
new_polys = difference(curr_poly_ext, new_hole_poly, T; target=GI.PolygonTrait())
757+
new_polys = difference(alg, curr_poly_ext, new_hole_poly, T; target=GI.PolygonTrait())
755758
n_new_polys = length(new_polys) - 1
756759
# replace original
757760
curr_poly.geom[1] = GI.getexterior(new_polys[1])
@@ -763,7 +766,7 @@ function _add_holes_to_polys!(::Type{T}, return_polys, hole_iterator, remove_pol
763766
end
764767
end
765768
# polygon is completely within hole
766-
elseif coveredby(curr_poly_ext, GI.Polygon(StaticArrays.SVector(curr_hole)))
769+
elseif coveredby(#=TODO: alg.manifold=#curr_poly_ext, GI.Polygon(StaticArrays.SVector(curr_hole)))
767770
remove_poly_idx[j] = true
768771
end
769772
end
@@ -788,16 +791,16 @@ are in the "main" polygon or in one of these new pieces and moved accordingly.
788791
If the holes don't touch or curr_poly has no holes, then new_hole is returned without any
789792
changes.
790793
=#
791-
function _combine_holes!(::Type{T}, new_hole, curr_poly, return_polys, remove_hole_idx) where T
794+
function _combine_holes!(alg::FosterHormannClipping{M, A}, ::Type{T}, new_hole, curr_poly, return_polys, remove_hole_idx) where {T, M, A}
792795
n_new_polys = 0
793796
empty!(remove_hole_idx)
794797
new_hole_poly = GI.Polygon(StaticArrays.SVector(new_hole))
795798
# Combine any existing holes in curr_poly with new hole
796799
for (k, old_hole) in enumerate(GI.gethole(curr_poly))
797800
old_hole_poly = GI.Polygon(StaticArrays.SVector(old_hole))
798-
if intersects(new_hole_poly, old_hole_poly)
801+
if intersects(#=TODO: alg.manifold=#new_hole_poly, old_hole_poly)
799802
# If the holes intersect, combine them into a bigger hole
800-
hole_union = union(new_hole_poly, old_hole_poly, T; target = GI.PolygonTrait())[1]
803+
hole_union = union(alg, new_hole_poly, old_hole_poly, T; target = GI.PolygonTrait())[1]
801804
push!(remove_hole_idx, k + 1)
802805
new_hole = GI.getexterior(hole_union)
803806
new_hole_poly = GI.Polygon(StaticArrays.SVector(new_hole))
@@ -826,7 +829,7 @@ end
826829

827830
#= Remove collinear edge points, other than the first and last edge vertex, to simplify
828831
polygon - including both the exterior ring and any holes=#
829-
function _remove_collinear_points!(polys, remove_idx, poly_a, poly_b)
832+
function _remove_collinear_points!(alg::FosterHormannClipping{M, A}, polys, remove_idx, poly_a, poly_b) where {M, A}
830833
for (i, poly) in Iterators.reverse(enumerate(polys))
831834
for (j, ring) in Iterators.reverse(enumerate(GI.getring(poly)))
832835
n = length(ring.geom)
@@ -844,6 +847,7 @@ function _remove_collinear_points!(polys, remove_idx, poly_a, poly_b)
844847
else
845848
p3 = p
846849
# check if p2 is approximately on the edge formed by p1 and p3 - remove if so
850+
# TODO: make this manifold aware
847851
if Predicates.orient(p1, p2, p3; exact = False()) == 0
848852
remove_idx[i - 1] = true
849853
end

0 commit comments

Comments
 (0)