예제 #1
0
        /// <summary>
        /// Search for elements within the volume defined by the bounding volume.
        /// </summary>
        public IEnumerable <T> FindInsideBoundingVolume(IBoundingVolume bv)
        {
            if (!bv.Intersect(this.Tree.InternalBounds))
            {
                yield break;
            }

            // Init search
            Stack <KdNode <T> > s = new Stack <KdNode <T> >();

            s.Push(this.Tree);
            int found = 0;

            // Run
            while (s.Count > 0 && found < this.CountLimit)
            {
                KdNode <T> n = s.Pop();
                if (n.Leaf)
                {
                    // Once we encounter a leaf an exhaustive search is performed for all elements inside
                    // the bounding volume up to the adjusted limit.
                    List <T> elements = this.ExhaustiveSearchLeaf(n, ref found, delegate(T obj) { return(bv.Inside(obj)); });
                    foreach (T t in elements)
                    {
                        yield return(t);
                    }
                }
                else // Intermediate node
                // Classify against split plane
                {
                    EPlanePosition pos = bv.ClassifyPlane(n.SplitDimension, n.SplitLocation);
                    if (pos == EPlanePosition.LeftOfBV)
                    {
                        s.Push(n.Right);
                    }
                    else if (pos == EPlanePosition.RightOfBV)
                    {
                        s.Push(n.Left);
                    }
                    else // Intersecting
                    {
                        s.Push(n.Right);
                        s.Push(n.Left);
                    }
                }
            }
        }
        /// <summary>
        /// Computes the complete intersection of the given ray with the object.
        /// </summary>
        /// <param name="p0">Ray origin.</param>
        /// <param name="p1">Ray direction vector.</param>
        /// <returns>Sorted list of intersection records.</returns>
        public override LinkedList <Intersection> Intersect(Vector3d p0, Vector3d p1)
        {
            if (children == null || children.Count == 0)
            {
                return(null);
            }

            if (BoundingVolume != null)
            {
                countBoundingBoxes++;
                if (BoundingVolume.Intersect(p0, p1) < -0.5)
                {
                    return(null);
                }
            }

            LinkedList <Intersection> result = null;
            LinkedList <Intersection> left   = null; // I'm going to reuse these two..

            bool leftOp = true;                      // the 1st pass => left operand

            foreach (ISceneNode child in children)
            {
                Vector3d origin = Vector3d.TransformPosition(p0, child.FromParent);
                Vector3d dir    = Vector3d.TransformVector(p1, child.FromParent);
                // ray in local child's coords: [ origin, dir ]

                LinkedList <Intersection> partial = child.Intersect(origin, dir);
                if (partial == null)
                {
                    partial = leftOp ? new LinkedList <Intersection>() : emptyResult;
                }
                else
                if (child is ISolid)
                {
                    Intersection.countIntersections += partial.Count;
                }

                if (leftOp)
                {
                    leftOp = false;
                    result = partial;
                    left   = new LinkedList <Intersection>();
                }
                else
                {
                    if (trivial && partial.Count == 0)
                    {
                        continue;
                    }

                    // resolve one binary operation (result := left # partial):
                    {
                        LinkedList <Intersection> tmp = left;
                        left   = result;
                        result = tmp;
                    }
                    // result .. empty so far
                    result.Clear();

                    double       lowestT    = Double.NegativeInfinity;
                    Intersection leftFirst  = (left.First == null) ? null : left.First.Value;
                    Intersection rightFirst = (partial.First == null) ? null : partial.First.Value;
                    // initial inside status values:
                    bool insideLeft   = (leftFirst != null && !leftFirst.Enter);
                    bool insideRight  = (rightFirst != null && !rightFirst.Enter);
                    bool insideResult = bop(insideLeft, insideRight);
                    // merge behavior:
                    bool minLeft  = (leftFirst != null && leftFirst.T == lowestT);
                    bool minRight = (rightFirst != null && rightFirst.T == lowestT);

                    while (leftFirst != null || rightFirst != null)
                    {
                        double leftVal  = (leftFirst != null) ? leftFirst.T : double.PositiveInfinity;
                        double rightVal = (rightFirst != null) ? rightFirst.T : double.PositiveInfinity;
                        lowestT = Math.Min(leftVal, rightVal);
                        Debug.Assert(!Double.IsInfinity(lowestT));

                        minLeft  = leftVal == lowestT;
                        minRight = rightVal == lowestT;

                        Intersection first = null;
                        if (minRight)
                        {
                            first = rightFirst;
                            partial.RemoveFirst();
                            rightFirst  = (partial.First == null) ? null : partial.First.Value;
                            insideRight = first.Enter;
                        }
                        if (minLeft)
                        {
                            first = leftFirst;
                            left.RemoveFirst();
                            leftFirst  = (left.First == null) ? null : left.First.Value;
                            insideLeft = first.Enter;
                        }
                        bool newResult = bop(insideLeft, insideRight);

                        if (newResult != insideResult)
                        {
                            first.Enter = insideResult = newResult;
                            result.AddLast(first);
                        }
                    }
                }
                if (shortCurcuit && result.Count == 0)
                {
                    break;
                }
            }

            return(result);
        }