Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ cover.out
.idea.cover
.cover
.idea/
output.txt
30 changes: 2 additions & 28 deletions bbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,40 +260,14 @@ func (e *Extent) Contains(ne MinMaxer) bool {
e.MaxY() >= ne.MaxY()
}

// Float64 compares two floats to see if they are within the given tolerance.
func cmpFloat64(f1, f2, tolerance float64) bool {
if math.IsInf(f1, 1) {
return math.IsInf(f2, 1)
}
if math.IsInf(f2, 1) {
return math.IsInf(f1, 1)
}
if math.IsInf(f1, -1) {
return math.IsInf(f2, -1)
}
if math.IsInf(f2, -1) {
return math.IsInf(f1, -1)
}
diff := math.Abs(f1 - f2)
return diff <= tolerance
}

func floatLessOrEqual(pt1, pt2 float64) bool {
if cmpFloat64(pt1, pt2, 0.001) {
return true
}
return pt1 < pt2
}

// ContainsPoint will return whether the given point is inside of the extent.
func (e *Extent) ContainsPoint(pt [2]float64) bool {
if e == nil {
return true
}

return floatLessOrEqual(e.MinX(), pt[0]) && floatLessOrEqual(pt[0], e.MaxX()) &&
floatLessOrEqual(e.MinY(), pt[1]) && floatLessOrEqual(pt[1], e.MaxY())

return e.MinX() <= pt[0] && pt[0] <= e.MaxX() &&
e.MinY() <= pt[1] && pt[1] <= e.MaxY()
}

// ContainsLine will return weather the given line completely inside of the extent.
Expand Down
57 changes: 31 additions & 26 deletions circle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,50 @@ import (
"testing"

"github.com/go-spatial/geom"
"github.com/go-spatial/geom/cmp"
)

const tolerance = geom.Tolerance
const bitTolerance = geom.BitTolerance
cmppkg "github.com/go-spatial/geom/cmp"
)

