@@ -14,20 +14,20 @@ The Wieler-Atherton algorithm for clipping polygons.
1414""" 
1515struct  WeilerAthertonClipping <:  ClippingMethod  end 
1616
17- #  VertexType has three different types of vertices used for deciding how to navigate the data
18- #  structure when collecting the polygon rings after clipping.
17+ #  VertexType distinguishes three different types of vertices used for constructing the structure
18+ #  used by the Weiler-Atherton clipping algorithm. Normal type represents regular vertices, the
19+ #  connecting points of edges of a rings. Entering and Exiting types represent intersections of
20+ #  two ring edges, where one belongs to a clipping and other belongs to a clipped ring. The
21+ #  Entering and Exiting types describe, from the perspective of the edges of the clipping ring,
22+ #  whether it enters or exits the interior of the clipped ring.
1923abstract type  VertexType end 
2024abstract type  Normal <:  VertexType  end 
2125abstract type  Entering <:  VertexType  end 
2226abstract type  Exiting <:  VertexType  end 
2327
2428#  Data structure for clipping the polygons. Fields left and right are used depending on the
25- #  VertexType. If Normal, left points to the following vertex of the original ring, and right
26- #  to the next intersection vertex on the edge between point and left.point, or the following
27- #  original ring vertex if no intersections on the edge. For Entering and Exiting types, left
28- #  poitns to the following vertex on the clipping ring and right to the following vertex on one
29- #  of the clipped rings.
30- #  TODO  Either properly document the usage of left and right, or separate RingVertex into Entering, Exiting and Normal vertices.
29+ #  VertexType, as designated with the helper functions. The data structure forms a directed
30+ #  graph with each element always pointing to two elements.
3131mutable struct  RingVertex{VT<: VertexType ,M<: Manifold ,C<: CRS }
3232  point:: Point{M,C} 
3333  left:: RingVertex{<:VertexType,M,C} 
@@ -53,11 +53,41 @@ function appendvertices!(v₁::RingVertex{Normal}, v₂::RingVertex{Normal})
5353  v₁. right =  v₂
5454end 
5555
56- #  Traversing and selecting following vertices for collecting of the rings after clipping depends
57- #  on the vertex type. Helper nextvertex follows the correct path.
56+ #  Helper functions to designate the use of the left and right branches of the RingVertex.
57+ 
58+ #  Normal vertex uses the left branch for the next Normal vertex,
59+ #  which is the end of the ring edge for which the current vertex is the edge start.
60+ nextnormal (v:: RingVertex{Normal} ) =  v. left
61+ #  Normal vertex uses the right branch for the next intersection on the ring edge if any.
62+ #  Otherwise, it holds the next Normal vertex, same as for the left branch.
5863nextvertex (v:: RingVertex{Normal} ) =  v. right
59- nextvertex (v:: RingVertex{Entering} ) =  v. right
60- nextvertex (v:: RingVertex{Exiting} ) =  v. left
64+ #  Next clipping vertex is a following vertex, normal or an intersection, on a clipping ring.
65+ #  Next clipped vertex is a following vertex, normal or an intersection, on a clipped ring.
66+ #  Normal vertices are either on a clipping or a clipped, but the implementation is same
67+ #  and helper functions can be used interchangeably.
68+ getnextclippingvertex (v:: RingVertex{Normal} ) =  v. right
69+ setnextclippingvertex! (v:: RingVertex{Normal} , next:: RingVertex ) =  v. right =  next
70+ getnextclippedvertex (v:: RingVertex{Normal} ) =  v. right
71+ setnextclippedvertex! (v:: RingVertex{Normal} , next:: RingVertex ) =  v. right =  next
72+ 
73+ #  Both Entering and Exiting vertices are always intersections and use the left branch for
74+ #  the following vertex on the clipping ring.
75+ getnextclippingvertex (v:: RingVertex ) =  v. left
76+ setnextclippingvertex! (v:: RingVertex , next:: RingVertex ) =  v. left =  next
77+ 
78+ #  Similarly, the right branch holds the following vertex on the clipped ring.
79+ getnextclippedvertex (v:: RingVertex ) =  v. right
80+ setnextclippedvertex! (v:: RingVertex , next:: RingVertex ) =  v. right =  next
81+ 
82+ #  Traversing and selecting correct following vertices from the directed graph of RingVertex
83+ #  elements should switch between rings whenever an intersection is encountered. If the current
84+ #  edge is entering the interior of the clipped ring, follow to the next vertex on the clipping
85+ #  ring. In case the edge is exiting the interior of the clipped ring, then follow the next vertex
86+ #  on the clipped ring. For a Normal vertex take the next vertex which can be either an intersection
87+ #  or an edge end.
88+ getnextresultvertex (v:: RingVertex{Normal} ) =  nextvertex (v)
89+ getnextresultvertex (v:: RingVertex{Entering} ) =  getnextclippedvertex (v)
90+ getnextresultvertex (v:: RingVertex{Exiting} ) =  getnextclippingvertex (v)
6191
6292function  clip (poly:: Polygon , ring:: Ring , :: WeilerAthertonClipping )
6393  polyrings =  rings (poly)
@@ -85,35 +115,39 @@ function clip(poly::Polygon, ring::Ring, ::WeilerAthertonClipping)
85115    #  Three consecutive clipping vertices are used to properly identify intersection vertex type
86116    #  for corner cases, so the clipping segment is constructed with the two following vertices
87117    #  after the current one.
88-     clippingsegment =  Segment (clipping. left. point, clipping. left. left. point)
118+     clippingedgestart =  nextnormal (clipping)
119+     clippingedgeend =  nextnormal (clippingedgestart)
120+     clippingsegment =  Segment (clippingedgestart. point, clippingedgeend. point)
89121
90122    for  (k, startclipped) in  enumerate (clippedrings)
91123      clipped =  startclipped
92124      while  true 
93125        #  Like for the clipping, the clipped also uses three consecutive vertices.
94-         clippedsegment =  Segment (clipped. left. point, clipped. left. left. point)
126+         clippededgestart =  nextnormal (clipped)
127+         clippededgeend =  nextnormal (clippededgestart)
128+         clippedsegment =  Segment (clippededgestart. point, clippededgeend. point)
95129
96130        I =  intersection (clippingsegment, clippedsegment)
97131        vertex =  vertexfromintersection (I, clipping, clipped)
98-         success =  insertintersections! (vertex, clipping, clipped , entering)
132+         success =  insertintersections! (vertex, clippingedgestart, clippededgestart , entering)
99133        intersected[k] =  intersected[k] ||  success
100134
101-         clipped =  clipped. left 
102-         clipped. left  ==  startclipped. left  &&  break 
135+         clipped =  nextnormal ( clipped) 
136+         nextnormal ( clipped)  ==  nextnormal ( startclipped)  &&  break 
103137      end 
104138    end 
105139
106-     clipping =  clipping. left 
107-     clipping. left  ==  startclipping. left  &&  break 
140+     clipping =  nextnormal ( clipping) 
141+     nextnormal ( clipping)  ==  nextnormal ( startclipping)  &&  break 
108142  end 
109143
110-   #  Handle the case when no interections have been found.
111144  if  ! any (intersected)
145+     #  Handle the case when no interections have been found.
112146    if  orientation (ring) ==  CW
113-       #  For an inner clipping ring take all outside  rings.
147+       #  For an inner clipping ring take all clipped  rings outside of it .
114148      return  PolyArea (collectoutsiderings (ring, polyrings)... )
115149    else 
116-       #  For an outer clipping ring add it to act as the outer ring.
150+       #  For an outer clipping ring add it to act as the outer ring of the clipped ring .
117151      collectedrings =  all (v ∈  PolyArea (polyrings[1 ]) for  v in  vertices (ring)) ?  [ring] :  []
118152    end 
119153  else 
@@ -177,34 +211,37 @@ function perhapsaddnonintersected!(ring, polyrings, intersected)
177211  newpolyrings
178212end 
179213
180- #  Inserts the  intersection in the ring. 
181- function   insertintersection! (head :: RingVertex , intersection :: RingVertex , side :: Symbol )
182-   tail  =  head. left 
183-   vertex  =  head
184- 
185-   new  =   measure ( Segment ( head. point, intersection . point)) 
214+ function   insertintersection! (head :: RingVertex{Normal} ,  intersection:: RingVertex , getnext, setnext!) 
215+   tail  =   nextnormal (head )
216+   current  =  head
217+   newdistance  =  measure ( Segment ( head. point, intersection . point)) 
218+    #  Search for the place to insert the intersection by comparing its distance 
219+   #  from the  head with other inserted intersections. 
186220  while  true 
187-     os =  isnormal (vertex) ?  :right  :  side
188-     current =  measure (Segment (head. point, getfield (vertex, os). point))
189-     if  (new <  current) ||  (getfield (vertex, os) ==  tail)
190-       next =  getfield (vertex, os)
191-       if  ! (new ≈  measure (Segment (head. point, next. point)))
192-         setfield! (intersection, side, next)
193-         setfield! (vertex, os, intersection)
221+     before =  current
222+     current =  getnext (current)
223+     currentdistance =  measure (Segment (head. point, current. point))
224+ 
225+     if  (newdistance <  currentdistance) ||  (current ==  tail)
226+       if  ! (newdistance ≈  currentdistance) #  TODO  Check if this is needed.
227+         #  Only add if it is not coincident with the following vertex, or it could be added twice,
228+         #  if it is the tail vertex. In such case, the intersection will be detected second time
229+         #  and added then.
230+         setnext! (intersection, current)
231+         setnext! (before, intersection)
194232      end 
195233      break 
196234    end 
197-     vertex =  getfield (vertex, os)
198235  end 
199236end 
200237
201238#  Inserts the intersection into both the clipping and the clipped rings.
202- function  insertintersections! (vertex:: Tuple , clipping, clipped, entering)
239+ function  insertintersections! (vertex:: Tuple , clipping:: RingVertex{Normal} , clipped:: RingVertex{Normal} , entering)
203240  (vtype, point) =  vertex
204241  if  ! isnothing (vtype)
205242    intersection =  RingVertex {vtype} (point)
206-     insertintersection! (clipping. left , intersection, :left )
207-     insertintersection! (clipped. left , intersection, :right )
243+     insertintersection! (clipping, intersection, getnextclippingvertex, setnextclippingvertex! )
244+     insertintersection! (clipped, intersection, getnextclippedvertex, setnextclippedvertex! )
208245
209246    if  vtype ==  Entering
210247      push! (entering, intersection)
@@ -235,7 +272,7 @@ function collectclipped(entering::Vector{RingVertex{Entering}})
235272
236273      push! (ring, vertex)
237274      push! (visited, vertex)
238-       vertex =  nextvertex (vertex)
275+       vertex =  getnextresultvertex (vertex)
239276    end 
240277
241278    #  Remove duplicates.
@@ -273,30 +310,30 @@ function vertexfromintersection(I, clipping, clipped)
273310end 
274311
275312function  vertexfromcrossing (point, clipping, clipped)
276-   cl =  Line (clipping. left . point, clipping. left . left . point)
277-   vertextype =  sideof (clipped. left . left . point, cl) ==  LEFT ?  Entering :  Exiting
313+   cl =  Line (nextnormal ( clipping) . point, nextnormal ( nextnormal ( clipping)) . point)
314+   vertextype =  sideof (nextnormal ( nextnormal ( clipped)) . point, cl) ==  LEFT ?  Entering :  Exiting
278315  (vertextype, point)
279316end 
280317
281318function  vertexfromedgetouching (point, clipping, clipped)
282319  vertextype =  nothing 
283-   if  point ≈  clipped. left . point
320+   if  point ≈  nextnormal ( clipped) . point
284321    #  When intersection is at the shared vertex of two edges of the clipped ring,
285-     #  then split the interscting  edge of the clipping ring at the intersection point.
322+     #  then split the intersecting  edge of the clipping ring at the intersection point.
286323    vertextype =  decidedirection (
287-       Segment (clipped. point, clipped. left . point),
288-       Segment (clipped. left . point, clipped. left . left . point),
289-       Segment (clipping. left . point, point),
290-       Segment (point, clipping. left . left . point)
324+       Segment (clipped. point, nextnormal ( clipped) . point),
325+       Segment (nextnormal ( clipped) . point, nextnormal ( nextnormal ( clipped)) . point),
326+       Segment (nextnormal ( clipping) . point, point),
327+       Segment (point, nextnormal ( nextnormal ( clipping)) . point)
291328    )
292-   elseif  point ≈  clipping. left . point
329+   elseif  point ≈  nextnormal ( clipping) . point
293330    #  When intersection is at the shared vertex of two edges of the clipping ring,
294-     #  then split the interscting  edge of the clipped ring at the intersection point.
331+     #  then split the intersecting  edge of the clipped ring at the intersection point.
295332    vertextype =  decidedirection (
296-       Segment (clipped. left . point, point),
297-       Segment (point, clipped. left . left . point),
298-       Segment (clipping. point, clipping. left . point),
299-       Segment (clipping. left . point, clipping. left . left . point)
333+       Segment (nextnormal ( clipped) . point, point),
334+       Segment (point, nextnormal ( nextnormal ( clipped)) . point),
335+       Segment (clipping. point, nextnormal ( clipping) . point),
336+       Segment (nextnormal ( clipping) . point, nextnormal ( nextnormal ( clipping)) . point)
300337    )
301338  end 
302339  (vertextype, point)
@@ -305,50 +342,50 @@ end
305342function  vertexfromcornertouching (point, clipping, clipped)
306343  vertextype =  nothing 
307344  #  When intersection is at the shared vertices of both the clipping and the clipped rings.
308-   if  (point ≈  clipped. left . point) &&  (point ≈  clipping. left . point)
345+   if  (point ≈  nextnormal ( clipped) . point) &&  (point ≈  nextnormal ( clipping) . point)
309346    #  Only applies if the intersection coincides with the middles of the currently observed
310347    #  vertices for both clipping and clipped rings.
311348    vertextype =  decidedirection (
312349      Segment (clipped. point, point),
313-       Segment (point, clipped. left . left . point),
350+       Segment (point, nextnormal ( nextnormal ( clipped)) . point),
314351      Segment (clipping. point, point),
315-       Segment (point, clipping. left . left . point)
352+       Segment (point, nextnormal ( nextnormal ( clipping)) . point)
316353    )
317354  end 
318355  (vertextype, point)
319356end 
320357
321358function  vertexfromoverlapping (segment, clipping, clipped)
322359  #  For both ends of the intersecting segment, check if it coincides with the middle of
323-   #  the obeserved  vertices for clipped and clipping rings. If it does, attempt adding a
360+   #  the observed  vertices for clipped and clipping rings. If it does, attempt adding a
324361  #  point.
325362
326363  ret =  Tuple[]
327364  for  point in  extrema (segment)
328-     if  point ≈  clipped. left . point
329-       clippingprev =  Segment (clipping. left . point, point)
365+     if  point ≈  nextnormal ( clipped) . point
366+       clippingprev =  Segment (nextnormal ( clipping) . point, point)
330367      if  measure (clippingprev) ≈  0.0 u " m" 
331368        clippingprev =  Segment (clipping. point, point)
332369      end 
333370      vertextype =  decidedirection (
334371        Segment (clipped. point, point),
335-         Segment (point, clipped. left . left . point),
372+         Segment (point, nextnormal ( nextnormal ( clipped)) . point),
336373        clippingprev,
337-         Segment (point, clipping. left . left . point)
374+         Segment (point, nextnormal ( nextnormal ( clipping)) . point)
338375      )
339376      push! (ret, (vertextype, point))
340377    end 
341378
342-     if  point ≈  clipping. left . point
343-       clippedprev =  Segment (clipped. left . point, point)
379+     if  point ≈  nextnormal ( clipping) . point
380+       clippedprev =  Segment (nextnormal ( clipped) . point, point)
344381      if  measure (clippedprev) ≈  0.0 u " m" 
345382        clippedprev =  Segment (clipped. point, point)
346383      end 
347384      vertextype =  decidedirection (
348385        clippedprev,
349-         Segment (point, clipped. left . left . point),
386+         Segment (point, nextnormal ( nextnormal ( clipped)) . point),
350387        Segment (clipping. point, point),
351-         Segment (point, clipping. left . left . point)
388+         Segment (point, nextnormal ( nextnormal ( clipping)) . point)
352389      )
353390      push! (ret, (vertextype, point))
354391    end 
@@ -416,5 +453,5 @@ function gettraversalring(ring::Ring)
416453    start =  new
417454  end 
418455
419-   return  start. left 
456+   return  nextnormal ( start) 
420457end 
0 commit comments