/// <summary> /// Search in the BVH tree using a flexible "locator" object, which should return the /// "distance" of a BVH Node object. Returns a list of results in increasing distance /// up to a relative bound and absolute maximum. /// </summary> /// <param name="distance_max">The maximum distance to look for.</param> /// <param name="relative_bound">Stop returning more items after 'relative_bound' times /// the first item's distance.</param> /// <param name="locator">A delegate, like Locate() but passed also the current 'distance_max'.</param> /// <returns>A list of instances of the concrete BVHNodeBase subclass.</returns> public List <BVHNodeBase> LocateList(float distance_max, float relative_bound, DistanceToNodeEx locator) { var output_list = new List <BVHNodeBase>(); if (!(root is BVHNode)) { if (root != null) { float distance = locator(root, distance_max); if (distance < distance_max) { output_list.Add(root); } } return(output_list); } var heapq = new HeapQ <LocNext>(); BVHNodeBase base_node = root; float distance_1 = 0; while (distance_1 < distance_max) { if (base_node is BVHNode) { var node = (BVHNode)base_node; float d_left = locator(node.left, distance_max); if (d_left < distance_max) { if (!(node.left is BVHNode)) { distance_max = Mathf.Min(distance_max, d_left * relative_bound); } heapq.Push(new LocNext(d_left, node.left)); } float d_right = locator(node.right, distance_max); if (d_right < distance_max) { if (!(node.right is BVHNode)) { distance_max = Mathf.Min(distance_max, d_right * relative_bound); } heapq.Push(new LocNext(d_right, node.right)); } } else { output_list.Add(base_node); } if (heapq.Empty) { break; } LocNext next = heapq.Pop(); distance_1 = next.distance; base_node = next.node; } return(output_list); }
/// <summary> /// Search in the BVH tree using a flexible "locator" delegate, which should return the /// "distance" of a BVH Node object. /// </summary> /// <param name="distance">The maximum distance to look for.</param> /// <param name="locator">A delegate. A typical implementation has got two cases: if /// given an instance of a concrete class that the caller knows about, it should return /// the distance to that; otherwise, it should return the distance to the bounding box. /// The present algorithm assumes that when a bounding box grows, the distance returned /// by "locator" decreases or stays constant.</param> /// <returns>A instance of the concrete BVHNodeBase subclass.</returns> public BVHNodeBase Locate(float distance_max, DistanceToNode locator) { if (!(root is BVHNode)) { if (root != null) { float distance = locator(root, distance_max); if (distance < distance_max) { return(root); } } return(null); } var heapq = new HeapQ <LocNext>(); BVHNodeBase base_node = root; while (true) { if (base_node is BVHNode) { var node = (BVHNode)base_node; float d_left = locator(node.left, distance_max); if (d_left < distance_max) { if (!(node.left is BVHNode)) { distance_max = d_left; } heapq.Push(new LocNext(d_left, node.left)); } float d_right = locator(node.right, distance_max); if (d_right < distance_max) { if (!(node.right is BVHNode)) { distance_max = d_right; } heapq.Push(new LocNext(d_right, node.right)); } } else { return(base_node); } if (heapq.Empty) { break; } LocNext next = heapq.Pop(); base_node = next.node; } return(null); }