Example #1
0
// 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),
	}
}
Example #2
0
// 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
}
Example #3
0
// 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
}
Example #4
0
// 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
}
Example #5
0
// 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
}
Example #6
0
// 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
}
Example #7
0
// 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
}
Example #8
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
}
Example #9
0
func (n *Node) fits(sb math.Rect3) bool {
	if sb.In(n.bounds) {
		return true
	}
	return false
}