@@ -46,6 +46,9 @@ RingVertex{VT}(point::Point{M,C}) where {VT<:VertexType,M<:Manifold,C<:CRS} = Ri
4646isnormal (:: RingVertex{Normal} ) =  true 
4747isnormal (:: RingVertex ) =  false 
4848
49+ isentering (:: RingVertex{Entering} ) =  true 
50+ isentering (:: RingVertex ) =  false 
51+ 
4952function  appendvertices! (v₁:: RingVertex{Normal} , v₂:: RingVertex{Normal} )
5053  v₂. left =  v₁. left
5154  v₁. left =  v₂
@@ -100,45 +103,51 @@ function clip(poly::Polygon, ring::Ring, ::WeilerAthertonClipping)
100103
101104  #  Convert the subject polygon rings and the clipping ring to the RingVertex data structure.
102105  clippedrings =  [gettraversalring (r) for  r in  polyrings]
103-   startclipping  =  gettraversalring (ring)
106+   clipping  =  gettraversalring (ring)
104107
105108  #  For keeping track of intersected rings, as the non-intersected ones need additional
106109  #  processing at the end.
107110  intersected =  zeros (Bool, length (clippedrings))
108111
112+   #  For marking of clipping ring vertices which touch rings of clipped polygon.
113+   clippingtouches =  zeros (Bool, nvertices (ring))
114+ 
109115  #  For collecting all entering vertices, as they are used as starting points for collection
110116  #  of the output rings.
111117  entering =  RingVertex{Entering}[]
112118
113-   clipping =  startclipping
114-   while  true 
119+   for  l in  1 : (nvertices (ring))
115120    #  Three consecutive clipping vertices are used to properly identify intersection vertex type
116121    #  for corner cases, so the clipping segment is constructed with the two following vertices
117122    #  after the current one.
118123    clippingedgestart =  nextnormal (clipping)
119124    clippingedgeend =  nextnormal (clippingedgestart)
120125    clippingsegment =  Segment (clippingedgestart. point, clippingedgeend. point)
121126
122-     for  (k, startclipped) in  enumerate (clippedrings)
123-       clipped =  startclipped
124-       while  true 
127+     for  (k, clipped) in  enumerate (clippedrings)
128+       for  _ in  1 : (nvertices (polyrings[k]))
125129        #  Like for the clipping, the clipped also uses three consecutive vertices.
126130        clippededgestart =  nextnormal (clipped)
127131        clippededgeend =  nextnormal (clippededgestart)
128132        clippedsegment =  Segment (clippededgestart. point, clippededgeend. point)
129133
130134        I =  intersection (clippingsegment, clippedsegment)
131-         vertex =  vertexfromintersection (I, clipping, clipped)
132-         success =  insertintersections! (vertex, clippingedgestart, clippededgestart, entering)
133-         intersected[k] =  intersected[k] ||  success
135+ 
136+         if  type (I) !=  NotIntersecting
137+           vertices =  vertexfromintersection (I, clipping, clipped)
138+           if  ! isnothing (vertices)
139+             insertintersections! (vertices, clippingedgestart, clippededgestart, entering)
140+             intersected[k] =  true 
141+           elseif  type (I) in  [EdgeTouching, CornerTouching] &&  get (I) ≈  clippingedgestart. point
142+             clippingtouches[l] =  true 
143+           end 
144+         end 
134145
135146        clipped =  nextnormal (clipped)
136-         nextnormal (clipped) ==  nextnormal (startclipped) &&  break 
137147      end 
138148    end 
139149
140150    clipping =  nextnormal (clipping)
141-     nextnormal (clipping) ==  nextnormal (startclipping) &&  break 
142151  end 
143152
144153  if  ! any (intersected)
@@ -147,8 +156,11 @@ function clip(poly::Polygon, ring::Ring, ::WeilerAthertonClipping)
147156      #  For an inner clipping ring take all clipped rings outside of it.
148157      return  PolyArea (collectoutsiderings (ring, polyrings)... )
149158    else 
159+       #  Align the clippingtouches with the ring vertices.
160+       clippingtouches =  [clippingtouches[end ], clippingtouches[1 : (end  -  1 )]. .. ]
150161      #  For an outer clipping ring add it to act as the outer ring of the clipped ring.
151-       collectedrings =  all (v ∈  PolyArea (polyrings[1 ]) for  v in  vertices (ring)) ?  [ring] :  []
162+       collectedrings = 
163+         all (t ||  v ∈  PolyArea (polyrings[1 ]) for  (t, v) in  zip (clippingtouches, vertices (ring))) ?  [ring] :  []
152164    end 
153165  else 
154166    #  Collect rings formed from the intersected rings.
@@ -223,36 +235,27 @@ function insertintersection!(head::RingVertex{Normal}, intersection::RingVertex,
223235    currentdistance =  measure (Segment (head. point, current. point))
224236
225237    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)
232-       end 
238+       setnext! (intersection, current)
239+       setnext! (before, intersection)
233240      break 
234241    end 
235242  end 
236243end 
237244
245+ insertintersections! (_:: Nothing , _, _, _) =  nothing 
246+ 
238247#  Inserts the intersection into both the clipping and the clipped rings.
239- function  insertintersections! (vertex:: Tuple , clipping:: RingVertex{Normal} , clipped:: RingVertex{Normal} , entering)
240-   (vtype, point) =  vertex
241-   if  ! isnothing (vtype)
242-     intersection =  RingVertex {vtype} (point)
243-     insertintersection! (clipping, intersection, getnextclippingvertex, setnextclippingvertex!)
244-     insertintersection! (clipped, intersection, getnextclippedvertex, setnextclippedvertex!)
245- 
246-     if  vtype ==  Entering
247-       push! (entering, intersection)
248-     end 
249-     return  true 
248+ function  insertintersections! (vertex:: RingVertex , clipping:: RingVertex{Normal} , clipped:: RingVertex{Normal} , entering)
249+   insertintersection! (clipping, vertex, getnextclippingvertex, setnextclippingvertex!)
250+   insertintersection! (clipped, vertex, getnextclippedvertex, setnextclippedvertex!)
251+ 
252+   if  isentering (vertex)
253+     push! (entering, vertex)
250254  end 
251-   false 
252255end 
253256
254257insertintersections! (vertices:: Array , clipping, clipped, entering) = 
255-   any ( insertintersections! .(vertices, Ref (clipping), Ref (clipped), Ref (entering) ))
258+   insertintersections! .(vertices, Ref (clipping), Ref (clipped), Ref (entering))
256259
257260#  Takes a list of entering vertices and returns all rings that contain those vertices.
258261function  collectclipped (entering:: Vector{RingVertex{Entering}} )
@@ -270,28 +273,14 @@ function collectclipped(entering::Vector{RingVertex{Entering}})
270273        break 
271274      end 
272275
273-       push! (ring, vertex)
274-       push! (visited, vertex)
275-       vertex =  getnextresultvertex (vertex)
276-     end 
277- 
278-     #  Remove duplicates.
279-     newring =  RingVertex[ring[1 ]]
280-     for  i in  2 : length (ring)
281-       if  ! (ring[i]. point ≈  newring[end ]. point)
282-         push! (newring, ring[i])
276+       nextvertex =  getnextresultvertex (vertex)
277+       #  Skip adding sequential duplicates, and sequential entering vertices
278+       #  which can happen with overlapping edge intersections.
279+       if  ! (isentering (vertex) &&  isentering (nextvertex)) &&  ! (vertex. point ≈  nextvertex. point)
280+         push! (ring, vertex)
283281      end 
284-     end 
285-     ring =  newring
286- 
287-     #  Polygon might start several vertices after the first collected.
288-     #  This generally happens when there are overlapping edges that lead
289-     #  to several entering vertices without exiting in between. Then, the
290-     #  actual polygon is found by discarding the extra vertices before the
291-     #  proper loop.
292-     k =  findfirst (x ->  ring[end ]. point ==  x. point, ring[1 : (end  -  1 )])
293-     if  ! isnothing (k)
294-       ring =  ring[(k +  1 ): end ]
282+       push! (visited, vertex)
283+       vertex =  nextvertex
295284    end 
296285
297286    if  length (ring) >  2 
@@ -306,13 +295,13 @@ function vertexfromintersection(I, clipping, clipped)
306295  type (I) ==  CornerTouching &&  return  vertexfromcornertouching (get (I), clipping, clipped)
307296  type (I) ==  EdgeTouching &&  return  vertexfromedgetouching (get (I), clipping, clipped)
308297  type (I) ==  Overlapping &&  return  vertexfromoverlapping (get (I), clipping, clipped)
309-   ( nothing ,  nothing ) 
298+   @assert   false   #  No other intersection types expected. 
310299end 
311300
312301function  vertexfromcrossing (point, clipping, clipped)
313302  cl =  Line (nextnormal (clipping). point, nextnormal (nextnormal (clipping)). point)
314303  vertextype =  sideof (nextnormal (nextnormal (clipped)). point, cl) ==  LEFT ?  Entering :  Exiting
315-   ( vertextype,  point)
304+   RingVertex { vertextype} ( point)
316305end 
317306
318307function  vertexfromedgetouching (point, clipping, clipped)
@@ -336,7 +325,7 @@ function vertexfromedgetouching(point, clipping, clipped)
336325      Segment (nextnormal (clipping). point, nextnormal (nextnormal (clipping)). point)
337326    )
338327  end 
339-   (vertextype,  point)
328+   isnothing (vertextype)  ?   nothing   :   RingVertex {vertextype} ( point)
340329end 
341330
342331function  vertexfromcornertouching (point, clipping, clipped)
@@ -352,15 +341,15 @@ function vertexfromcornertouching(point, clipping, clipped)
352341      Segment (point, nextnormal (nextnormal (clipping)). point)
353342    )
354343  end 
355-   (vertextype,  point)
344+   isnothing (vertextype)  ?   nothing   :   RingVertex {vertextype} ( point)
356345end 
357346
358347function  vertexfromoverlapping (segment, clipping, clipped)
359348  #  For both ends of the intersecting segment, check if it coincides with the middle of
360349  #  the observed vertices for clipped and clipping rings. If it does, attempt adding a
361350  #  point.
362351
363-   ret =  Tuple []
352+   ret =  RingVertex []
364353  for  point in  extrema (segment)
365354    if  point ≈  nextnormal (clipped). point
366355      clippingprev =  Segment (nextnormal (clipping). point, point)
@@ -373,7 +362,9 @@ function vertexfromoverlapping(segment, clipping, clipped)
373362        clippingprev,
374363        Segment (point, nextnormal (nextnormal (clipping)). point)
375364      )
376-       push! (ret, (vertextype, point))
365+       if  ! isnothing (vertextype)
366+         push! (ret, RingVertex {vertextype} (point))
367+       end 
377368    end 
378369
379370    if  point ≈  nextnormal (clipping). point
@@ -387,10 +378,12 @@ function vertexfromoverlapping(segment, clipping, clipped)
387378        Segment (clipping. point, point),
388379        Segment (point, nextnormal (nextnormal (clipping)). point)
389380      )
390-       push! (ret, (vertextype, point))
381+       if  ! isnothing (vertextype)
382+         push! (ret, RingVertex {vertextype} (point))
383+       end 
391384    end 
392385  end 
393-   ret
386+   ( length (ret)  ==   0 )  ?   nothing   :   ret
394387end 
395388
396389#  Used to figure out the type of the vertex to add when intersection is other than the crossing
0 commit comments