From 87449a8a9a4492010625ee2faded96ab83a1d42e Mon Sep 17 00:00:00 2001
From: josidd <joseph.siddons@noc.ac.uk>
Date: Wed, 27 Nov 2024 12:03:00 +0000
Subject: [PATCH 1/2] feat: add method to remove Record from QuadTree and
 OctTree classes

---
 GeoSpatialTools/octtree.py  | 35 +++++++++++++++++++++++++++++++++++
 GeoSpatialTools/quadtree.py | 27 +++++++++++++++++++++++++++
 test/test_octtree.py        | 35 +++++++++++++++++++++++++++++++++++
 test/test_quadtree.py       | 23 +++++++++++++++++++++++
 4 files changed, 120 insertions(+)

diff --git a/GeoSpatialTools/octtree.py b/GeoSpatialTools/octtree.py
index a82a2be..029ff9e 100644
--- a/GeoSpatialTools/octtree.py
+++ b/GeoSpatialTools/octtree.py
@@ -591,6 +591,41 @@ class OctTree:
                 return True
             return False
 
+    def remove(self, point: SpaceTimeRecord) -> bool:
+        """
+        Remove a SpaceTimeRecord from the OctTree if it is in the OctTree.
+
+        Returns True if the SpaceTimeRecord is removed.
+        """
+        if not self.boundary.contains(point):
+            return False
+
+        if point in self.points:
+            self.points.remove(point)
+            return True
+
+        if not self.divided:
+            return False
+
+        if self.northwestback.remove(point):
+            return True
+        elif self.northeastback.remove(point):
+            return True
+        elif self.southwestback.remove(point):
+            return True
+        elif self.southeastback.remove(point):
+            return True
+        elif self.northwestfwd.remove(point):
+            return True
+        elif self.northeastfwd.remove(point):
+            return True
+        elif self.southwestfwd.remove(point):
+            return True
+        elif self.southeastfwd.remove(point):
+            return True
+
+        return False
+
     def query(
         self,
         rect: SpaceTimeRectangle,
diff --git a/GeoSpatialTools/quadtree.py b/GeoSpatialTools/quadtree.py
index d24b4be..214bc38 100644
--- a/GeoSpatialTools/quadtree.py
+++ b/GeoSpatialTools/quadtree.py
@@ -404,6 +404,33 @@ class QuadTree:
                 return True
             return False
 
+    def remove(self, point: Record) -> bool:
+        """
+        Remove a Record from the QuadTree if it is in the QuadTree.
+
+        Returns True if the Record is removed.
+        """
+        if not self.boundary.contains(point):
+            return False
+
+        if point in self.points:
+            self.points.remove(point)
+            return True
+
+        if not self.divided:
+            return False
+
+        if self.northwest.remove(point):
+            return True
+        elif self.northeast.remove(point):
+            return True
+        elif self.southwest.remove(point):
+            return True
+        elif self.southeast.remove(point):
+            return True
+
+        return False
+
     def query(
         self,
         rect: Rectangle,
diff --git a/test/test_octtree.py b/test/test_octtree.py
index ab3d388..4a04eb2 100644
--- a/test/test_octtree.py
+++ b/test/test_octtree.py
@@ -223,6 +223,41 @@ class TestOctTree(unittest.TestCase):
         ]
         assert res == expected
 
+    def test_remove(self):
+        d = datetime(2023, 3, 24, 12, 0)
+        dt = timedelta(days=10)
+        start = d - dt
+        end = d + dt
+
+        boundary = Rectangle(0, 20, 0, 8, start, end)
+        otree = OctTree(boundary, capacity=3)
+        points: list[Record] = [
+            Record(10, 4, d, "main"),
+            Record(12, 1, d + timedelta(hours=3), "main2"),
+            Record(3, 7, d - timedelta(days=3), "main3"),
+            Record(13, 2, d + timedelta(hours=17), "southeastfwd"),
+            Record(3, 6, d - timedelta(days=1), "northwestback"),
+            Record(10, 4, d, "northwestback"),
+            Record(18, 2, d + timedelta(days=23), "not added"),
+            Record(11, 7, d + timedelta(hours=2), "northeastfwd"),
+        ]
+        to_remove = points[4]
+        for point in points:
+            otree.insert(point)
+
+        # TEST: query works before remove
+        q_res = otree.nearby_points(
+            to_remove, dist=0.1, t_dist=timedelta(minutes=5)
+        )
+        assert len(q_res) == 1
+
+        # TEST: point is removed and query fails
+        assert otree.remove(to_remove)
+        q_res = otree.nearby_points(
+            to_remove, dist=0.1, t_dist=timedelta(minutes=5)
+        )
+        assert len(q_res) == 0
+
     def test_query(self):
         d = datetime(2023, 3, 24, 12, 0)
         dt = timedelta(days=10)
diff --git a/test/test_quadtree.py b/test/test_quadtree.py
index 223c892..86a643e 100644
--- a/test/test_quadtree.py
+++ b/test/test_quadtree.py
@@ -103,6 +103,29 @@ class TestQuadTree(unittest.TestCase):
         ]
         assert res == expected
 
+    def test_remove(self):
+        boundary = Rectangle(0, 20, 0, 8)
+        qtree = QuadTree(boundary, capacity=3)
+        points: list[Record] = [
+            Record(10, 5),
+            Record(19, 1),
+            Record(0, 0),
+            Record(-2, -9.2),
+            Record(12.8, 2.1),
+        ]
+        to_remove = points[2]
+        for point in points:
+            qtree.insert(point)
+        q_res = qtree.nearby_points(to_remove, dist=0.1)
+
+        # TEST: get the point
+        assert len(q_res) == 1
+
+        # TEST: Point is removed
+        assert qtree.remove(to_remove)
+        q_res = qtree.nearby_points(to_remove, dist=0.1)
+        assert len(q_res) == 0
+
     def test_query(self):
         boundary = Rectangle(0, 20, 0, 8)
         qtree = QuadTree(boundary, capacity=3)
-- 
GitLab


From 04f2049b1736b6c7b685daee95057ebe8ed05054 Mon Sep 17 00:00:00 2001
From: josidd <joseph.siddons@noc.ac.uk>
Date: Wed, 27 Nov 2024 12:03:23 +0000
Subject: [PATCH 2/2] chore: version

---
 pyproject.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index a9c82cd..9cc4b05 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,7 +12,7 @@ packages = ["GeoSpatialTools"]
 
 [project]
 name = "GeoSpatialTools"
-version = "0.7.1"
+version = "0.8.0"
 dependencies = [
     "numpy",
 ]
-- 
GitLab