@@ -27,16 +27,21 @@ public class FortuneSweep {
2727 /// Service Data Structures
2828 private var eventQueue : PriorityQueue < Event > !
2929 private var beachline : Beachline !
30- private var sweepLineY = Double ( 0 )
30+ private var sweepLineY : Double = 0
3131 private var firstSiteY : Double ?
3232
3333 private var container : Rectangle !
3434 private var clipper : Rectangle !
3535
36+ /// Debug Data structures
37+ private var logger : FortuneSweepLogging ?
38+ private var currentStep : Int = 0
3639 /// Result Data Structure
37- private( set) var diagram = Diagram ( )
40+ private( set) var diagram : Diagram !
3841
39- public init ( ) { }
42+ public init ( logger: FortuneSweepLogging ? = nil ) {
43+ self . logger = logger
44+ }
4045
4146 public func compute(
4247 sites: Set < Site > ,
@@ -48,9 +53,13 @@ public class FortuneSweep {
4853 let filtered = sites
4954 . filter { clipper. contains ( $0) }
5055 . map { Event ( point: $0) }
56+
5157 /// Diagram is a whole plane. Do nothing
52- if filtered. isEmpty { return }
53-
58+ if filtered. isEmpty {
59+ logger? . log ( " Computation done. No sites inside defined area! " , level: . info)
60+ return
61+ }
62+ currentStep = 0
5463 sweepLineY = 0
5564 firstSiteY = nil
5665 beachline = Beachline ( )
@@ -74,6 +83,9 @@ public class FortuneSweep {
7483 /// 1. Pop an event from the event queue
7584 /// 2. Check the event type and process the event appropriately
7685 private func step( ) {
86+ currentStep += 1
87+ logger? . log ( " Step: \( currentStep) " , level: . info)
88+
7789 if let event = eventQueue. pop ( ) {
7890 switch event. kind {
7991 case . site:
@@ -88,6 +100,8 @@ public class FortuneSweep {
88100 /// Processes **Site event** and performs all the necessary actions
89101 /// - Parameter event: **Site Event** to process
90102 private func processSiteEvent( _ event: Event ) {
103+ logger? . log ( " Site Event: \( event. point) " , level: . info)
104+
91105 /// #Step 1:
92106 /// Update **Sweepline** position
93107 sweepLineY = event. point. y
@@ -100,12 +114,12 @@ public class FortuneSweep {
100114 /// Case 1: (Always present once)
101115 /// Beachline is empty. Create beachline root Arc and return
102116 if beachline. isEmpty {
117+ logger? . log ( " Site Event first occurence. Root arc inserted for Site: \( event. point) " , level: . info)
103118 let root = beachline. insertRootArc ( point: event. point)
104119 firstSiteY = event. point. y
105120
106- let padding : Double = 20
121+ let padding : Double = 20 // Arbitrary padding to make sure that container contains clipping rect
107122 container = . rect( from: clipper, with: padding)
108- // container = clipper
109123
110124 /// Create new **Cell** record in **Voronoi Diagram**
111125 container. expandToContainPoint ( event. point)
@@ -121,6 +135,8 @@ public class FortuneSweep {
121135 /// - *y* coordinate will lay somewhere far above the points.
122136 /// We replace *y* with an arbitrary value big enough to cover our case. (`yVal`)
123137 if firstSiteY == sweepLineY {
138+ logger? . log ( " Site Event degenerate case (Existing Sites share Y coodinate ( \( sweepLineY) ) with new Site) for Site: \( event. point) " , level: . warning)
139+
124140 container. expandToContainPoint ( event. point)
125141 let yVal : Double = - 1000000 //.leastNormalMagnitude
126142 let arc = beachline. handleSpecialArcInsertionCase ( event. point)
@@ -137,7 +153,7 @@ public class FortuneSweep {
137153 arc. leftHalfEdge = diagram. createHalfEdge ( arc. cell!)
138154 arc. leftHalfEdge? . origin = p
139155 makeTwins ( prev. rightHalfEdge, arc. leftHalfEdge)
140-
156+
141157 /// There is no sense to check for circle event when we encounter degenerate case because all the sites are colinear
142158 return
143159 }
@@ -156,6 +172,8 @@ public class FortuneSweep {
156172 container. expandToContainPoint ( event. point)
157173 diagram. createCell ( newArc)
158174
175+
176+
159177 /// #Step 3:
160178 /// If the arc we broke has circle event, than this event is false-alarm and has to be removed
161179 removeCircleEvent ( newArc. prev)
@@ -212,6 +230,8 @@ public class FortuneSweep {
212230
213231 prev. rightHalfEdge = lTwin
214232 next. leftHalfEdge = rTwin
233+
234+ logger? . log ( " Site Event degenerate case (Breapoint has the same X coordinate as a Site: \( event. point) " , level: . warning)
215235 } else {
216236 /// Regular and most likely case. Here we break the arc, create **HalfEdge** records and set proper pointers between them
217237 next. cell = prev. cell
@@ -282,6 +302,8 @@ public class FortuneSweep {
282302 /// Processes circle event and performs all the necessary actions
283303 /// - Parameter event: **Circle Event**
284304 private func processCircleEvent( _ event: Event ) {
305+ logger? . log ( " Circle Event: \( event. point) " , level: . info)
306+
285307 guard let arc = event. arc,
286308 let left = arc. prev,
287309 let right = arc. next
@@ -327,6 +349,8 @@ public class FortuneSweep {
327349 /// - arc: **Beachline** arc to add event
328350 /// - circle: Circle represented by three points
329351 private func createCircleEvent( _ arc: Arc ) {
352+ logger? . log ( " Create Circle Event for Arc: \( arc. point!) " , level: . info)
353+
330354 let left = arc. prev
331355 let right = arc. next
332356 guard let circle = checkCircleEvent ( left: left, mid: arc, right: right) else {
@@ -356,6 +380,8 @@ public class FortuneSweep {
356380
357381 eventQueue. removeAll ( event)
358382 arc. event = nil
383+
384+ logger? . log ( " Remove Circle Event for Arc: \( arc. point!) " , level: . info)
359385 }
360386
361387
@@ -364,9 +390,7 @@ public class FortuneSweep {
364390 /// 2. Complete incomplete cells
365391 /// 3. Clip cells to clipping rectangle
366392 private func terminate( ) {
367- // if diagram.cells.count == 1 {
368- // return
369- // }
393+ logger? . log ( " Event Queue is empty. Diagram bounding started. " , level: . info)
370394
371395 // Step 1:
372396 // Bound incomplete arcs
@@ -404,6 +428,8 @@ public class FortuneSweep {
404428 // Clip cells
405429 clipCell ( cell, clippingRect: clipper)
406430 }
431+
432+ logger? . log ( " Done! " , level: . info)
407433 }
408434
409435 /// Some of the cells will not be completed (Are not looped linked list of half-edges)
@@ -502,7 +528,8 @@ public class FortuneSweep {
502528 var finish = false
503529 while !finish {
504530 guard let segmentToClip = he? . toSegment ( ) else {
505- fatalError ( " [FATAL ERROR]: Cannot create segment from the `HalfEdge`! " )
531+ logger? . log ( " Fatal Error! Malformed Half-Edge! " , level: . critical)
532+ fatalError ( )
506533 }
507534
508535 let ( isOriginClipped, isDestinationClipped, segment) = lb_clip ( segmentToClip, clipper: clippingRect. toClipper ( ) )
@@ -679,10 +706,10 @@ extension Site {
679706
680707extension Vector2D {
681708 var normal : Vector2D {
682- return Vector2D ( dx: - dy, dy: dx)
709+ Vector2D ( dx: - dy, dy: dx)
683710 }
684711
685712 var point : Site {
686- return Site ( x: dx, y: dy)
713+ Site ( x: dx, y: dy)
687714 }
688715}
0 commit comments