internal static void AddObjectPushdown(IBVHNodeAdapter <T> nAda, BVHNode <T> curNode, T newOb)
        {
            var left  = curNode.Left;
            var right = curNode.Right;

            // merge and pushdown left and right as a new node..
            var mergedSubnode = new BVHNode <T>(nAda.BVH);

            mergedSubnode.Left     = left;
            mergedSubnode.Right    = right;
            mergedSubnode.Parent   = curNode;
            mergedSubnode.GObjects = null;             // we need to be an interior node... so null out our object list..
            left.Parent            = mergedSubnode;
            right.Parent           = mergedSubnode;
            mergedSubnode.ChildRefit(nAda, propagate: false);

            // make new subnode for obj
            var newSubnode = new BVHNode <T>(nAda.BVH);

            newSubnode.Parent   = curNode;
            newSubnode.GObjects = new List <T> {
                newOb
            };
            nAda.MapObjectToBVHLeaf(newOb, newSubnode);
            newSubnode.ComputeVolume(nAda);

            // make assignments..
            curNode.Left  = mergedSubnode;
            curNode.Right = newSubnode;
            curNode.SetDepth(nAda, curNode.Depth);             // propagate new depths to our children.
            curNode.ChildRefit(nAda);
        }
        internal bool RefitVolume(IBVHNodeAdapter <T> nAda)
        {
            if (GObjects.Count == 0)
            {
                // TODO: fix this... we should never get called in this case...
                throw new NotImplementedException();
            }

            Bounds oldbox = Box;

            ComputeVolume(nAda);
            if (!Box.Equals(oldbox))
            {
                if (Parent != null)
                {
                    Parent.ChildRefit(nAda);
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
        /// <summary>
        /// tryRotate looks at all candidate rotations, and executes the rotation with the best resulting SAH (if any)
        /// </summary>
        /// <param name="bvh"></param>
        internal void TryRotate(BVH <T> bvh)
        {
            IBVHNodeAdapter <T> nAda = bvh.nAda;

            // if we are not a grandparent, then we can't rotate, so queue our parent and bail out
            if (Left.IsLeaf && Right.IsLeaf)
            {
                if (Parent != null)
                {
                    bvh.refitNodes.Add(Parent);
                    return;
                }
            }

            // for each rotation, check that there are grandchildren as necessary (aka not a leaf)
            // then compute total SAH cost of our branches after the rotation.

            float mySA = SA(Left) + SA(Right);

            RotOpt bestRot = EachRot.Min((rot) =>
            {
                switch (rot)
                {
                case Rot.NONE: return(new RotOpt(mySA, Rot.NONE));

                // child to grandchild rotations
                case Rot.L_RL:
                    if (Right.IsLeaf)
                    {
                        return(new RotOpt(float.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(Right.Left) + SA(AABBofPair(Left, Right.Right)), rot));
                    }

                case Rot.L_RR:
                    if (Right.IsLeaf)
                    {
                        return(new RotOpt(float.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(Right.Right) + SA(AABBofPair(Left, Right.Left)), rot));
                    }

                case Rot.R_LL:
                    if (Left.IsLeaf)
                    {
                        return(new RotOpt(float.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(AABBofPair(Right, Left.Right)) + SA(Left.Left), rot));
                    }

                case Rot.R_LR:
                    if (Left.IsLeaf)
                    {
                        return(new RotOpt(float.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(AABBofPair(Right, Left.Left)) + SA(Left.Right), rot));
                    }

                // grandchild to grandchild rotations
                case Rot.LL_RR:
                    if (Left.IsLeaf || Right.IsLeaf)
                    {
                        return(new RotOpt(float.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(AABBofPair(Right.Right, Left.Right)) + SA(AABBofPair(Right.Left, Left.Left)), rot));
                    }

                case Rot.LL_RL:
                    if (Left.IsLeaf || Right.IsLeaf)
                    {
                        return(new RotOpt(float.MaxValue, Rot.NONE));
                    }
                    else
                    {
                        return(new RotOpt(SA(AABBofPair(Right.Left, Left.Right)) + SA(AABBofPair(Left.Left, Right.Right)), rot));
                    }

                // unknown...
                default: throw new NotImplementedException("missing implementation for BVH Rotation SAH Computation .. " + rot.ToString());
                }
            });

            // perform the best rotation...
            if (bestRot.rot != Rot.NONE)
            {
                // if the best rotation is no-rotation... we check our parents anyhow..
                if (Parent != null)
                {
                    // but only do it some random percentage of the time.
                    if ((DateTime.Now.Ticks % 100) < 2)
                    {
                        bvh.refitNodes.Add(Parent);
                    }
                }
            }
            else
            {
                if (Parent != null)
                {
                    bvh.refitNodes.Add(Parent);
                }

                if (((mySA - bestRot.SAH) / mySA) < 0.3f)
                {
                    return;                     // the benefit is not worth the cost
                }
                Console.WriteLine("BVH swap {0} from {1} to {2}", bestRot.rot.ToString(), mySA, bestRot.SAH);

                // in order to swap we need to:
                //  1. swap the node locations
                //  2. update the depth (if child-to-grandchild)
                //  3. update the parent pointers
                //  4. refit the boundary box
                BVHNode <T> swap = null;
                switch (bestRot.rot)
                {
                case Rot.NONE: break;

                // child to grandchild rotations
                case Rot.L_RL: swap = Left; Left = Right.Left; Left.Parent = this; Right.Left = swap; swap.Parent = Right; Right.ChildRefit(nAda, propagate: false); break;

                case Rot.L_RR: swap = Left; Left = Right.Right; Left.Parent = this; Right.Right = swap; swap.Parent = Right; Right.ChildRefit(nAda, propagate: false); break;

                case Rot.R_LL: swap = Right; Right = Left.Left; Right.Parent = this; Left.Left = swap; swap.Parent = Left; Left.ChildRefit(nAda, propagate: false); break;

                case Rot.R_LR: swap = Right; Right = Left.Right; Right.Parent = this; Left.Right = swap; swap.Parent = Left; Left.ChildRefit(nAda, propagate: false); break;

                // grandchild to grandchild rotations
                case Rot.LL_RR: swap = Left.Left; Left.Left = Right.Right; Right.Right = swap; Left.Left.Parent = Left; swap.Parent = Right; Left.ChildRefit(nAda, propagate: false); Right.ChildRefit(nAda, propagate: false); break;

                case Rot.LL_RL: swap = Left.Left; Left.Left = Right.Left; Right.Left = swap; Left.Left.Parent = Left; swap.Parent = Right; Left.ChildRefit(nAda, propagate: false); Right.ChildRefit(nAda, propagate: false); break;

                // unknown...
                default: throw new NotImplementedException("missing implementation for BVH Rotation .. " + bestRot.rot.ToString());
                }

                // fix the depths if necessary....
                switch (bestRot.rot)
                {
                case Rot.L_RL:
                case Rot.L_RR:
                case Rot.R_LL:
                case Rot.R_LR:
                    this.SetDepth(nAda, this.Depth);
                    break;
                }
            }
        }