Merge pull request #176 from bcvery1/master
Avoiding floating point rounding errors
This commit is contained in:
commit
2cb87efb8c
29
geometry.go
29
geometry.go
|
@ -49,6 +49,33 @@ func V(x, y float64) Vec {
|
||||||
return Vec{x, y}
|
return Vec{x, y}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nearlyEqual compares two float64s and returns whether they are equal, accounting for rounding errors.At worst, the
|
||||||
|
// result is correct to 7 significant digits.
|
||||||
|
func nearlyEqual(a, b float64) bool {
|
||||||
|
epsilon := 0.000001
|
||||||
|
|
||||||
|
if a == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := math.Abs(a - b)
|
||||||
|
|
||||||
|
if a == 0.0 || b == 0.0 || diff < math.SmallestNonzeroFloat64 {
|
||||||
|
return diff < (epsilon * math.SmallestNonzeroFloat64)
|
||||||
|
}
|
||||||
|
|
||||||
|
absA := math.Abs(a)
|
||||||
|
absB := math.Abs(b)
|
||||||
|
|
||||||
|
return diff/math.Min(absA+absB, math.MaxFloat64) < epsilon
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eq will compare two vectors and return whether they are equal accounting for rounding errors. At worst, the result
|
||||||
|
// is correct to 7 significant digits.
|
||||||
|
func (u Vec) Eq(v Vec) bool {
|
||||||
|
return nearlyEqual(u.X, v.X) && nearlyEqual(u.Y, v.Y)
|
||||||
|
}
|
||||||
|
|
||||||
// Unit returns a vector of length 1 facing the given angle.
|
// Unit returns a vector of length 1 facing the given angle.
|
||||||
func Unit(angle float64) Vec {
|
func Unit(angle float64) Vec {
|
||||||
return Vec{1, 0}.Rotated(angle)
|
return Vec{1, 0}.Rotated(angle)
|
||||||
|
@ -275,7 +302,7 @@ func (l Line) Closest(v Vec) Vec {
|
||||||
|
|
||||||
// Contains returns whether the provided Vec lies on the line.
|
// Contains returns whether the provided Vec lies on the line.
|
||||||
func (l Line) Contains(v Vec) bool {
|
func (l Line) Contains(v Vec) bool {
|
||||||
return l.Closest(v) == v
|
return l.Closest(v).Eq(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formula will return the values that represent the line in the formula: y = mx + b
|
// Formula will return the values that represent the line in the formula: y = mx + b
|
||||||
|
|
|
@ -1181,6 +1181,19 @@ func TestLine_Intersect(t *testing.T) {
|
||||||
args: args{k: pixel.L(pixel.V(0, 1), pixel.V(10, 11))},
|
args: args{k: pixel.L(pixel.V(0, 1), pixel.V(10, 11))},
|
||||||
want: pixel.ZV,
|
want: pixel.ZV,
|
||||||
want1: false,
|
want1: false,
|
||||||
|
}, {
|
||||||
|
name: "Lines intersect",
|
||||||
|
fields: fields{A: pixel.V(600, 600), B: pixel.V(925, 150)},
|
||||||
|
args: args{k: pixel.L(pixel.V(740, 255), pixel.V(925, 255))},
|
||||||
|
want: pixel.V(849.1666666666666, 255),
|
||||||
|
want1: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Lines intersect",
|
||||||
|
fields: fields{A: pixel.V(600, 600), B: pixel.V(925, 150)},
|
||||||
|
args: args{k: pixel.L(pixel.V(740, 255), pixel.V(925, 255.0001))},
|
||||||
|
want: pixel.V(849.1666240490657, 255.000059008986),
|
||||||
|
want1: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
Loading…
Reference in New Issue