Skip to content

Commit 11b13d9

Browse files
author
Oleksandr Glagoliev
committed
Fix some corner case bugs
1 parent 13ace78 commit 11b13d9

File tree

7 files changed

+70
-44
lines changed

7 files changed

+70
-44
lines changed

Demo/Demo/EdgeCases.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import Foundation
1010

1111
var edgeCases = [
12+
broken0,
1213
broken,
1314
testSites_3,
1415
testSites_4,
@@ -106,3 +107,11 @@ let broken = Set<Site>(
106107
Site(x: 166.0, y: 153.0),
107108
]
108109
)
110+
111+
let broken0 = Set<Site>(
112+
[
113+
Site(x: 241.0, y: 293.0),
114+
Site(x: 166.0, y: 192.0),
115+
]
116+
)
117+

Demo/Demo/UIBezierPath+RoundedCorners.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ extension UIBezierPath {
6060
let dy = p.y * 2 - c1.y - c2.y
6161

6262
let p_c = (dx.sqr + dy.sqr).squareRoot()
63-
6463
// Find Circle origin
6564
let o = CGPoint(
6665
x: p.x - dx * p_o / p_c,
@@ -72,13 +71,21 @@ extension UIBezierPath {
7271
let endAngle = (atan2((c2.y - o.y), (c2.x - o.x))).positiveAngle
7372

7473

75-
if isStart {
76-
path.move(to: c1)
74+
75+
if !radius.isNaN && !o.x.isNaN && !o.y.isNaN {
76+
if isStart {
77+
path.move(to: c1)
78+
} else {
79+
path.addLine(to: c1)
80+
}
81+
path.addArc(withCenter: o, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: angle < .pi)
7782
} else {
78-
path.addLine(to: c1)
83+
if isStart {
84+
path.move(to: p)
85+
} else {
86+
path.addLine(to: p)
87+
}
7988
}
80-
81-
path.addArc(withCenter: o, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: angle < .pi)
8289
}
8390

8491
public static func roundedCornersPath(_ pts: [CGPoint], _ r: CGFloat) -> UIBezierPath? {

Demo/Demo/VoronoiView.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ class VoronoiView: UIView {
6767
// numberOfAxis: 1
6868
// )
6969
// )
70+
71+
7072
// if axipoints.count > 4 {
7173
// axipoints = Array<Site>(axipoints.dropFirst(axipoints.count - 5))
7274
// }
7375

7476

75-
// drawRandomSites(100)
77+
// drawRandomSites(200)
7678

7779
drawNextEdgeCase()
7880
}
@@ -87,7 +89,7 @@ class VoronoiView: UIView {
8789
for i in 0..<numberOfAxis {
8890
// Dirty hack to prevent points to share coordinate
8991
// Otherwise it may produce glitches
90-
let wiggle = CGFloat(CGFloat.random(in: 0..<10) * 0.2)
92+
let wiggle = CGFloat.zero//CGFloat(CGFloat.random(in: 0..<10) * 0.002)
9193

9294
let theta = CGFloat(
9395
atan2(seedPoint.y - center.y, seedPoint.x - center.x)
@@ -161,7 +163,7 @@ class VoronoiView: UIView {
161163
var he = cell.outerComponent
162164

163165
var finish = false
164-
while !finish {
166+
while !finish {
165167

166168
if he!.toSegment()!.length() < 1.0 {
167169
he = he?.next

Sources/FortunesAlgorithm/Event.swift

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,6 @@ extension Event: Comparable {
3030
}
3131

3232
static func < (lhs: Event, rhs: Event) -> Bool {
33-
if lhs.point == rhs.point {
34-
35-
guard
36-
let lp = lhs.arc?.point,
37-
let rp = rhs.arc?.point else {
38-
return true
39-
}
40-
41-
if lp.y == rp.y {
42-
return lp.x < rp.x
43-
}
44-
return lp.y < rp.y
45-
}
4633
if lhs.point.y == rhs.point.y {
4734
return lhs.point.x < rhs.point.x
4835
}

Sources/FortunesAlgorithm/FortuneSweep.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ public class FortuneSweep {
7979
if beachline.isEmpty {
8080
let root = beachline.insertRootArc(point: event.point)
8181
firstSiteY = event.point.y
82-
container = clipper
82+
83+
let padding: Double = 20
84+
container = .rect(from: clipper, with: padding)
85+
// container = clipper
8386

8487
/// Create new **Cell** record in **Voronoi Diagram**
8588
container.expandToContainPoint(event.point)
@@ -96,7 +99,7 @@ public class FortuneSweep {
9699
/// We replace *y* with an arbitrary value big enough to cover our case. (`yVal`)
97100
if firstSiteY == sweepLineY {
98101
container.expandToContainPoint(event.point)
99-
let yVal: Double = .leastNormalMagnitude
102+
let yVal: Double = -1000000//.leastNormalMagnitude
100103
let arc = beachline.handleSpecialArcInsertionCase(event.point)
101104

102105
/// 1. Create new **Cell** record in **Voronoi Diagram**
@@ -397,8 +400,8 @@ public class FortuneSweep {
397400

398401
let clipper = container!.toClipper()
399402

400-
last.destination = lb_clip(last.toSegment()!, clipper: clipper).resultSegment!.b
401-
first.origin = lb_clip(first.toSegment()!, clipper: clipper).resultSegment!.a
403+
last.destination = lb_clip(last.toSegment()!, clipper: clipper).resultSegment?.b
404+
first.origin = lb_clip(first.toSegment()!, clipper: clipper).resultSegment?.a
402405

403406
guard let start = last.destination, let end = first.origin else {
404407
return

Sources/FortunesAlgorithm/Geometry/Rectangle.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ extension Rectangle {
9393
getLine(.bottom)
9494
]
9595
}
96+
97+
public static func rect(from sourceRect: Rectangle, with padding: Double) -> Rectangle {
98+
Rectangle(
99+
origin: Site(x: sourceRect.tl.x - padding, y: sourceRect.tl.y - padding),
100+
size: Size(width: sourceRect.width + 2 * padding, height: sourceRect.height + 2 * padding)
101+
)
102+
}
96103
}
97104

98105

SpriteKitDemo/SpriteKitDemo/GameScene.swift

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class GameScene: SKScene {
2727
// removeAllChildren()
2828
let totalPath = UIBezierPath()
2929

30-
DispatchQueue.global(qos: .userInteractive).async { [unowned self] in
30+
// DispatchQueue.global(qos: .userInteractive).async { [unowned self] in
3131
self.diagram.clear()
3232
self.fs.compute(
3333
sites: sites,
@@ -42,11 +42,11 @@ class GameScene: SKScene {
4242
var finish = false
4343
while !finish {
4444

45-
if he!.toSegment()!.length() < 1.0 {
46-
he = he?.next
47-
finish = he === cell.outerComponent
48-
continue
49-
}
45+
// if he!.toSegment()!.length() < 1.0 {
46+
// he = he?.next
47+
// finish = he === cell.outerComponent
48+
// continue
49+
// }
5050

5151
let o = he!.origin!
5252
points.append(o)
@@ -56,21 +56,30 @@ class GameScene: SKScene {
5656
finish = he === cell.outerComponent
5757
}
5858

59+
// let hullVertices = points.map { $0.cgPoint }
60+
// for i in 0..<hullVertices.count {
61+
// if i == 0 {
62+
// totalPath.move(to: hullVertices[i])
63+
// } else { totalPath.addLine(to: hullVertices[i])}
64+
// }
65+
// totalPath.close()
66+
5967
let hullVertices = points.map { $0.cgPoint }
60-
for i in 0..<hullVertices.count {
61-
if i == 0 {
62-
totalPath.move(to: hullVertices[i])
63-
} else { totalPath.addLine(to: hullVertices[i])}
68+
69+
for i in 0..<1 {
70+
let paddedHull = paddedPolygon(hullVertices, padding: CGFloat(-i) * 10)
71+
if let path = UIBezierPath.roundedCornersPath(paddedHull, 10) {
72+
totalPath.append(path)
73+
}
6474
}
65-
totalPath.close()
6675
}
6776

68-
DispatchQueue.main.async {
77+
// DispatchQueue.main.async {
6978
self.diagramNode.path = totalPath.cgPath
7079
self.diagramNode.strokeColor = UIColor.black
7180
self.diagramNode.fillColor = .clear
72-
}
73-
}
81+
// }
82+
// }
7483
}
7584

7685
override func didMove(to view: SKView) {
@@ -128,17 +137,18 @@ class GameScene: SKScene {
128137

129138

130139
var hexLike: [Site] {
131-
var num = 5
140+
let num = 5
132141
let step: Double = 50
133142
var res = [Site]()
134143
for i in 0..<num {
135-
for j in 0..<num {
144+
for j in 0..<3 {
136145
res.append(
137146
Site(
138147
x:Double(i) * step + Double(j) * step / 2 + 200,
139148
y:Double(j) * step + 200
140149
)
141150
)
151+
print(res.last!)
142152
}
143153
}
144154
return res
@@ -150,8 +160,9 @@ class GameScene: SKScene {
150160
func touchMoved(toPoint pos : CGPoint) {
151161
let spriteAtPoint = atPoint(pos)
152162
if spriteAtPoint != diagramNode {
153-
atPoint(pos).position = pos
163+
atPoint(pos).position = CGPoint(x: pos.x.rounded(), y: pos.y.rounded())
154164
}
165+
redraw(Set<Site>(balls.map { $0.position.point }))
155166
}
156167

157168
func touchUp(atPoint pos : CGPoint) {
@@ -179,7 +190,7 @@ class GameScene: SKScene {
179190
}
180191

181192
override func update(_ currentTime: TimeInterval) {
182-
redraw(Set<Site>(balls.map { $0.position.point }))
193+
// redraw(Set<Site>(balls.map { $0.position.point }))
183194
}
184195
}
185196

0 commit comments

Comments
 (0)