spatial/{barneshut,vptree}: refuse points at infinity
MODIFY
spatial/barneshut/barneshut2.go
spatial/barneshut/barneshut2.go
@@ -47,12 +47,23 @@ type Plane struct {
}
// NewPlane returns a new Plane.
+//
+// Points in p must not be infinitely distant, otherwise NewPlane will panic.
func NewPlane(p []Particle2) *Plane {
+ for _, l := range p {
+ if isInfR2(l.Coord2()) {
+ panic("barneshut: point at infinity")
+ }
+ }
q := Plane{Particles: p}
q.Reset()
return &q
}
+func isInfR2(v r2.Vec) bool {
+ return math.IsInf(v.X, 0) || math.IsInf(v.Y, 0)
+}
+
// Reset reconstructs the Barnes-Hut tree. Reset must be called if the
// Particles field or elements of Particles have been altered, unless
// ForceOn is called with theta=0 or no data structures have been

MODIFY
spatial/barneshut/barneshut3.go
spatial/barneshut/barneshut3.go
@@ -47,12 +47,23 @@ type Volume struct {
}
// NewVolume returns a new Volume.
+//
+// Points in p must not be infinitely distant, otherwise NewVolume will panic.
func NewVolume(p []Particle3) *Volume {
+ for _, l := range p {
+ if isInfR3(l.Coord3()) {
+ panic("barneshut: point at infinity")
+ }
+ }
q := Volume{Particles: p}
q.Reset()
return &q
}
+func isInfR3(v r3.Vec) bool {
+ return math.IsInf(v.X, 0) || math.IsInf(v.Y, 0) || math.IsInf(v.Z, 0)
+}
+
// Reset reconstructs the Barnes-Hut tree. Reset must be called if the
// Particles field or elements of Particles have been altered, unless
// ForceOn is called with theta=0 or no data structures have been

MODIFY
spatial/vptree/vptree.go
spatial/vptree/vptree.go
@@ -64,6 +64,8 @@ type Tree struct {
// The order of elements in p will be altered after New returns. The src parameter
// provides the source of randomness for vantage point selection. If src is nil
// global rand package functions are used.
+//
+// Points in p must not be infinitely distant, otherwise New will panic.
func New(p []Comparable, effort int, src rand.Source) *Tree {
var intn func(int) int
var shuf func(n int, swap func(i, j int))
@@ -118,13 +120,21 @@ func (b *builder) selectVantage(s []Comparable, effort int) Comparable {
choices := b.random(effort, s)
for _, p := range choices {
for i, q := range choices {
- b.work[i] = p.Distance(q)
+ d := p.Distance(q)
+ if math.IsInf(d, 0) {
+ panic("vptree: point at infinity")
+ }
+ b.work[i] = d
}
variance := stat.Variance(b.work, nil)
if variance > bestVar {
best, bestVar = p, variance
}
}
+ if best == nil {
+ // This should never be reached.
+ panic("vptree: could not find vantage point")
+ }
return best
}
@@ -139,7 +149,11 @@ func (b *builder) random(n int, s []Comparable) []Comparable {
func (b *builder) partition(v Comparable, s []Comparable) (radius float64, closer, further []Comparable) {
b.work = b.work[:len(s)]
for i, p := range s {
- b.work[i] = v.Distance(p)
+ d := v.Distance(p)
+ if math.IsInf(d, 0) {
+ panic("vptree: point at infinity")
+ }
+ b.work[i] = d
}
sort.Sort(byDist{dists: b.work, points: s})

spatial/{barneshut,vptree}: refuse points at infinity