// 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), } }
// 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 }
func (n *Node) fits(sb math.Rect3) bool { if sb.In(n.bounds) { return true } return false }