From c23a55691e8d2699f536c7898446b18cd99057fb Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:19:37 +0530 Subject: [PATCH 1/7] feat: add QuadTree datastructure --- .../datastructures/trees/QuadTree.java | 172 ++++++++++++++++++ .../datastructures/trees/QuadTreeTest.java | 35 ++++ 2 files changed, 207 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java create mode 100644 src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java new file mode 100644 index 000000000000..27613b7948ad --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java @@ -0,0 +1,172 @@ +package com.thealgorithms.datastructures.trees; + +import java.util.ArrayList; +import java.util.List; + +/** + * Point is a simple class that represents a point in 2D space. + * + * @see Point + * @author Sailok Chinta + */ +class Point { + public double x; + public double y; + + Point(double x, double y) { + this.x = x; + this.y = y; + } +} + +/** + * BoundingBox is a simple class that represents a bounding box in 2D space. + * + * @see Bounding Box + * @author Sailok Chinta + */ +class BoundingBox { + private static final double BOUNDING_BOX_HALF_WIDTH = 0.5; + + public Point center; + public double halfWidth; + + BoundingBox(Point center, double halfWidth) { + this.center = center; + this.halfWidth = halfWidth; + } + + /** + * Checks if the point is inside the bounding box + * + * @param point The point to check + * @return true if the point is inside the bounding box, false otherwise + */ + public boolean containsPoint(Point point) { + return point.x >= center.x - halfWidth + && point.x <= center.x + halfWidth + && point.y >= center.y - halfWidth + && point.y <= center.y + halfWidth; + } + + /** + * Checks if the bounding box intersects with the other bounding box + * + * @param otherBoundingBox The other bounding box + * @return true if the bounding box intersects with the other bounding box, false otherwise + */ + public boolean intersectsBoundingBox(BoundingBox otherBoundingBox) { + return otherBoundingBox.center.x - otherBoundingBox.halfWidth <= center.x + halfWidth + && otherBoundingBox.center.x + otherBoundingBox.halfWidth >= center.x - halfWidth + && otherBoundingBox.center.y - otherBoundingBox.halfWidth <= center.y + halfWidth + && otherBoundingBox.center.y + otherBoundingBox.halfWidth >= center.y - halfWidth; + } +} + +/** + * QuadTree is a tree data structure that is used to store spatial information + * in an efficient way. + * + * This implementation is specific to Point QuadTrees + * + * @see Quad Tree + * @author Sailok Chinta + */ +public class QuadTree { + private final BoundingBox boundary; + private final int capacity; + + private List pointList; + private boolean divided; + private QuadTree northWest; + private QuadTree northEast; + private QuadTree southWest; + private QuadTree southEast; + + public QuadTree(BoundingBox boundary, int capacity) { + this.boundary = boundary; + this.capacity = capacity; + + this.pointList = new ArrayList<>(); + this.divided = false; + this.northWest = null; + this.northEast = null; + this.southWest = null; + this.southEast = null; + } + + /** + * Inserts a point into the tree + * + * @param point The point to insert + * @return true if the point is successfully inserted, false otherwise + */ + public boolean insert(Point point) { + if (point == null) { + return false; + } + + // Ignore points that don't belong to this quad tree + if (!boundary.containsPoint(point)) { + return false; + } + + // if the space is not already occupied, add it to the list + if (pointList.size() < capacity) { + pointList.add(point); + return true; + } + + // if subdivision hasn't happened, divide the tree + if (!divided) { + subDivide(); + } + + // try to add the point in one of the four quadrants + if (northWest.insert(point)) return true; + if (northEast.insert(point)) return true; + if (southWest.insert(point)) return true; + if (southEast.insert(point)) return true; + + return false; + } + + /** + * Create four children that fully divide this quad into four quads of equal area + */ + private void subDivide() { + double quadrantHalfWidth = boundary.halfWidth / 2; + + northWest = new QuadTree(new BoundingBox(new Point(boundary.center.x - quadrantHalfWidth, boundary.center.y + quadrantHalfWidth), quadrantHalfWidth), this.capacity); + northEast = new QuadTree(new BoundingBox(new Point(boundary.center.x + quadrantHalfWidth, boundary.center.y + quadrantHalfWidth), quadrantHalfWidth), this.capacity); + southWest = new QuadTree(new BoundingBox(new Point(boundary.center.x - quadrantHalfWidth, boundary.center.y - quadrantHalfWidth), quadrantHalfWidth), this.capacity); + southEast = new QuadTree(new BoundingBox(new Point(boundary.center.x + quadrantHalfWidth, boundary.center.y - quadrantHalfWidth), quadrantHalfWidth), this.capacity); + divided = true; + } + + /** + * Queries all the points that intersect with the other bounding box + * + * @param otherBoundingBox The other bounding box + * @return List of points that intersect with the other bounding box + */ + public List query(BoundingBox otherBoundingBox) { + List points = new ArrayList<>(); + + if (!boundary.intersectsBoundingBox(otherBoundingBox)) { + return points; + } + + // filter the points that intersect with the other bounding box + points.addAll(pointList.stream().filter(otherBoundingBox::containsPoint).toList()); + + if (divided) { + points.addAll(northWest.query(otherBoundingBox)); + points.addAll(northEast.query(otherBoundingBox)); + points.addAll(southWest.query(otherBoundingBox)); + points.addAll(southEast.query(otherBoundingBox)); + } + + return points; + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java new file mode 100644 index 000000000000..f815396ff250 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java @@ -0,0 +1,35 @@ +package com.thealgorithms.datastructures.trees; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; + +public class QuadTreeTest { + int quadTreeCapacity = 4; + BoundingBox boundingBox = new BoundingBox(new Point(0, 0), 500); + QuadTree quadTree = new QuadTree(boundingBox, quadTreeCapacity); + + @Test + public void testInsertIntoQuadTree() { + Assertions.assertTrue(quadTree.insert(new Point(10, -10))); + Assertions.assertTrue(quadTree.insert(new Point(-10, 10))); + Assertions.assertTrue(quadTree.insert(new Point(-10, -10))); + Assertions.assertTrue(quadTree.insert(new Point(10, 10))); + Assertions.assertFalse(quadTree.insert(new Point(1050, 1050))); + } + + @Test + public void testQueryInQuadTree() { + quadTree.insert(new Point(10, -10)); + quadTree.insert(new Point(-10, 10)); + quadTree.insert(new Point(-10, -10)); + quadTree.insert(new Point(10, 10)); + + List points = quadTree.query(new BoundingBox(new Point(0, 0), 100)); + Assertions.assertEquals(4, points.size()); + + points = quadTree.query(new BoundingBox(new Point(5, 5), 5)); + Assertions.assertEquals(1, points.size()); + } +} From c368341314e87c94316eb7e87e5fd45b9ffbfb11 Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:21:53 +0530 Subject: [PATCH 2/7] feat: fix clang format issues & checkstyle issues --- .../datastructures/trees/QuadTree.java | 30 +++++++++++-------- .../datastructures/trees/QuadTreeTest.java | 3 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java index 27613b7948ad..e020fa24a1dc 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java @@ -43,10 +43,7 @@ class BoundingBox { * @return true if the point is inside the bounding box, false otherwise */ public boolean containsPoint(Point point) { - return point.x >= center.x - halfWidth - && point.x <= center.x + halfWidth - && point.y >= center.y - halfWidth - && point.y <= center.y + halfWidth; + return point.x >= center.x - halfWidth && point.x <= center.x + halfWidth && point.y >= center.y - halfWidth && point.y <= center.y + halfWidth; } /** @@ -56,10 +53,8 @@ public boolean containsPoint(Point point) { * @return true if the bounding box intersects with the other bounding box, false otherwise */ public boolean intersectsBoundingBox(BoundingBox otherBoundingBox) { - return otherBoundingBox.center.x - otherBoundingBox.halfWidth <= center.x + halfWidth - && otherBoundingBox.center.x + otherBoundingBox.halfWidth >= center.x - halfWidth - && otherBoundingBox.center.y - otherBoundingBox.halfWidth <= center.y + halfWidth - && otherBoundingBox.center.y + otherBoundingBox.halfWidth >= center.y - halfWidth; + return otherBoundingBox.center.x - otherBoundingBox.halfWidth <= center.x + halfWidth && otherBoundingBox.center.x + otherBoundingBox.halfWidth >= center.x - halfWidth && otherBoundingBox.center.y - otherBoundingBox.halfWidth <= center.y + halfWidth + && otherBoundingBox.center.y + otherBoundingBox.halfWidth >= center.y - halfWidth; } } @@ -123,10 +118,21 @@ public boolean insert(Point point) { } // try to add the point in one of the four quadrants - if (northWest.insert(point)) return true; - if (northEast.insert(point)) return true; - if (southWest.insert(point)) return true; - if (southEast.insert(point)) return true; + if (northWest.insert(point)) { + return true; + } + + if (northEast.insert(point)) { + return true; + } + + if (southWest.insert(point)) { + return true; + } + + if (southEast.insert(point)) { + return true; + } return false; } diff --git a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java index f815396ff250..8cfbc4708057 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java @@ -1,10 +1,9 @@ package com.thealgorithms.datastructures.trees; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import java.util.List; - public class QuadTreeTest { int quadTreeCapacity = 4; BoundingBox boundingBox = new BoundingBox(new Point(0, 0), 500); From 6ab3088a6192eb225892f62b2620c8af6d1bf40f Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:24:46 +0530 Subject: [PATCH 3/7] feat: update CONTRIBUTING.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 70de110e86ea..58676269167e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -205,6 +205,7 @@ * [PostOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PostOrderTraversal.java) * [PreOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PreOrderTraversal.java) * [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PrintTopViewofTree.java) + * [QuadTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java) * [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/RedBlackBST.java) * [SameTreesCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SameTreesCheck.java) * [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java) From ce6a9f3029948580617c46e395ca5102e8a5cd5c Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:27:29 +0530 Subject: [PATCH 4/7] feat: improve test coverage --- .../datastructures/trees/QuadTreeTest.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java index 8cfbc4708057..8490ad45f8b0 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java @@ -9,6 +9,11 @@ public class QuadTreeTest { BoundingBox boundingBox = new BoundingBox(new Point(0, 0), 500); QuadTree quadTree = new QuadTree(boundingBox, quadTreeCapacity); + @Test + public void testNullPointInsertIntoQuadTree() { + Assertions.assertFalse(quadTree.insert(null)); + } + @Test public void testInsertIntoQuadTree() { Assertions.assertTrue(quadTree.insert(new Point(10, -10))); @@ -18,12 +23,28 @@ public void testInsertIntoQuadTree() { Assertions.assertFalse(quadTree.insert(new Point(1050, 1050))); } + @Test + public void testInsertIntoQuadTreeAndSubDivide() { + Assertions.assertTrue(quadTree.insert(new Point(10, -10))); + Assertions.assertTrue(quadTree.insert(new Point(-10, 10))); + Assertions.assertTrue(quadTree.insert(new Point(-10, -10))); + Assertions.assertTrue(quadTree.insert(new Point(10, 10))); + Assertions.assertTrue(quadTree.insert(new Point(-100, 100))); + Assertions.assertTrue(quadTree.insert(new Point(100, -100))); + Assertions.assertTrue(quadTree.insert(new Point(-100, -100))); + Assertions.assertTrue(quadTree.insert(new Point(100, 100))); + } + @Test public void testQueryInQuadTree() { quadTree.insert(new Point(10, -10)); quadTree.insert(new Point(-10, 10)); quadTree.insert(new Point(-10, -10)); quadTree.insert(new Point(10, 10)); + quadTree.insert(new Point(-100, 100)); + quadTree.insert(new Point(100, -100)); + quadTree.insert(new Point(-100, -100)); + quadTree.insert(new Point(100, 100)); List points = quadTree.query(new BoundingBox(new Point(0, 0), 100)); Assertions.assertEquals(4, points.size()); From 3f1fd6f32cbc224432f96b1993695fe8841826eb Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:29:10 +0530 Subject: [PATCH 5/7] feat: remove unused code --- .../java/com/thealgorithms/datastructures/trees/QuadTree.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java index e020fa24a1dc..e0d255b1e784 100644 --- a/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java +++ b/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java @@ -26,8 +26,6 @@ class Point { * @author Sailok Chinta */ class BoundingBox { - private static final double BOUNDING_BOX_HALF_WIDTH = 0.5; - public Point center; public double halfWidth; From 677067f32fee740cd128b62a9eb05bb590917594 Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:31:26 +0530 Subject: [PATCH 6/7] feat: fix test case --- .../com/thealgorithms/datastructures/trees/QuadTreeTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java index 8490ad45f8b0..de56d90ebd84 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java @@ -47,7 +47,7 @@ public void testQueryInQuadTree() { quadTree.insert(new Point(100, 100)); List points = quadTree.query(new BoundingBox(new Point(0, 0), 100)); - Assertions.assertEquals(4, points.size()); + Assertions.assertEquals(8, points.size()); points = quadTree.query(new BoundingBox(new Point(5, 5), 5)); Assertions.assertEquals(1, points.size()); From 6e57a4467730533aa4baccc745265c604b626c29 Mon Sep 17 00:00:00 2001 From: "sailok.chinta" Date: Wed, 9 Oct 2024 21:37:13 +0530 Subject: [PATCH 7/7] feat: fix test case --- .../com/thealgorithms/datastructures/trees/QuadTreeTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java index de56d90ebd84..62b86da214db 100644 --- a/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java +++ b/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java @@ -30,7 +30,7 @@ public void testInsertIntoQuadTreeAndSubDivide() { Assertions.assertTrue(quadTree.insert(new Point(-10, -10))); Assertions.assertTrue(quadTree.insert(new Point(10, 10))); Assertions.assertTrue(quadTree.insert(new Point(-100, 100))); - Assertions.assertTrue(quadTree.insert(new Point(100, -100))); + Assertions.assertTrue(quadTree.insert(new Point(100, -101))); Assertions.assertTrue(quadTree.insert(new Point(-100, -100))); Assertions.assertTrue(quadTree.insert(new Point(100, 100))); } @@ -51,5 +51,8 @@ public void testQueryInQuadTree() { points = quadTree.query(new BoundingBox(new Point(5, 5), 5)); Assertions.assertEquals(1, points.size()); + + points = quadTree.query(new BoundingBox(new Point(-200, -200), 5)); + Assertions.assertEquals(0, points.size()); } }