WIP (quad tree)

This commit is contained in:
Matthias Koefferlein 2025-03-16 16:36:49 +01:00
parent f1f35ae2a4
commit 4369835e8b
2 changed files with 90 additions and 53 deletions

View File

@ -30,7 +30,7 @@
namespace db
{
template <class T, class BC, size_t thr>
template <class T, class BC, size_t thr, class CMP>
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 <class T, class BC, size_t thr, class S>
template <class T, class BC, size_t thr, class CMP, class S>
class quad_tree_iterator
{
public:
typedef quad_tree_node<T, BC, thr> quad_tree_node_type;
typedef quad_tree_node<T, BC, thr, CMP> quad_tree_node_type;
typedef typename T::coord_type coord_type;
typedef db::box<coord_type> box_type;
@ -575,15 +592,23 @@ private:
box_type m_box;
};
// @@@ TODO: copy, assignment, move, swap
template <class T, class BC, size_t thr>
template <class T>
struct quad_tree_default_cmp
{
bool operator() (const T &a, const T &b) const
{
return a == b;
}
};
template <class T, class BC, size_t thr, class CMP = quad_tree_default_cmp<T>>
class quad_tree
{
public:
typedef quad_tree_node<T, BC, thr> quad_tree_node_type;
typedef quad_tree_iterator<T, BC, thr, quad_tree_always_sel<T, BC> > quad_tree_flat_iterator;
typedef quad_tree_iterator<T, BC, thr, quad_tree_touching_sel<T, BC> > quad_tree_touching_iterator;
typedef quad_tree_iterator<T, BC, thr, quad_tree_overlapping_sel<T, BC> > quad_tree_overlapping_iterator;
typedef quad_tree_node<T, BC, thr, CMP> quad_tree_node_type;
typedef quad_tree_iterator<T, BC, thr, CMP, quad_tree_always_sel<T, BC> > quad_tree_flat_iterator;
typedef quad_tree_iterator<T, BC, thr, CMP, quad_tree_touching_sel<T, BC> > quad_tree_touching_iterator;
typedef quad_tree_iterator<T, BC, thr, CMP, quad_tree_overlapping_sel<T, BC> > quad_tree_overlapping_iterator;
typedef typename T::coord_type coord_type;
typedef db::box<coord_type> box_type;
typedef db::point<coord_type> point_type;

View File

@ -28,9 +28,17 @@
#include <stdlib.h>
typedef db::quad_tree<db::DBox, db::box_convert<db::DBox>, 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<db::DBox, db::box_convert<db::DBox>, size_t (1), MyQuadTreeCMP> MyQuadTree;
std::string find_all (const MyQuadTree &qt)
{
std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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 ()) {