/// <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); }