func (t *Table) Remove(s gfx.Spatial) { sb := s.Bounds() // Remove minimum. i := t.Index(sb.Min) for ki, k := range t.Data[i] { if k == s { t.Data[i] = append(t.Data[i][ki:], t.Data[i][ki+1:]...) } } // Remove center. i = t.Index(sb.Center()) for ki, k := range t.Data[i] { if k == s { t.Data[i] = append(t.Data[i][ki:], t.Data[i][ki+1:]...) } } // Remove maximum. i = t.Index(sb.Max) for ki, k := range t.Data[i] { if k == s { t.Data[i] = append(t.Data[i][ki:], t.Data[i][ki+1:]...) } } return }
// Remove tries to remove the given spatial from the N tree. // // It should be explicitly noted that it is only possible to remove a spatial // if Bounds() returns the same identical bounds as when it was added, this is // for efficiency reasons. Clients wishing to not have to keep track can just // use a map of spatials to their gfx.Bounds of when they where added to the N // tree. // // This method returns true if the spatial was removed or false if it could not // be located in the tree due to: // 1. The spatial's bounds having changed since the last time it was added. // 2. The spatial having already been removed. func (t *Tree) Remove(s gfx.Spatial) bool { if t.Root == nil { return false } sb := s.Bounds() found := t.Root.find(sb) if found == nil { goto outside } for i, o := range found.Objects { if o == s { found.Objects = append(found.Objects[:i], found.Objects[i+1:]...) t.count-- return true } } outside: for i, o := range t.outside { if o == s { t.outside = append(t.outside[:i], t.outside[i+1:]...) t.count-- return true } } return false }
// findLeaf finds the leaf node containing obj. func (t *Tree) findLeaf(n *node, obj gfx.Spatial) *node { if n.leaf { return n } // if not leaf, search all candidate subtrees objBounds := obj.Bounds() for _, e := range n.entries { fmt.Printf("\nin %p\n", n, objBounds.In(e.bounds)) fmt.Println("objBounds", objBounds) fmt.Println("e.bounds", e.bounds) if objBounds.In(e.bounds) { leaf := t.findLeaf(e.child, obj) if leaf == nil { continue } // check if the leaf actually contains the object for _, leafEntry := range leaf.entries { if leafEntry.obj == obj { return leaf } } } } return nil }
// Add adds the spatial to the tree. func (t *Tree) Add(s gfx.Spatial) { t.count++ sb := s.Bounds() if sb.Empty() { panic("Tree.Add(): cannot add empty spatial") } if t.root == nil { t.root = &Node{ parent: t.root, bounds: sb, Objects: []gfx.Spatial{s}, } return } n := t.root.findNode(sb) if n != nil { n.place(sb, s) return } t.root.place(sb, s) t.root.sanitizeBounds() return }
// Insert inserts the given spatial object into the tree. func (t *Tree) Insert(s gfx.Spatial) { t.size++ e := entry{ bounds: s.Bounds(), obj: s, } t.insert(e, 1) }
// Insert inserts the given entry into the tree, splitting the tree as needed. func (t *Tree) Insert(e gfx.Spatial) { var l, ll *Node // Select a leaf node, l, in which to place the entry, e. eBounds := e.Bounds() l = t.Root.ChooseLeaf(eBounds) // Add the entry to the leaf node. If L has room for another entry, install // it. Otherwise invoke SplitNode to obtain L and LL containing E and all // of the old entries of L. if len(l.Entries) < t.Max { // We have room to store the entry. l.Entries = append(l.Entries, &Node{ Parent: l, Bounds: eBounds, Height: t.Root.Height, Object: e, }) } else { // We must split the node. l, ll = l.SplitNode() } // Propagate the changes to the tree upward. Invoke AdjustTree on L, also // passing LL if a split was performed. // XXX: AdjustTree must check if ll != nil to see if a split was performed. root, splitRoot := t.AdjustTree(l, ll) if splitRoot != nil { // Grow the tree taller. If node split propagation caused the root to // split then create a new root whose children are the two resulting // nodes. oldRoot := root t.Root.Height++ t.Root = &Node{ Parent: nil, // XXX: It's the root but is nil okay? Height: t.Root.Height, } t.Root.Entries = []*Node{ &Node{ Parent: t.Root, Bounds: splitRoot.calcBounds(), Height: t.Root.Height, }, &Node{ Parent: t.Root, Bounds: oldRoot.calcBounds(), Height: t.Root.Height, }, } t.Root.Bounds = t.Root.calcBounds() } }
// Add adds the given spatial to the N tree. func (t *Tree) Add(s gfx.Spatial) { t.count++ sb := s.Bounds() if t.Root == nil { size := sb.Size() if size.Y > size.X { size.X = size.X size.Y = size.X size.Z = size.X } if size.Z > size.X { size.X = size.X size.Y = size.X size.Z = size.X } s := t.startScale t.Root = &Node{ bounds: math.Rect3{ Min: sb.Min.MulScalar(s), Max: sb.Min.Add(size).MulScalar(s), }, } } for !sb.In(t.Root.bounds) { rootBounds := t.Root.bounds rootSize := rootBounds.Size() if t.Root.Level < -t.maxExpand { break } expanded := &Node{ Level: t.Root.Level - 1, bounds: math.Rect3{ Min: rootBounds.Min.Sub(rootSize), Max: rootBounds.Max.Add(rootSize), }, Children: []*Node{t.Root}, } t.Root = expanded } // Create a path of nodes, subdividings as needed to insert the object into // the tree. p := t.Root.createPath(t.divisor, t.maxDepth, sb) if p == nil { // Doesn't fit in the tree. t.outside = append(t.outside, s) return } p.Objects = append(p.Objects, s) }
func (t *Table) Add(s gfx.Spatial) { sb := s.Bounds() // Add minimum. i := t.Index(sb.Min) t.Data[i] = append(t.Data[i], s) // Add center. i = t.Index(sb.Center()) t.Data[i] = append(t.Data[i], s) // Add maximum. i = t.Index(sb.Max) t.Data[i] = append(t.Data[i], s) }
func (o *Octant) add(b gfx.Spatial, maxDepth int) { if o.Depth+1 <= maxDepth { bounds := b.Bounds() childIndex := o.childFits(bounds) fmt.Println("\n\nChild fits") fmt.Println("Boundable:", b) fmt.Println("Child:", childIndex, o.childBounds(childIndex)) if childIndex != -1 { child := &Octant{ Bounds: o.childBounds(childIndex), Depth: o.Depth + 1, } o.Children[childIndex] = child child.add(b, maxDepth) return } } o.Objects = append(o.Objects, b) fmt.Printf("add %v %p\n", b, o) return }
func (s *Shash) Add(sp gfx.Spatial) { // Find the distance from the center of the spatial's bounding box to the // center of the world. b := sp.Bounds() dist := b.Center().Sub(math.Vec3Zero) s.AvgLengthSq += dist.LengthSq() s.AvgLengthSq /= 2.0 // Find the angle between the spatial's position in space relative to the // center of the world. angle, _ := dist.Normalized() // Computer the start and end indices. start := s.AngleIndex(angle) end := s.AngleIndex(angle) distStart := s.DistIndex(b.Min) distEnd := s.DistIndex(b.Max) if start > end || distStart > distEnd { panic("ups") } //fmt.Println(start, end, "|", distStart, distEnd) _ = fmt.Println // Insert into table. for a := start; a <= end; a *= len(s.Table) { ak := a % len(s.Table) for d := distStart; d <= distEnd; d *= len(s.Table) { dk := d % len(s.Table) s.Table[ak][dk] = append(s.Table[ak][dk], Index{ AvgLengthSq: s.AvgLengthSq, S: sp, }) } } }