Skip to content

Commit 85fb726

Browse files
committed
Use exact hashing and tolerant golden comparisons
1 parent b4ceb3a commit 85fb726

File tree

9 files changed

+258
-75
lines changed

9 files changed

+258
-75
lines changed

Sources/Cadova/Extensions/MiscExtensions.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ extension Double {
2121
var unitClamped: Double {
2222
clamped(to: 0...1)
2323
}
24-
25-
var roundedForHash: Int {
26-
Int((self * 1000000000.0).rounded())
27-
}
2824
}
2925

3026
extension Set {

Sources/Cadova/Node Layer/GeometryNode+Hashable.swift

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ extension GeometryNode.Contents: Equatable {
1515
case let (.materialized(k1), .materialized(k2)): k1 == k2
1616
case let (.shape2D(a), .shape2D(b)): a == b
1717
case let (.offset(a1, aa, aj, am, asc), .offset(a2, ba, bj, bm, bsc)):
18-
a1 == a2 && aa.roundedForHash == ba.roundedForHash && aj == bj && am.roundedForHash == bm.roundedForHash && asc == bsc
18+
a1 == a2 && aa == ba && aj == bj && am == bm && asc == bsc
1919
case let (.projection(a1, k1), .projection(a2, k2)): a1 == a2 && k1 == k2
2020
case let (.shape3D(a), .shape3D(b)): a == b
2121
case let (.applyMaterial(ba, aa), .applyMaterial(bb, ab)): ba == bb && aa == ab
2222
case let (.extrusion(a1, k1), .extrusion(a2, k2)): a1 == a2 && k1 == k2
2323
case let (.trim(a1, p1), .trim(a2, p2)): a1 == a2 && p1 == p2
2424
case let (.smoothOut(a1, minSharpAngleA, minSmoothnessA), .smoothOut(a2, minSharpAngleB, minSmoothnessB)):
2525
a1 == a2
26-
&& minSharpAngleA.roundedForHash == minSharpAngleB.roundedForHash
27-
&& minSmoothnessA.roundedForHash == minSmoothnessB.roundedForHash
26+
&& minSharpAngleA == minSharpAngleB
27+
&& minSmoothnessA == minSmoothnessB
2828

2929
default: false
3030
}
@@ -71,9 +71,9 @@ extension GeometryNode.Contents: Hashable {
7171
case .offset(let body, let amount, let joinStyle, let miterLimit, let segmentCount):
7272
hasher.combine(GeometryNode.Kind.offset)
7373
hasher.combine(body)
74-
hasher.combine(amount.roundedForHash)
74+
hasher.combine(amount)
7575
hasher.combine(joinStyle)
76-
hasher.combine(miterLimit.roundedForHash)
76+
hasher.combine(miterLimit)
7777
hasher.combine(segmentCount)
7878
case .projection(let body, let kind):
7979
hasher.combine(GeometryNode.Kind.projection)
@@ -97,8 +97,8 @@ extension GeometryNode.Contents: Hashable {
9797
case .smoothOut(let body, let minSharpAngle, let minSmoothness):
9898
hasher.combine(GeometryNode.Kind.smoothOut)
9999
hasher.combine(body)
100-
hasher.combine(minSharpAngle.roundedForHash)
101-
hasher.combine(minSmoothness.roundedForHash)
100+
hasher.combine(minSharpAngle)
101+
hasher.combine(minSmoothness)
102102
}
103103
}
104104
}
@@ -111,7 +111,7 @@ extension GeometryNode.Projection {
111111
static func == (lhs: Self, rhs: Self) -> Bool {
112112
switch (lhs, rhs) {
113113
case (.full, .full): true
114-
case let (.slice(a), .slice(b)): a.roundedForHash == b.roundedForHash
114+
case let (.slice(a), .slice(b)): a == b
115115

116116
case (.full, _), (.slice, _): false
117117
}
@@ -123,7 +123,7 @@ extension GeometryNode.Projection {
123123
hasher.combine(Kind.full)
124124
case .slice(let z):
125125
hasher.combine(Kind.slice)
126-
hasher.combine(z.roundedForHash)
126+
hasher.combine(z)
127127
}
128128
}
129129
}
@@ -136,7 +136,7 @@ extension GeometryNode.Extrusion {
136136
static func == (lhs: Self, rhs: Self) -> Bool {
137137
switch (lhs, rhs) {
138138
case let (.linear(h1, t1, d1, s1), .linear(h2, t2, d2, s2)):
139-
h1.roundedForHash == h2.roundedForHash && t1 == t2 && d1 == d2 && s1 == s2
139+
h1 == h2 && t1 == t2 && d1 == d2 && s1 == s2
140140
case let (.rotational(a1, s1), .rotational(a2, s2)):
141141
a1 == a2 && s1 == s2
142142

@@ -148,7 +148,7 @@ extension GeometryNode.Extrusion {
148148
switch self {
149149
case .linear(let height, let twist, let divisions, let scaleTop):
150150
hasher.combine(Kind.linear)
151-
hasher.combine(height.roundedForHash)
151+
hasher.combine(height)
152152
hasher.combine(twist)
153153
hasher.combine(divisions)
154154
hasher.combine(scaleTop)
@@ -172,7 +172,7 @@ extension GeometryNode.PrimitiveShape2D {
172172
hasher.combine(size)
173173
case .circle(let radius, let segments):
174174
hasher.combine(Kind.circle)
175-
hasher.combine(radius.roundedForHash)
175+
hasher.combine(radius)
176176
hasher.combine(segments)
177177
case .polygons(let list, let fillRule):
178178
hasher.combine(Kind.polygon)
@@ -187,7 +187,7 @@ extension GeometryNode.PrimitiveShape2D {
187187
static func == (lhs: Self, rhs: Self) -> Bool {
188188
switch (lhs, rhs) {
189189
case let (.rectangle(a), .rectangle(b)): a == b
190-
case let (.circle(ra, sa), .circle(rb, sb)): ra.roundedForHash == rb.roundedForHash && sa == sb
190+
case let (.circle(ra, sa), .circle(rb, sb)): ra == rb && sa == sb
191191
case let (.polygons(la, fa), .polygons(lb, fb)): la == lb && fa == fb
192192
case let (.convexHull(pa), .convexHull(pb)): pa == pb
193193

@@ -208,13 +208,13 @@ extension GeometryNode.PrimitiveShape3D {
208208
hasher.combine(size)
209209
case .sphere(let radius, let segmentCount):
210210
hasher.combine(Kind.sphere)
211-
hasher.combine(radius.roundedForHash)
211+
hasher.combine(radius)
212212
hasher.combine(segmentCount)
213213
case .cylinder(let bottomRadius, let topRadius, let height, let segmentCount):
214214
hasher.combine(Kind.cylinder)
215-
hasher.combine(bottomRadius.roundedForHash)
216-
hasher.combine(topRadius.roundedForHash)
217-
hasher.combine(height.roundedForHash)
215+
hasher.combine(bottomRadius)
216+
hasher.combine(topRadius)
217+
hasher.combine(height)
218218
hasher.combine(segmentCount)
219219
case .convexHull(let points):
220220
hasher.combine(Kind.convexHull)
@@ -228,9 +228,9 @@ extension GeometryNode.PrimitiveShape3D {
228228
static func == (lhs: Self, rhs: Self) -> Bool {
229229
switch (lhs, rhs) {
230230
case let (.box(a), .box(b)): a == b
231-
case let (.sphere(ra, sa), .sphere(rb, sb)): ra.roundedForHash == rb.roundedForHash && sa == sb
231+
case let (.sphere(ra, sa), .sphere(rb, sb)): ra == rb && sa == sb
232232
case let (.cylinder(ba, ta, ha, sa), .cylinder(bb, tb, hb, sb)):
233-
ba.roundedForHash == bb.roundedForHash && ta.roundedForHash == tb.roundedForHash && ha.roundedForHash == hb.roundedForHash && sa == sb
233+
ba == bb && ta == tb && ha == hb && sa == sb
234234
case let (.convexHull(pa), .convexHull(pb)): pa == pb
235235
case let (.mesh(ma), .mesh(mb)): ma == mb
236236

Sources/Cadova/Values/Angle/Angle.swift

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,3 @@ extension Angle: CustomDebugStringConvertible {
111111
String(format: "%g°", degrees)
112112
}
113113
}
114-
115-
extension Angle {
116-
public func hash(into hasher: inout Hasher) {
117-
hasher.combine(degrees.rounded())
118-
}
119-
120-
public static func ==(lhs: Self, rhs: Self) -> Bool {
121-
lhs.degrees.roundedForHash == rhs.degrees.roundedForHash
122-
}
123-
}
124-

Sources/Cadova/Values/Transforms/Transform.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,15 @@ public extension Transform {
7878
func hash(into hasher: inout Hasher) {
7979
for row in (0..<Self.size.rows) {
8080
for column in (0..<Self.size.columns) {
81-
hasher.combine(self[row, column].roundedForHash)
81+
hasher.combine(self[row, column])
8282
}
8383
}
8484
}
8585

8686
static func ==(_ lhs: Self, _ rhs: Self) -> Bool {
8787
for row in (0..<Self.size.rows) {
8888
for column in (0..<Self.size.columns) {
89-
if lhs[row, column].roundedForHash != rhs[row, column].roundedForHash {
89+
if lhs[row, column] != rhs[row, column] {
9090
return false
9191
}
9292
}

Sources/Cadova/Values/Vectors/Vector2D.swift

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,3 @@ extension Vector2D: CustomDebugStringConvertible {
196196
String(format: "[%g, %g]", x, y)
197197
}
198198
}
199-
200-
extension Vector2D {
201-
public func hash(into hasher: inout Hasher) {
202-
x.roundedForHash.hash(into: &hasher)
203-
y.roundedForHash.hash(into: &hasher)
204-
}
205-
206-
public static func ==(_ lhs: Vector2D, _ rhs: Vector2D) -> Bool {
207-
lhs.x.roundedForHash == rhs.x.roundedForHash &&
208-
lhs.y.roundedForHash == rhs.y.roundedForHash
209-
}
210-
}

Sources/Cadova/Values/Vectors/Vector3D.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -231,29 +231,3 @@ extension Vector3D: CustomDebugStringConvertible {
231231
String(format: "[%g, %g, %g]", x, y, z)
232232
}
233233
}
234-
235-
extension Vector3D {
236-
/// Hashes the vector using rounded values for stability.
237-
///
238-
/// - Parameter hasher: The hasher to use when combining the components.
239-
///
240-
public func hash(into hasher: inout Hasher) {
241-
x.roundedForHash.hash(into: &hasher)
242-
y.roundedForHash.hash(into: &hasher)
243-
z.roundedForHash.hash(into: &hasher)
244-
}
245-
246-
/// Compares two vectors using rounded values to allow tolerance.
247-
///
248-
/// - Parameters:
249-
/// - lhs: The left-hand side vector.
250-
/// - rhs: The right-hand side vector.
251-
///
252-
/// - Returns: `true` if the vectors are equal within the rounding tolerance.
253-
///
254-
public static func ==(_ lhs: Vector3D, _ rhs: Vector3D) -> Bool {
255-
lhs.x.roundedForHash == rhs.x.roundedForHash &&
256-
lhs.y.roundedForHash == rhs.y.roundedForHash &&
257-
lhs.z.roundedForHash == rhs.z.roundedForHash
258-
}
259-
}

0 commit comments

Comments
 (0)