func TestCircleFromPoints(t *testing.T) {
type tcase struct {
p [3][2]float64
circle geom.Circle
err error
cmp *cmppkg.Compare
}
fn := func(t *testing.T, tc tcase) {
circle, err := geom.CircleFromPoints(tc.p[0], tc.p[1], tc.p[2])
if (tc.err != nil && err == nil) || (tc.err == nil && err != nil) {
t.Errorf("error, expected %v got %v", tc.err, err)
return
fn := func(tc tcase) func(*testing.T) {
cmp := cmppkg.DefaultCompare()
if tc.cmp != nil {
cmp = *tc.cmp
}
if tc.err != nil {
if tc.err != err {
return func(t *testing.T) {

circle, err := geom.CircleFromPoints(tc.p[0], tc.p[1], tc.p[2])
if (tc.err != nil && err == nil) || (tc.err == nil && err != nil) {
t.Errorf("error, expected %v got %v", tc.err, err)
return
}
if tc.err != nil {
if tc.err != err {
t.Errorf("error, expected %v got %v", tc.err, err)
}
return
}
return
}

if !cmp.Float64(circle.Radius, tc.circle.Radius, tolerance, bitTolerance) {
t.Errorf("circle radius, expected %v got %v", tc.circle, circle)
return
}
if !cmp.Float(circle.Radius, tc.circle.Radius) {
t.Errorf("circle radius, expected %v got %v", tc.circle, circle)
return
}

if !cmp.Float64(circle.Center[0], tc.circle.Center[0], tolerance, bitTolerance) {
t.Errorf("circle x, expected %v got %v", tc.circle, circle)
return
}
if !cmp.Float(circle.Center[0], tc.circle.Center[0]) {
t.Errorf("circle x, expected %v got %v", tc.circle, circle)
return
}

if !cmp.Float64(circle.Center[1], tc.circle.Center[1], tolerance, bitTolerance) {
t.Errorf("circle y, expected %v got %v", tc.circle, circle)
return
if !cmp.Float(circle.Center[1], tc.circle.Center[1]) {
t.Errorf("circle y, expected %v got %v", tc.circle, circle)
return
}
}
}

Expand Down Expand Up @@ -72,7 +78,6 @@ func TestCircleFromPoints(t *testing.T) {
},
}
for name, tc := range tests {
tc := tc
t.Run(name, func(t *testing.T) { fn(t, tc) })
t.Run(name, fn(tc))
}
}
4 changes: 2 additions & 2 deletions cmp/cmp.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ func BitToleranceFor(tol float64) int64 {
// These are here for compability reasons

// Tolerance is only here for compability reasons
var Tolerance = compare.Tolerance
var Tolerance = DefaultCompare().Tolerance

// BitTolerance is only here for compability reasons
var BitTolerance = compare.BitTolerance
var BitTolerance = DefaultCompare().BitTolerance

// Float64Slice compares two sets of float64 slices within the given tolerance.
func Float64Slice(f1, f2 []float64, tolerance float64, bitTolerance int64) bool {
Expand Down
75 changes: 48 additions & 27 deletions cmp/default_compare.go
Original file line number Diff line number Diff line change
@@ -1,95 +1,116 @@
package cmp

import (
"sync/atomic"

"github.com/go-spatial/geom"
)

// HiPrecision is a high precision for comparator
const HiPrecision = 0.000000001

// HiCMP is a high precision comparator
var HiCMP = New(HiPrecision)

// compare will have six digits of precision by default.
// This is equivalent to :
// var compare = NewForNumPrecision(6)
var compare = Compare{
Tolerance: 0.000001,
// It was calculated as math.Float64bits(1.000001) - math.Float64bits(1.0)
BitTolerance: 4503599627,
var compare = func() (av atomic.Value) {
av.Store(NewForNumPrecision(6))
return av
}()

// DefaultCompare returns the current default compare
func DefaultCompare() Compare {
return compare.Load().(Compare)
}

// SetDefault will set the default for the package.
func SetDefault(cmp Compare) Compare {
old := compare.Load().(Compare)
compare.Store(cmp)
return old
}

// Tolerances returns the default tolerance values
func Tolerances() (float64, int64) { return compare.Tolerances() }
func Tolerances() (float64, int64) { return DefaultCompare().Tolerances() }

// Float compares two floats to see if they are within 0.00001 from each other. This is the best way to compare floats.
func Float(f1, f2 float64) bool { return compare.Float(f1, f2) }
func Float(f1, f2 float64) bool { return DefaultCompare().Float(f1, f2) }

// FloatSlice compare two sets of float slices.
func FloatSlice(f1, f2 []float64) bool { return compare.FloatSlice(f1, f2) }
func FloatSlice(f1, f2 []float64) bool { return DefaultCompare().FloatSlice(f1, f2) }

// Extent will check to see if the Extents's are the same.
func Extent(extent1, extent2 [4]float64) bool { return compare.Extent(extent1, extent2) }
func Extent(extent1, extent2 [4]float64) bool { return DefaultCompare().Extent(extent1, extent2) }

// GeomExtent will check to see if geom.BoundingBox's are the same.
func GeomExtent(extent1, extent2 geom.Extenter) bool { return compare.GeomExtent(extent1, extent2) }
func GeomExtent(extent1, extent2 geom.Extenter) bool {
return DefaultCompare().GeomExtent(extent1, extent2)
}

// PointLess returns weather p1 is < p2 by first comparing the X values, and if they are the same the Y values.
func PointLess(p1, p2 [2]float64) bool { return compare.PointLess(p1, p2) }
func PointLess(p1, p2 [2]float64) bool { return DefaultCompare().PointLess(p1, p2) }

// PointEqual returns weather both points have the same value for x,y.
func PointEqual(p1, p2 [2]float64) bool { return compare.PointEqual(p1, p2) }
func PointEqual(p1, p2 [2]float64) bool { return DefaultCompare().PointEqual(p1, p2) }

// GeomPointEqual returns weather both points have the same value for x,y.
func GeomPointEqual(p1, p2 geom.Point) bool { return compare.GeomPointEqual(p1, p2) }
func GeomPointEqual(p1, p2 geom.Point) bool { return DefaultCompare().GeomPointEqual(p1, p2) }

// MultiPointEqual will check to see see if the given slices are the same.
func MultiPointEqual(p1, p2 [][2]float64) bool { return compare.MultiPointEqual(p1, p2) }
func MultiPointEqual(p1, p2 [][2]float64) bool { return DefaultCompare().MultiPointEqual(p1, p2) }

// LineStringEqual given two LineStrings it will check to see if the line
// strings have the same points in the same order.
func LineStringEqual(v1, v2 [][2]float64) bool { return compare.LineStringEqual(v1, v2) }
func LineStringEqual(v1, v2 [][2]float64) bool { return DefaultCompare().LineStringEqual(v1, v2) }

// MultiLineEqual will return if the two multilines are equal.
func MultiLineEqual(ml1, ml2 [][][2]float64) bool { return compare.MultiLineEqual(ml1, ml2) }
func MultiLineEqual(ml1, ml2 [][][2]float64) bool { return DefaultCompare().MultiLineEqual(ml1, ml2) }

// PolygonEqual will return weather the two polygons are the same.
func PolygonEqual(ply1, ply2 [][][2]float64) bool { return compare.PolygonEqual(ply1, ply2) }
func PolygonEqual(ply1, ply2 [][][2]float64) bool { return DefaultCompare().PolygonEqual(ply1, ply2) }

// PointerEqual will check to see if the x and y of both points are the same.
func PointerEqual(geo1, geo2 geom.Pointer) bool { return compare.PointerEqual(geo1, geo2) }
func PointerEqual(geo1, geo2 geom.Pointer) bool { return DefaultCompare().PointerEqual(geo1, geo2) }

// PointerLess returns weather p1 is < p2 by first comparing the X values, and if they are the same the Y values.
func PointerLess(p1, p2 geom.Pointer) bool { return compare.PointLess(p1.XY(), p2.XY()) }
func PointerLess(p1, p2 geom.Pointer) bool { return DefaultCompare().PointLess(p1.XY(), p2.XY()) }

// MultiPointerEqual will check to see if the provided multipoints have the same points.
func MultiPointerEqual(geo1, geo2 geom.MultiPointer) bool {
return compare.MultiPointerEqual(geo1, geo2)
return DefaultCompare().MultiPointerEqual(geo1, geo2)
}

// LineStringerEqual will check to see if the two linestrings passed to it are equal, if
// there lengths are both the same, and the sequence of points are in the same order.
// The points don't have to be in the same index point in both line strings.
func LineStringerEqual(geo1, geo2 geom.LineStringer) bool {
return compare.LineStringerEqual(geo1, geo2)
return DefaultCompare().LineStringerEqual(geo1, geo2)
}

// MultiLineStringerEqual will check to see if the 2 MultiLineStrings pass to it
// are equal. This is done by converting them to lineStrings and using MultiLineEqual
func MultiLineStringerEqual(geo1, geo2 geom.MultiLineStringer) bool {
return compare.MultiLineStringerEqual(geo1, geo2)
return DefaultCompare().MultiLineStringerEqual(geo1, geo2)
}

// PolygonerEqual will check to see if the Polygoners are the same, by checking
// if the linearRings are equal.
func PolygonerEqual(geo1, geo2 geom.Polygoner) bool { return compare.PolygonerEqual(geo1, geo2) }
func PolygonerEqual(geo1, geo2 geom.Polygoner) bool {
return DefaultCompare().PolygonerEqual(geo1, geo2)
}

// MultiPolygonerEqual will check to see if the given multipolygoners are the same, by check each of the constitute
// polygons to see if they match.
func MultiPolygonerEqual(geo1, geo2 geom.MultiPolygoner) bool {
return compare.MultiPolygonerEqual(geo1, geo2)
return DefaultCompare().MultiPolygonerEqual(geo1, geo2)
}

// CollectionerEqual will check if the two collections are equal based on length
// then if each geometry inside is equal. Therefor order matters.
func CollectionerEqual(col1, col2 geom.Collectioner) bool {
return compare.CollectionerEqual(col1, col2)
return DefaultCompare().CollectionerEqual(col1, col2)
}

// GeometryEqual checks if the two geometries are of the same type and then
// calls the type method to check if they are equal
func GeometryEqual(g1, g2 geom.Geometry) bool { return compare.GeometryEqual(g1, g2) }
func GeometryEqual(g1, g2 geom.Geometry) bool { return DefaultCompare().GeometryEqual(g1, g2) }
Loading