作者:pombredann
项目:ran
// 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),
}
}
作者:pombredann
项目:ran
// 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
}
作者:pombredann
项目:ran
// 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
}
作者:pombredann
项目:ran
// 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
}
作者:pombredann
项目:ran
// 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
}
作者:pombredann
项目:ran
// 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
}
作者:pombredann
项目:ran
// 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
}
作者:pombredann
项目:ran
// 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,
//.........这里部分代码省略.........
作者:pombredann
项目:ran
func (n *Node) fits(sb math.Rect3) bool {
if sb.In(n.bounds) {
return true
}
return false
}