Example #1
0
// 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
}