From 62c8817a70ad6b1ab5d2b53ca49894319479200a Mon Sep 17 00:00:00 2001 From: Daniel Schramm <xschramm@fi.muni.cz> Date: Mon, 22 Mar 2021 17:07:54 +0100 Subject: [PATCH] ClosestNodeMultipleVisitor repeated tree traversal reduced --- .../kdtree/ClosestNodeMultipleVisitor.java | 63 +++++-------------- .../ClosestNodeMultipleVisitorTest.java | 51 +++++++++++++++ 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitor.java b/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitor.java index 4c510c66..221637b1 100644 --- a/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitor.java +++ b/Comparison/src/main/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitor.java @@ -59,54 +59,18 @@ public class ClosestNodeMultipleVisitor extends ClosestNodeAbstractVisitor { return; } - KdNode foundNode = closestNode(kdTree.getRoot()); - final double closestDistance = MeshPoint.distance(getPoint3d(), foundNode.getLocation()); - synchronized (this) { - if (updateMinimalDistance(closestDistance)) { - closest.clear(); - } - } - - // There is no closer point than the 'closestFound' in our tree. - // Search for other closest points with the same distance. - while (foundNode != null) { - final double distanceFound = MeshPoint.distance(getPoint3d(), foundNode.getLocation()); - synchronized (this) { - if (distanceFound == getDistance()) { - closest.add(foundNode); - } else { // There is a closer point found in some other tree visited by this visitor - return; - } - } - foundNode = closestNodeOmitting(root); - } - } - - /* - * Find an undiscovered node with its distance equal to 'distance'. - * - * - Discovered nodes are those stored in the 'closest' set. - * - We are not looking for distance closer than 'distance' because - * from the method {@link cz.fidentis.analyst.visitors.kdtree.ClosestNodeMultipleVisitor#visitKdTree} - * we already know distance to the closest node of the visited tree. - */ - private KdNode closestNodeOmitting(KdNode root) { - if (root == null) { - return null; - } + KdNode searchedNode = root; /* - * First, find the closest node + * Reduce the search space by exploring the area where the closest node + * may theoretically be located. */ - KdNode nearNode = null; - KdNode searchedNode = root; - while (searchedNode != null) { final Vector3d nodePos = searchedNode.getLocation(); final double dist = MeshPoint.distance(getPoint3d(), nodePos); synchronized (this) { - if (dist == getDistance() && !closest.contains(searchedNode)) { - nearNode = searchedNode; + if (updateMinimalDistance(dist) && !closest.isEmpty()) { + closest.clear(); } } @@ -118,20 +82,23 @@ public class ClosestNodeMultipleVisitor extends ClosestNodeAbstractVisitor { } /* - * Second, search for a vertex that could be potentially closer than - * the nearest vertex already found + * Search for vertices that could be potentially closer than + * the closest distance already found or at the same distance. */ final Queue<KdNode> queue = new LinkedList<>(); queue.add(root); while (!queue.isEmpty()) { searchedNode = queue.poll(); - Vector3d nodePos = searchedNode.getLocation(); + final Vector3d nodePos = searchedNode.getLocation(); final double dist = MeshPoint.distance(getPoint3d(), nodePos); synchronized (this) { - if (dist == getDistance() && !closest.contains(searchedNode)) { - nearNode = searchedNode; + if (updateMinimalDistance(dist)) { + closest.clear(); + closest.add(searchedNode); + } else if (dist == getDistance()) { + closest.add(searchedNode); } } @@ -156,8 +123,6 @@ public class ClosestNodeMultipleVisitor extends ClosestNodeAbstractVisitor { } } } - - return nearNode; } - + } diff --git a/Comparison/src/test/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitorTest.java b/Comparison/src/test/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitorTest.java index a0ba2374..89e0d65a 100644 --- a/Comparison/src/test/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitorTest.java +++ b/Comparison/src/test/java/cz/fidentis/analyst/visitors/kdtree/ClosestNodeMultipleVisitorTest.java @@ -110,4 +110,55 @@ public class ClosestNodeMultipleVisitorTest { assertEquals(8, closestFound.size()); testContainsExactlyPositions(closest, closestFound); } + + @Test + public void threeTreesSingleClosestTest() { + final Set<MeshPoint> closest = getTreeNodesSymmetric(1); + final KdTree kdTreeClosest = new KdTree(closest); + + final KdTree kdTree1 = new KdTree(getTreeNodesSymmetric(2)); + final KdTree kdTree2 = new KdTree(getTreeNodesSymmetric(3)); + + final ClosestNodeMultipleVisitor visitor = new ClosestNodeMultipleVisitor(centerNode, false); + kdTree1.accept(visitor); + kdTreeClosest.accept(visitor); + kdTree2.accept(visitor); + + final Set<KdNode> closestFound = visitor.getClosestNodes(); + assertEquals(8, closestFound.size()); + testContainsExactlyPositions(closest, closestFound); + } + + @Test + public void threeTreesTwoClosestTest() { + final Set<MeshPoint> closest = getTreeNodesSymmetric(1); + final Set<MeshPoint> closest1 = new HashSet<>(); + final Set<MeshPoint> closest2 = new HashSet<>(); + boolean odd = true; + for (final MeshPoint point: closest) { + if (odd) { + closest1.add(point); + } else { + closest2.add(point); + } + odd = !odd; + } + assertEquals(8, closest.size()); + assertEquals(4, closest1.size()); + assertEquals(4, closest2.size()); + + final KdTree kdTreeClosest1 = new KdTree(closest1); + final KdTree kdTreeClosest2 = new KdTree(closest2); + final KdTree kdTree = new KdTree(getTreeNodesSymmetric(2)); + + final ClosestNodeMultipleVisitor visitor = new ClosestNodeMultipleVisitor(centerNode, false); + kdTreeClosest1.accept(visitor); + kdTree.accept(visitor); + kdTreeClosest2.accept(visitor); + + final Set<KdNode> closestFound = visitor.getClosestNodes(); + assertEquals(8, closestFound.size()); + testContainsExactlyPositions(closest, closestFound); + } + } -- GitLab