From 4369835e8b641f82d426fda584efc667b157a643 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 16 Mar 2025 16:36:49 +0100 Subject: [PATCH] WIP (quad tree) --- src/db/db/dbQuadTree.h | 55 ++++++++++++----- src/db/unit_tests/dbQuadTreeTests.cc | 88 ++++++++++++++++------------ 2 files changed, 90 insertions(+), 53 deletions(-) diff --git a/src/db/db/dbQuadTree.h b/src/db/db/dbQuadTree.h index 546c007ff..31034827f 100644 --- a/src/db/db/dbQuadTree.h +++ b/src/db/db/dbQuadTree.h @@ -30,7 +30,7 @@ namespace db { -template +template class quad_tree_node { public: @@ -137,7 +137,7 @@ public: if (! m_split || n < 0) { for (auto i = m_objects.begin (); i != m_objects.end (); ++i) { - if (*i == value) { + if (CMP () (*i, value)) { m_objects.erase (i); return true; } @@ -290,7 +290,7 @@ private: } box_type b = BC () (value); - if (b.inside (box (ucenter))) { + if (inside (b, box (ucenter))) { int n = quad_for (b); if (n < 0) { @@ -337,7 +337,7 @@ private: coord_type dx = std::max (std::abs (total_box.left () - m_center.x ()), std::abs (total_box.right () - m_center.y ())); coord_type dy = std::max (std::abs (total_box.bottom () - m_center.y ()), std::abs (total_box.top () - m_center.y ())); - return m_center - vector_type (dx, dy); + return m_center - vector_type (dx * 2, dy * 2); } bool check (const point_type &ucenter) const @@ -348,10 +348,15 @@ private: for (auto i = m_objects.begin (); i != m_objects.end (); ++i) { box_type b = BC () (*i); - if (! b.inside (bq)) { + if (! inside (b, bq)) { tl::error << "Box " << b.to_string () << " not inside quad box " << bq.to_string (); result = false; } + if (coord_traits::equal (b.left (), ucenter.x ()) || coord_traits::equal (b.right (), ucenter.x ()) || + coord_traits::equal (b.bottom (), ucenter.y ()) || coord_traits::equal (b.top (), ucenter.y ())) { + tl::error << "Box " << b.to_string () << " touches center of upper-level quad " << ucenter.to_string (); + result = false; + } } if (m_split) { @@ -367,9 +372,11 @@ private: for (unsigned int n = 0; n < 4; ++n) { if (m_q[n]) { - m_q[n]->check (m_center); + if (! m_q[n]->check (m_center)) { + result = false; + } box_type bbq = m_q[n]->box (m_center); - if (bbq != q (n, ucenter)) { + if (! bbq.equal (q (n, ucenter))) { tl::error << "Quad not centered (quad box is " << bbq.to_string () << ", should be " << q (n, ucenter).to_string (); result = false; } @@ -394,13 +401,23 @@ private: return result; } + + static bool inside (const box_type &box, const box_type &in) + { + if (box.empty () || in.empty ()) { + return false; + } else { + return ! coord_traits::less (box.left (), in.left ()) && ! coord_traits::less (in.right (), box.right ()) && + ! coord_traits::less (box.bottom (), in.bottom ()) && ! coord_traits::less (in.top (), box.top ()); + } + } }; -template +template class quad_tree_iterator { public: - typedef quad_tree_node quad_tree_node_type; + typedef quad_tree_node quad_tree_node_type; typedef typename T::coord_type coord_type; typedef db::box box_type; @@ -575,15 +592,23 @@ private: box_type m_box; }; -// @@@ TODO: copy, assignment, move, swap -template +template +struct quad_tree_default_cmp +{ + bool operator() (const T &a, const T &b) const + { + return a == b; + } +}; + +template > class quad_tree { public: - typedef quad_tree_node quad_tree_node_type; - typedef quad_tree_iterator > quad_tree_flat_iterator; - typedef quad_tree_iterator > quad_tree_touching_iterator; - typedef quad_tree_iterator > quad_tree_overlapping_iterator; + typedef quad_tree_node quad_tree_node_type; + typedef quad_tree_iterator > quad_tree_flat_iterator; + typedef quad_tree_iterator > quad_tree_touching_iterator; + typedef quad_tree_iterator > quad_tree_overlapping_iterator; typedef typename T::coord_type coord_type; typedef db::box box_type; typedef db::point point_type; diff --git a/src/db/unit_tests/dbQuadTreeTests.cc b/src/db/unit_tests/dbQuadTreeTests.cc index 1866907d1..c0df73a44 100644 --- a/src/db/unit_tests/dbQuadTreeTests.cc +++ b/src/db/unit_tests/dbQuadTreeTests.cc @@ -28,9 +28,17 @@ #include -typedef db::quad_tree, size_t (1)> my_quad_tree; +struct MyQuadTreeCMP +{ + bool operator() (const db::DBox &a, const db::DBox &b) const + { + return a.equal (b); + } +}; -std::string find_all (const my_quad_tree &qt) +typedef db::quad_tree, size_t (1), MyQuadTreeCMP> MyQuadTree; + +std::string find_all (const MyQuadTree &qt) { std::vector v; auto i = qt.begin (); @@ -42,7 +50,7 @@ std::string find_all (const my_quad_tree &qt) return tl::join (v, "/"); } -std::string find_touching (const my_quad_tree &qt, const db::DBox &box) +std::string find_touching (const MyQuadTree &qt, const db::DBox &box) { std::vector v; auto i = qt.begin_touching (box); @@ -54,7 +62,7 @@ std::string find_touching (const my_quad_tree &qt, const db::DBox &box) return tl::join (v, "/"); } -std::string find_touching_from_all (const my_quad_tree &qt, const db::DBox &box) +std::string find_touching_from_all (const MyQuadTree &qt, const db::DBox &box) { std::vector v; auto i = qt.begin (); @@ -68,7 +76,7 @@ std::string find_touching_from_all (const my_quad_tree &qt, const db::DBox &box) return tl::join (v, "/"); } -std::string find_overlapping (const my_quad_tree &qt, const db::DBox &box) +std::string find_overlapping (const MyQuadTree &qt, const db::DBox &box) { std::vector v; auto i = qt.begin_overlapping (box); @@ -80,7 +88,7 @@ std::string find_overlapping (const my_quad_tree &qt, const db::DBox &box) return tl::join (v, "/"); } -std::string find_overlapping_from_all (const my_quad_tree &qt, const db::DBox &box) +std::string find_overlapping_from_all (const MyQuadTree &qt, const db::DBox &box) { std::vector v; auto i = qt.begin (); @@ -96,7 +104,7 @@ std::string find_overlapping_from_all (const my_quad_tree &qt, const db::DBox &b TEST(basic) { - my_quad_tree tree; + MyQuadTree tree; EXPECT_EQ (tree.empty (), true); EXPECT_EQ (tree.size (), size_t (0)); EXPECT_EQ (tree.check (), true); @@ -174,7 +182,7 @@ TEST(basic) EXPECT_EQ (tree.empty (), false); EXPECT_EQ (tree.size (), size_t (3)); EXPECT_EQ (tree.check (), true); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;3,0)"); @@ -204,7 +212,7 @@ TEST(basic) EXPECT_EQ (tree.empty (), false); EXPECT_EQ (tree.size (), size_t (4)); EXPECT_EQ (tree.check (), true); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); @@ -233,7 +241,7 @@ TEST(basic) TEST(remove) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -260,12 +268,12 @@ TEST(remove) TEST(grow) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); tree.insert (db::DBox (-1, -3, -0.5, 2)); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); tree.insert (db::DBox (-100, -3, -99, 2)); EXPECT_EQ (tree.levels (), size_t (8)); @@ -286,12 +294,12 @@ TEST(grow) TEST(grow2) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); tree.insert (db::DBox (-1, -3, -0.5, 2)); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); tree.insert (db::DBox (-100, -3, -99, -1)); EXPECT_EQ (tree.levels (), size_t (8)); @@ -312,7 +320,7 @@ TEST(grow2) TEST(clear) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -332,7 +340,7 @@ TEST(clear) TEST(copy) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -340,19 +348,19 @@ TEST(copy) EXPECT_EQ (tree.check (), true); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); - my_quad_tree tree2 (tree); + MyQuadTree tree2 (tree); tree.clear (); EXPECT_EQ (tree2.check (), true); EXPECT_EQ (find_all (tree2), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree2.levels (), size_t (2)); + EXPECT_EQ (tree2.levels (), size_t (3)); } TEST(assign) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -360,20 +368,20 @@ TEST(assign) EXPECT_EQ (tree.check (), true); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); - my_quad_tree tree2; + MyQuadTree tree2; tree2 = tree; tree.clear (); EXPECT_EQ (tree2.check (), true); EXPECT_EQ (find_all (tree2), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree2.levels (), size_t (2)); + EXPECT_EQ (tree2.levels (), size_t (3)); } TEST(swap) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -381,9 +389,9 @@ TEST(swap) EXPECT_EQ (tree.check (), true); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); - my_quad_tree tree2; + MyQuadTree tree2; tree2.swap (tree); EXPECT_EQ (tree.check (), true); @@ -393,12 +401,12 @@ TEST(swap) EXPECT_EQ (tree2.check (), true); EXPECT_EQ (find_all (tree2), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree2.levels (), size_t (2)); + EXPECT_EQ (tree2.levels (), size_t (3)); } TEST(move) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -406,9 +414,9 @@ TEST(move) EXPECT_EQ (tree.check (), true); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); - my_quad_tree tree2; + MyQuadTree tree2; tree2 = std::move (tree); EXPECT_EQ (tree.check (), true); @@ -418,12 +426,12 @@ TEST(move) EXPECT_EQ (tree2.check (), true); EXPECT_EQ (find_all (tree2), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree2.levels (), size_t (2)); + EXPECT_EQ (tree2.levels (), size_t (3)); } TEST(move_ctor) { - my_quad_tree tree; + MyQuadTree tree; tree.insert (db::DBox (-1, -2, 3, 4)); tree.insert (db::DBox (-1, -3, 3, 0)); tree.insert (db::DBox (-1, -3, -0.5, -2)); @@ -431,9 +439,9 @@ TEST(move_ctor) EXPECT_EQ (tree.check (), true); EXPECT_EQ (find_all (tree), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree.levels (), size_t (2)); + EXPECT_EQ (tree.levels (), size_t (3)); - my_quad_tree tree2 (std::move (tree)); + MyQuadTree tree2 (std::move (tree)); EXPECT_EQ (tree.check (), true); EXPECT_EQ (tree.empty (), true); @@ -442,7 +450,7 @@ TEST(move_ctor) EXPECT_EQ (tree2.check (), true); EXPECT_EQ (find_all (tree2), "(-1,-2;3,4)/(-1,-3;-0.5,-2)/(-1,-3;-0.5,2)/(-1,-3;3,0)"); - EXPECT_EQ (tree2.levels (), size_t (2)); + EXPECT_EQ (tree2.levels (), size_t (3)); } static double rvalue () @@ -452,13 +460,16 @@ static double rvalue () static db::DBox rbox () { - return db::DBox (db::DPoint (rvalue (), rvalue ()), db::DPoint (rvalue (), rvalue ())); + db::DBox box; + while ((box = db::DBox (db::DPoint (rvalue (), rvalue ()), db::DPoint (rvalue (), rvalue ()))).empty ()) { + ; + } + return box; } TEST(many) { - return; // @@@ - my_quad_tree tree; + MyQuadTree tree; unsigned int n = 1000; @@ -467,6 +478,7 @@ TEST(many) } EXPECT_EQ (tree.check (), true); + EXPECT_EQ (tree.size (), size_t (n)); bool r = true; while (r && ! tree.empty ()) {