// Takes a child node position and returns it's bounds. func (n *Node) childBounds(pos, divisor math.Vec3) math.Rect3 { size := n.childSize(divisor) cb := math.Rect3{ Min: pos, Max: pos.Add(size), } if !n.bounds.Contains(cb.Min) || !n.bounds.Contains(cb.Max) { fmt.Println(pos) fmt.Println(n.bounds) fmt.Println(n.bounds.Contains(cb.Min)) fmt.Println(n.bounds.Contains(cb.Max)) panic("not contained") } if !cb.In(n.bounds) { //fmt.Println("pos ", pos) //fmt.Println("size ", size) //fmt.Println("child ", cb) //fmt.Println("parent", n.bounds) //panic("") } return math.Rect3{ Min: pos, Max: pos.Add(size), } }
// CalculateBounds calculates a new axis aligned bounding box for this mesh. // // The mesh's write lock must be held for this method to operate safely. func (m *Mesh) CalculateBounds() { var bb math.Rect3 if len(m.Vertices) > 0 { for _, v32 := range m.Vertices { v := v32.Vec3() bb.Min = bb.Min.Min(v) bb.Max = bb.Max.Max(v) } } m.AABB = bb }
// findPlace finds a place in this node or any node below it in the tree where // r can be placed. func (n *Node) findPlace(r math.Rect3) (*Node, ChildIndex) { if !r.In(n.bounds) { return nil, -1 } childIndex := n.childFits(r) if childIndex != -1 && n.children[childIndex] != nil { cn, ci := n.children[childIndex].findPlace(r) if cn != nil { return cn, ci } } return n, -1 }
// find finds this or a distance node where the given rectangle, r, would have // been placed. func (n *Node) find(r math.Rect3) *Node { if !r.In(n.bounds) { // Not inside this node at all. return nil } // Check children... for _, child := range n.Children { ccn := child.find(r) if ccn != nil { return ccn } } return n }
// childFits finds a direct child of this node that can fit the rectangle, r, // and returns it's bounds. func (n *Node) childFits(r math.Rect3, divisor math.Vec3) (b math.Rect3, ok bool) { // Find a child path to create. nb := n.bounds sz := n.childSize(divisor) for x := nb.Min.X; x <= nb.Max.X; x += sz.X { for y := nb.Min.Y; y <= nb.Max.Y; y += sz.Y { for z := nb.Min.Z; z <= nb.Max.Z; z += sz.Z { cb := n.childBounds(math.Vec3{x, y, z}, divisor) if r.In(cb) { return cb, true } } } } return math.Rect3Zero, false }
// createPath creates nodes along the needed path up to maxDepth where the // given spatial's bounds, sb, can be placed. func (n *Node) createPath(divisor math.Vec3, maxDepth int, sb math.Rect3) *Node { nb := n.bounds if !sb.In(nb) { // Not inside this node at all. return nil } if n.Level+1 > maxDepth { // Any child would exceed the maximum depth. return n } // Check existing children... for _, child := range n.Children { ccn := child.find(sb) if ccn != nil { // An existing child node can fit the spatials bounds, sb, so ask // it to create the path instead. return child.createPath(divisor, maxDepth, sb) } } // Find a child path to create. db, ok := n.childFits(sb, divisor) if ok { // Create the child. child := &Node{ Level: n.Level + 1, bounds: db, } n.Children = append(n.Children, child) ccn := child.createPath(divisor, maxDepth, sb) if ccn != nil { return ccn } return child } return n }
// Bounds implements the Spatial interface. The returned bounding box takes // into account all of the mesh's bounding boxes, transformed into world space. // // This method properly read-locks the object. func (o *Object) Bounds() math.Rect3 { var b math.Rect3 o.RLock() for i, m := range o.Meshes { if i == 0 { b = m.Bounds() } else { b = b.Union(m.Bounds()) } } if o.Transform != nil { b.Min = o.Transform.ConvertPos(b.Min, LocalToWorld) b.Max = o.Transform.ConvertPos(b.Max, LocalToWorld) b = b.Union(b) } o.RUnlock() return b }
// expand performs expansion of the root node, n, towards r's center. If a new // root node is created then it is returned and n.parent is set to the new root // node. func (n *Node) expand(r math.Rect3) *Node { nb := n.bounds if nb.Empty() { // For starting bounds we will (squarely) encapsulate the rectangle. rsz := r.Size() s := rsz.X if rsz.Y > s { s = rsz.Y } if rsz.Z > s { s = rsz.Z } rcenter := r.Center() s /= 2 s *= 32 startSize := math.Vec3{s, s, s} n.bounds = math.Rect3{ Min: rcenter.Sub(startSize), Max: rcenter.Add(startSize), } return nil } // Expansion occurs by growing the octree such that the root node becomes // a new node whose child is the old root node. Thus we can simply // determine in which direction the new root should be extended (by twice // the old root's size) by comparing the centres of the old root and the // rectangle in question. c := nb.Center() rc := r.Center() sz := nb.Size() // Expand by becoming the opposite octant of r's closest point to nb. var ci ChildIndex if rc.Z > c.Z { // Top if rc.Y > c.Y { // Top, Front if rc.X > c.X { ci = TopFrontRight } else { ci = TopFrontLeft } } else { // Top, Back if rc.X > c.X { ci = TopBackRight } else { ci = TopBackLeft } } } else { // Bottom if rc.Y > c.Y { // Bottom, Front if rc.X > c.X { ci = BottomFrontRight } else { ci = BottomFrontLeft } } else { // Bottom, Back if rc.X > c.X { ci = BottomBackRight } else { ci = BottomBackLeft } } } expDown := ci.Bottom() expBack := ci.Back() expLeft := ci.Left() fb := n.bounds if expDown { fb.Min.Z -= sz.Z } else { fb.Max.Z += sz.Z } if expBack { fb.Min.Y -= sz.Y } else { fb.Max.Y += sz.Y } if expLeft { fb.Min.X -= sz.X } else { fb.Max.X += sz.X } newRoot := &Node{ access: n.access, bounds: fb, level: n.level + 1, objects: make([][]*entry, 9), } newRoot.children[ci] = n n.parent = newRoot return newRoot }
func (n *Node) fits(sb math.Rect3) bool { if sb.In(n.bounds) { return true } return false }