mdds
Loading...
Searching...
No Matches
point_quad_tree.hpp
1// SPDX-FileCopyrightText: 2010 - 2025 Kohei Yoshida
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include "mdds/quad_node.hpp"
8
9#include <cstdlib>
10#include <cassert>
11#include <iostream>
12#include <fstream>
13#include <string>
14#include <vector>
15#include <memory>
16
17#define DEBUG_POINT_QUAD_TREE 0
18
19namespace mdds {
20
21template<typename _PairType>
22void ensure_order(_PairType& v)
23{
24 if (v.first > v.second)
25 ::std::swap(v.first, v.second);
26}
27
28template<typename _Key, typename _NodeType, typename _Inserter>
29void search_region_node(const _NodeType* p, _Key x1, _Key y1, _Key x2, _Key y2, _Inserter& result)
30{
31 using namespace std;
32
33 if (!p)
34 return;
35
36 search_region_space_t region = ::mdds::get_search_region_space(p, x1, y1, x2, y2);
37
38 switch (region)
39 {
40 case region_center:
41 result(p);
42 search_region_node(p->northeast.get(), x1, y1, x2, y2, result);
43 search_region_node(p->northwest.get(), x1, y1, x2, y2, result);
44 search_region_node(p->southeast.get(), x1, y1, x2, y2, result);
45 search_region_node(p->southwest.get(), x1, y1, x2, y2, result);
46 break;
47 case region_east:
48 search_region_node(p->northwest.get(), x1, y1, x2, y2, result);
49 search_region_node(p->southwest.get(), x1, y1, x2, y2, result);
50 break;
51 case region_north:
52 search_region_node(p->southeast.get(), x1, y1, x2, y2, result);
53 search_region_node(p->southwest.get(), x1, y1, x2, y2, result);
54 break;
55 case region_northeast:
56 search_region_node(p->southwest.get(), x1, y1, x2, y2, result);
57 break;
58 case region_northwest:
59 search_region_node(p->southeast.get(), x1, y1, x2, y2, result);
60 break;
61 case region_south:
62 search_region_node(p->northeast.get(), x1, y1, x2, y2, result);
63 search_region_node(p->northwest.get(), x1, y1, x2, y2, result);
64 break;
65 case region_southeast:
66 search_region_node(p->northwest.get(), x1, y1, x2, y2, result);
67 break;
68 case region_southwest:
69 search_region_node(p->northeast.get(), x1, y1, x2, y2, result);
70 break;
71 case region_west:
72 search_region_node(p->northeast.get(), x1, y1, x2, y2, result);
73 search_region_node(p->southeast.get(), x1, y1, x2, y2, result);
74 break;
75 default:
76 throw general_error("unknown search region");
77 }
78}
79
80template<typename _Key, typename _Value>
81class point_quad_tree
82{
83private:
84 class search_result_inserter;
85
86public:
87 typedef _Key key_type;
88 typedef _Value value_type;
89 typedef size_t size_type;
90 typedef ::std::vector<value_type> data_array_type;
91
92 class data_not_found : public ::std::exception
93 {
94 };
95
96private:
97 struct node;
98 typedef ::boost::intrusive_ptr<node> node_ptr;
99
100 struct node : quad_node_base<node_ptr, node, key_type>
101 {
102 value_type data;
103 node(key_type _x, key_type _y, value_type _data) : quad_node_base<node_ptr, node, key_type>(_x, _y), data(_data)
104 {}
105
106 node(const node& r) : quad_node_base<node_ptr, node, key_type>(r), data(r.data)
107 {}
108
109 void dispose()
110 {}
111
112 bool operator==(const node& r) const
113 {
114 return quad_node_base<node_ptr, node, key_type>::operator==(r) && data == r.data;
115 }
116
117 node& operator=(const node& r)
118 {
120 data = r.data;
121 return *this;
122 }
123 };
124
125 typedef ::std::vector<node_ptr> reinsert_tree_array_type;
126 typedef ::std::pair<key_type, key_type> key_range_type;
127
128public:
133 class node_access
134 {
135 friend class point_quad_tree<_Key, _Value>;
136
137 public:
138 node_access northeast() const
139 {
140 return node_access(mp->northeast.get());
141 }
142 node_access northwest() const
143 {
144 return node_access(mp->northwest.get());
145 }
146 node_access southeast() const
147 {
148 return node_access(mp->southeast.get());
149 }
150 node_access southwest() const
151 {
152 return node_access(mp->southwest.get());
153 }
154
155 value_type data() const
156 {
157 return mp->data;
158 }
159 key_type x() const
160 {
161 return mp->x;
162 }
163 key_type y() const
164 {
165 return mp->y;
166 }
167
168 operator bool() const
169 {
170 return mp != nullptr;
171 }
172 bool operator==(const node_access& r) const
173 {
174 return mp == r.mp;
175 }
176
177 node_access() : mp(nullptr)
178 {}
179 ~node_access()
180 {}
181
182 private:
183 node_access(const node* p) : mp(p)
184 {}
185
186 private:
187 const node* mp;
188 };
189
190 struct point
191 {
192 key_type x;
193 key_type y;
194 point(key_type _x, key_type _y) : x(_x), y(_y)
195 {}
196 point() : x(0), y(0)
197 {}
198 };
199
200 class search_results
201 {
202 friend class search_result_inserter;
203
204 using res_nodes_type = std::vector<const node*>;
205 using res_nodes_ptr = std::shared_ptr<res_nodes_type>;
206
207 public:
208 class const_iterator
209 {
210 friend class point_quad_tree<_Key, _Value>::search_results;
211 typedef typename point_quad_tree<_Key, _Value>::point point;
212 typedef typename point_quad_tree<_Key, _Value>::value_type parent_value_type;
213
214 public:
215 // Iterator traits
216 typedef std::pair<point, parent_value_type> value_type;
217 typedef value_type* pointer;
218 typedef value_type& reference;
219 typedef ptrdiff_t difference_type;
220 typedef ::std::bidirectional_iterator_tag iterator_category;
221
222 const_iterator(res_nodes_ptr& ptr) : mp_res_nodes(ptr), m_end_pos(false)
223 {}
224
225 const_iterator(const const_iterator& r)
226 : mp_res_nodes(r.mp_res_nodes), m_cur_pos(r.m_cur_pos), m_cur_value(r.m_cur_value),
227 m_end_pos(r.m_end_pos)
228 {}
229
230 const_iterator& operator=(const const_iterator& r)
231 {
232 mp_res_nodes = r.mp_res_nodes;
233 m_cur_pos = r.m_cur_pos;
234 m_cur_value = r.m_cur_value;
235 m_end_pos = r.m_end_pos;
236 return *this;
237 }
238
239 bool operator==(const const_iterator& r) const
240 {
241 if (mp_res_nodes)
242 {
243 // Non-empty result set.
244 return mp_res_nodes.get() == r.mp_res_nodes.get() && m_cur_pos == r.m_cur_pos &&
245 m_end_pos == r.m_end_pos;
246 }
247
248 // Empty result set.
249 if (r.mp_res_nodes)
250 return false;
251
252 return m_end_pos == r.m_end_pos;
253 }
254
255 bool operator!=(const const_iterator& r) const
256 {
257 return !operator==(r);
258 }
259
260 const value_type& operator*() const
261 {
262 return m_cur_value;
263 }
264
265 const value_type* operator->() const
266 {
267 return get_current_value();
268 }
269
270 const value_type* operator++()
271 {
272 // The only difference between the last data position and the
273 // end iterator position must be the value of m_end_pos;
274 // m_cur_pos needs to point to the last data position even
275 // when the iterator is at the end-of-iterator position.
276
277 typename res_nodes_type::const_iterator cur_pos = m_cur_pos;
278 if (++cur_pos == mp_res_nodes->end())
279 {
280 m_end_pos = true;
281 return nullptr;
282 }
283 m_cur_pos = cur_pos;
284 update_current_value();
285 return operator->();
286 }
287
288 const value_type* operator--()
289 {
290 if (m_end_pos)
291 {
292 m_end_pos = false;
293 return get_current_value();
294 }
295 --m_cur_pos;
296 update_current_value();
297 return get_current_value();
298 }
299
300 private:
301 void move_to_front()
302 {
303 if (!mp_res_nodes)
304 {
305 // Empty data set.
306 m_end_pos = true;
307 return;
308 }
309
310 m_cur_pos = mp_res_nodes->begin();
311 m_end_pos = false;
312 update_current_value();
313 }
314
315 void move_to_end()
316 {
317 m_end_pos = true;
318 if (!mp_res_nodes)
319 // Empty data set.
320 return;
321
322 m_cur_pos = mp_res_nodes->end();
323 --m_cur_pos; // Keep the position at the last data position.
324 }
325
326 void update_current_value()
327 {
328 const node* p = *m_cur_pos;
329 m_cur_value.first = point(p->x, p->y);
330 m_cur_value.second = p->data;
331 }
332
333 const value_type* get_current_value() const
334 {
335 return &m_cur_value;
336 }
337
338 private:
339 res_nodes_ptr mp_res_nodes;
340 typename res_nodes_type::const_iterator m_cur_pos;
341 value_type m_cur_value;
342 bool m_end_pos : 1;
343 };
344
345 search_results() = default;
346 search_results(const search_results& other) = default;
347 search_results(search_results&& other) = default;
348 search_results& operator=(const search_results& other) = default;
349 search_results& operator=(search_results&& other) = default;
350
351 typename search_results::const_iterator begin()
352 {
353 typename search_results::const_iterator itr(mp_res_nodes);
354 itr.move_to_front();
355 return itr;
356 }
357
358 typename search_results::const_iterator end()
359 {
360 typename search_results::const_iterator itr(mp_res_nodes);
361 itr.move_to_end();
362 return itr;
363 }
364
365 private:
366 void push_back(const node* p)
367 {
368 if (!mp_res_nodes)
369 mp_res_nodes.reset(new res_nodes_type);
370 mp_res_nodes->push_back(p);
371 }
372
373 private:
374 res_nodes_ptr mp_res_nodes;
375 };
376
377 point_quad_tree();
378 point_quad_tree(const point_quad_tree& r);
379 ~point_quad_tree();
380
389 void insert(key_type x, key_type y, value_type data);
390
403 void search_region(key_type x1, key_type y1, key_type x2, key_type y2, data_array_type& result) const;
404
418 search_results search_region(key_type x1, key_type y1, key_type x2, key_type y2) const;
419
430 value_type find(key_type x, key_type y) const;
431
439 void remove(key_type x, key_type y);
440
446 void swap(point_quad_tree& r);
447
451 void clear();
452
458 bool empty() const;
459
465 size_t size() const;
466
472 node_access get_node_access() const;
473
474 point_quad_tree& operator=(const point_quad_tree& r);
475
476 bool operator==(const point_quad_tree& r) const;
477
478 bool operator!=(const point_quad_tree& r) const
479 {
480 return !operator==(r);
481 }
482
483#ifdef MDDS_UNIT_TEST
484public:
485#else
486private:
487#endif
492 struct node_data
493 {
494 key_type x;
495 key_type y;
496 value_type data;
497 node_data(key_type _x, key_type _y, value_type _data) : x(_x), y(_y), data(_data)
498 {}
499 node_data(const node_data& r) : x(r.x), y(r.y), data(r.data)
500 {}
501
502 bool operator==(const node_data& r) const
503 {
504 return (x == r.x) && (y == r.y) && (data == r.data);
505 }
506
507 bool operator!=(const node_data& r) const
508 {
509 return !operator==(r);
510 }
511
512 struct sorter
513 {
514 bool operator()(const node_data& left, const node_data& right) const
515 {
516 if (left.x != right.x)
517 return left.x < right.x;
518 if (left.y != right.y)
519 return left.y < right.y;
520 return left.data < right.data;
521 }
522 };
523 };
524
525 static bool equals(::std::vector<node_data>& v1, ::std::vector<node_data>& v2);
526
527 bool verify_data(::std::vector<node_data>& expected) const;
528
529 bool verify_node_iterator(const node_access& nac) const;
530 static bool verify_node_iterator(const node_access& nac, const node* p);
531
532 void get_all_stored_data(::std::vector<node_data>& stored_data) const;
533
534 void dump_tree_svg(const ::std::string& fpath) const;
535
536private:
537 class array_inserter
538 {
539 public:
540 array_inserter(data_array_type& result) : m_result(result)
541 {}
542
543 void operator()(const node* p)
544 {
545 m_result.push_back(p->data);
546 }
547
548 private:
549 data_array_type& m_result;
550 };
551
552 class search_result_inserter
553 {
554 public:
555 search_result_inserter(search_results& result) : m_result(result)
556 {}
557
558 void operator()(const node* p)
559 {
560 m_result.push_back(p);
561 }
562
563 private:
564 search_results& m_result;
565 };
566
567 class data_inserter
568 {
569 public:
570 data_inserter(point_quad_tree& db) : m_db(db)
571 {}
572
573 void operator()(const node_data& v)
574 {
575 m_db.insert(v.x, v.y, v.data);
576 }
577
578 private:
579 point_quad_tree& m_db;
580 };
581
582 struct node_distance
583 {
584 node_quadrant_t quad;
585 key_type dist;
586 node_ptr node;
587
588 node_distance() : quad(quad_unspecified), dist(0), node(nullptr)
589 {}
590 node_distance(node_quadrant_t _quad, key_type _dist, const node_ptr& _node)
591 : quad(_quad), dist(_dist), node(_node)
592 {}
593 };
594
595 node_ptr find_node(key_type x, key_type y) const;
596 const node* find_node_ptr(key_type x, key_type y) const;
597 node_ptr find_replacement_node(key_type x, key_type y, const node_ptr& delete_node) const;
598
599 void find_candidate_in_quad(
600 key_type x, key_type y, node_distance& dx_node, node_distance& dy_node, node_distance& min_city_block_node,
601 const node_ptr& delete_node, node_quadrant_t quad) const;
602
603 void adjust_quad(
604 const key_range_type& hatched_xrange, const key_range_type& hatched_yrange, node_ptr quad_root, direction_t dir,
605 reinsert_tree_array_type& insert_list);
606
607 void set_new_root(
608 const key_range_type& hatched_xrange, const key_range_type& hatched_yrange, node_ptr& quad_root,
609 node_quadrant_t dir, reinsert_tree_array_type& insert_list);
610
611 void insert_node(node_ptr& dest, node_ptr& node);
612 void reinsert_tree(node_ptr& dest, node_ptr& root);
613 void reinsert_tree(node_ptr& dest, node_quadrant_t quad, node_ptr& root);
614 void clear_all_nodes();
615 void dump_node_svg(const node* p, ::std::ofstream& file) const;
616 void count_all_nodes(const node* p, size_t& node_count) const;
617 void insert_data_from(const point_quad_tree& r);
618 void get_all_stored_data(const node* p, ::std::vector<node_data>& stored_data) const;
619
620private:
621 node_ptr m_root;
622
623 key_range_type m_xrange;
624 key_range_type m_yrange;
625};
626
627template<typename _Key, typename _Value>
628point_quad_tree<_Key, _Value>::point_quad_tree() : m_root(nullptr), m_xrange(0, 0), m_yrange(0, 0)
629{}
630
631template<typename _Key, typename _Value>
632point_quad_tree<_Key, _Value>::point_quad_tree(const point_quad_tree& r)
633 : m_root(nullptr), m_xrange(0, 0), m_yrange(0, 0)
634{
635 insert_data_from(r);
636}
637
638template<typename _Key, typename _Value>
639point_quad_tree<_Key, _Value>::~point_quad_tree()
640{
641 clear_all_nodes();
642}
643
644template<typename _Key, typename _Value>
645void point_quad_tree<_Key, _Value>::insert(key_type x, key_type y, value_type data)
646{
647 m_xrange.first = ::std::min(m_xrange.first, x);
648 m_xrange.second = ::std::max(m_xrange.second, x);
649 m_yrange.first = ::std::min(m_yrange.first, y);
650 m_yrange.second = ::std::max(m_yrange.second, y);
651
652 if (!m_root)
653 {
654 // The very first node.
655 m_root.reset(new node(x, y, data));
656 return;
657 }
658
659 node_ptr cur_node = m_root;
660 while (true)
661 {
662 if (cur_node->x == x && cur_node->y == y)
663 {
664 // Replace the current data with this, and we are done!
665 cur_node->data = data;
666 return;
667 }
668
669 node_quadrant_t quad = cur_node->get_quadrant(x, y);
670 switch (quad)
671 {
672 case quad_northeast:
673 if (cur_node->northeast)
674 cur_node = cur_node->northeast;
675 else
676 {
677 cur_node->northeast.reset(new node(x, y, data));
678 cur_node->northeast->parent = cur_node;
679 return;
680 }
681 break;
682 case quad_northwest:
683 if (cur_node->northwest)
684 cur_node = cur_node->northwest;
685 else
686 {
687 cur_node->northwest.reset(new node(x, y, data));
688 cur_node->northwest->parent = cur_node;
689 return;
690 }
691 break;
692 case quad_southeast:
693 if (cur_node->southeast)
694 cur_node = cur_node->southeast;
695 else
696 {
697 cur_node->southeast.reset(new node(x, y, data));
698 cur_node->southeast->parent = cur_node;
699 return;
700 }
701 break;
702 case quad_southwest:
703 if (cur_node->southwest)
704 cur_node = cur_node->southwest;
705 else
706 {
707 cur_node->southwest.reset(new node(x, y, data));
708 cur_node->southwest->parent = cur_node;
709 return;
710 }
711 break;
712 default:
713 throw general_error("unknown quadrant");
714 }
715 }
716 assert(!"This should never be reached.");
717}
718
719template<typename _Key, typename _Value>
721 key_type x1, key_type y1, key_type x2, key_type y2, data_array_type& result) const
722{
723 using namespace std;
724 const node* p = m_root.get();
725 array_inserter _inserter(result);
726 ::mdds::search_region_node(p, x1, y1, x2, y2, _inserter);
727}
728
729template<typename _Key, typename _Value>
731 key_type x1, key_type y1, key_type x2, key_type y2) const
732{
733 using namespace std;
734 search_results result;
735 const node* p = m_root.get();
736 search_result_inserter _inserter(result);
737 ::mdds::search_region_node(p, x1, y1, x2, y2, _inserter);
738 return result;
739}
740
741template<typename _Key, typename _Value>
742typename point_quad_tree<_Key, _Value>::value_type point_quad_tree<_Key, _Value>::find(key_type x, key_type y) const
743{
744 const node* p = find_node_ptr(x, y);
745 if (!p)
746 throw data_not_found();
747 return p->data;
748}
749
750template<typename _Key, typename _Value>
751void point_quad_tree<_Key, _Value>::remove(key_type x, key_type y)
752{
753 using namespace std;
754 node_ptr delete_node = find_node(x, y);
755 if (!delete_node)
756 // No node exists at this coordinate.
757 return;
758
759#if DEBUG_POINT_QUAD_TREE
760 cout << "found the node to be removed at " << delete_node->x << "," << delete_node->y << " (" << *delete_node->data
761 << ")" << endl;
762#endif
763
764 // Check if this is a leaf node, in which case we can just delete it
765 // without further processing.
766 if (delete_node->leaf())
767 {
768#if DEBUG_POINT_QUAD_TREE
769 cout << "deleting a leaf node." << endl;
770#endif
771 if (delete_node.get() == m_root.get())
772 m_root.reset();
773 else
774 disconnect_node_from_parent(delete_node);
775 delete_node.reset();
776 return;
777 }
778
779 node_ptr repl_node = find_replacement_node(x, y, delete_node);
780 if (!repl_node)
781 // Non-leaf node should have at least one replacement candidate.
782 throw general_error("failed to find a replacement candidate node.");
783
784 node_quadrant_t repl_quad = delete_node->get_quadrant(repl_node->x, repl_node->y);
785
786 key_range_type xrange(delete_node->x, repl_node->x);
787 key_range_type yrange(delete_node->y, repl_node->y);
788 ensure_order(xrange);
789 ensure_order(yrange);
790 reinsert_tree_array_type insert_list;
791
792 // Call the quadrant where the replacement node is quadrant I. Adjust the
793 // quadrants adjacent to quadrant I first, then adjust quadrant I
794 // afterwards.
795 switch (repl_quad)
796 {
797 case quad_northeast:
798 adjust_quad(xrange, yrange, delete_node->northwest, dir_south, insert_list);
799 adjust_quad(xrange, yrange, delete_node->southeast, dir_west, insert_list);
800 set_new_root(xrange, yrange, delete_node->northeast, quad_southwest, insert_list);
801 break;
802 case quad_northwest:
803 adjust_quad(xrange, yrange, delete_node->northeast, dir_south, insert_list);
804 adjust_quad(xrange, yrange, delete_node->southwest, dir_east, insert_list);
805 set_new_root(xrange, yrange, delete_node->northwest, quad_southeast, insert_list);
806 break;
807 case quad_southeast:
808 adjust_quad(xrange, yrange, delete_node->northeast, dir_west, insert_list);
809 adjust_quad(xrange, yrange, delete_node->southwest, dir_north, insert_list);
810 set_new_root(xrange, yrange, delete_node->southeast, quad_northwest, insert_list);
811 break;
812 case quad_southwest:
813 adjust_quad(xrange, yrange, delete_node->northwest, dir_east, insert_list);
814 adjust_quad(xrange, yrange, delete_node->southeast, dir_north, insert_list);
815 set_new_root(xrange, yrange, delete_node->southwest, quad_northeast, insert_list);
816 break;
817 default:
818 throw general_error("quadrant for the replacement node is unspecified.");
819 }
820
821 // Reinsert all child nodes from the replacement node into the node to be
822 // "deleted".
823 switch (repl_quad)
824 {
825 case quad_northeast:
826 case quad_southwest:
827 {
828 node_ptr root = repl_node->northwest;
829 repl_node->northwest.reset();
830 reinsert_tree(delete_node, quad_northwest, root);
831
832 root = repl_node->southeast;
833 repl_node->southeast.reset();
834 reinsert_tree(delete_node, quad_southeast, root);
835 }
836 break;
837 case quad_northwest:
838 case quad_southeast:
839 {
840 node_ptr root = repl_node->northeast;
841 repl_node->northeast.reset();
842 reinsert_tree(delete_node, quad_northeast, root);
843
844 root = repl_node->southwest;
845 repl_node->southwest.reset();
846 reinsert_tree(delete_node, quad_southwest, root);
847 }
848 break;
849 default:
850 throw general_error("quadrant for the replacement node is unspecified.");
851 }
852
853 // Finally, replace the node to be removed with the replacement node.
854 delete_node->x = repl_node->x;
855 delete_node->y = repl_node->y;
856 delete_node->data = repl_node->data;
857
858 // Reset the parent node.
859 delete_node->parent = repl_node->parent;
860 repl_node->parent.reset();
861
862 switch (repl_quad)
863 {
864 case quad_northeast:
865 delete_node->northeast = repl_node->northeast;
866 repl_node->northeast.reset();
867 break;
868 case quad_northwest:
869 delete_node->northwest = repl_node->northwest;
870 repl_node->northwest.reset();
871 break;
872 case quad_southeast:
873 delete_node->southeast = repl_node->southeast;
874 repl_node->southeast.reset();
875 break;
876 case quad_southwest:
877 delete_node->southwest = repl_node->southwest;
878 repl_node->southwest.reset();
879 break;
880 default:
881 throw general_error("quadrant for the replacement node is unspecified.");
882 }
883
884 // Lastly, re-insert all those trees that have been cut during the quad
885 // adjustment into the new root.
886 typename reinsert_tree_array_type::iterator itr = insert_list.begin(), itr_end = insert_list.end();
887 for (; itr != itr_end; ++itr)
888 reinsert_tree(delete_node, *itr);
889}
890
891template<typename _Key, typename _Value>
893{
894 m_root.swap(r.m_root);
895 ::std::swap(m_xrange, r.m_xrange);
896 ::std::swap(m_yrange, r.m_yrange);
897}
898
899template<typename _Key, typename _Value>
901{
902 clear_all_nodes();
903}
904
905template<typename _Key, typename _Value>
907{
908 return (m_root.get() == nullptr);
909}
910
911template<typename _Key, typename _Value>
913{
914 size_t node_count = 0;
915 count_all_nodes(m_root.get(), node_count);
916 return node_count;
917}
918
919template<typename _Key, typename _Value>
924
925template<typename _Key, typename _Value>
926point_quad_tree<_Key, _Value>& point_quad_tree<_Key, _Value>::operator=(const point_quad_tree& r)
927{
928 m_xrange = key_range_type(0, 0);
929 m_yrange = key_range_type(0, 0);
930 clear_all_nodes();
931 insert_data_from(r);
932 return *this;
933}
934
935template<typename _Key, typename _Value>
936bool point_quad_tree<_Key, _Value>::operator==(const point_quad_tree& r) const
937{
938 ::std::vector<node_data> v1, v2;
939 get_all_stored_data(v1);
940 r.get_all_stored_data(v2);
941 return equals(v1, v2);
942}
943
944template<typename _Key, typename _Value>
945void point_quad_tree<_Key, _Value>::dump_tree_svg(const ::std::string& fpath) const
946{
947 using namespace std;
948 ofstream file(fpath.c_str());
949 file << "<svg width=\"60cm\" height=\"60cm\" viewBox=\"-2 -2 202 202\" xmlns=\"http://www.w3.org/2000/svg\" "
950 "version=\"1.1\">"
951 << endl;
952 file << "<defs>"
953 << " <marker id=\"Triangle\""
954 << " viewBox=\"0 0 10 10\" refX=\"10\" refY=\"5\" "
955 << " markerUnits=\"strokeWidth\""
956 << " markerWidth=\"9\" markerHeight=\"6\""
957 << " orient=\"auto\">"
958 << " <path d=\"M 0 0 L 10 5 L 0 10 z\" />"
959 << " </marker>"
960 << "</defs>" << endl;
961
962 file << "<path d=\"M 0 0 L 0 " << m_yrange.second + 1
963 << "\" stroke=\"blue\" stroke-width=\"0.2\" marker-end=\"url(#Triangle)\"/>" << endl;
964 file << "<path d=\"M 0 0 L " << m_xrange.second + 1
965 << " 0\" stroke=\"blue\" stroke-width=\"0.2\" marker-end=\"url(#Triangle)\"/>" << endl;
966 dump_node_svg(m_root.get(), file);
967 file << "</svg>" << endl;
968}
969
970template<typename _NodePtr>
971void draw_svg_arrow(::std::ofstream& file, const _NodePtr start, const _NodePtr end)
972{
973 using namespace std;
974 file << "<g stroke=\"red\" marker-end=\"url(#Triangle)\">" << endl;
975 file << "<line x1=\"" << start->x << "\" y1=\"" << start->y << "\" x2=\"" << end->x << "\" y2=\"" << end->y
976 << "\" stroke-width=\"0.2\"/>" << endl;
977 file << "</g>" << endl;
978}
979
980template<typename _Key, typename _Value>
981void point_quad_tree<_Key, _Value>::dump_node_svg(const node* p, ::std::ofstream& file) const
982{
983 using namespace std;
984
985 if (!p)
986 return;
987
988 file << "<circle cx=\"" << p->x << "\" cy=\"" << p->y << "\" r=\"0.1\""
989 << " fill=\"black\" stroke=\"black\"/>" << endl;
990 file << "<text x=\"" << p->x + 1 << "\" y=\"" << p->y + 2 << "\" font-size=\"1.2\" fill=\"black\">" << *p->data
991 << " (" << p->x << "," << p->y << ")</text>" << endl;
992
993 if (p->northwest)
994 draw_svg_arrow<const node*>(file, p, p->northwest.get());
995
996 if (p->northeast)
997 draw_svg_arrow<const node*>(file, p, p->northeast.get());
998
999 if (p->southwest)
1000 draw_svg_arrow<const node*>(file, p, p->southwest.get());
1001
1002 if (p->southeast)
1003 draw_svg_arrow<const node*>(file, p, p->southeast.get());
1004
1005 dump_node_svg(p->northeast.get(), file);
1006 dump_node_svg(p->northwest.get(), file);
1007 dump_node_svg(p->southeast.get(), file);
1008 dump_node_svg(p->southwest.get(), file);
1009}
1010
1011template<typename _Key, typename _Value>
1012bool point_quad_tree<_Key, _Value>::equals(::std::vector<node_data>& v1, ::std::vector<node_data>& v2)
1013{
1014 using namespace std;
1015
1016 if (v1.size() != v2.size())
1017 return false;
1018
1019 sort(v1.begin(), v1.end(), typename node_data::sorter());
1020 sort(v2.begin(), v2.end(), typename node_data::sorter());
1021
1022 typename vector<node_data>::const_iterator itr1 = v1.begin(), itr1_end = v1.end(), itr2 = v2.begin(),
1023 itr2_end = v2.end();
1024
1025 for (; itr1 != itr1_end; ++itr1, ++itr2)
1026 {
1027 if (itr2 == itr2_end)
1028 return false;
1029
1030 if (*itr1 != *itr2)
1031 return false;
1032 }
1033 if (itr2 != itr2_end)
1034 return false;
1035
1036 return true;
1037}
1038
1039template<typename _Key, typename _Value>
1040void point_quad_tree<_Key, _Value>::get_all_stored_data(::std::vector<node_data>& stored_data) const
1041{
1042 stored_data.clear();
1043 if (!m_root)
1044 return;
1045
1046 get_all_stored_data(m_root.get(), stored_data);
1047}
1048
1049template<typename _Key, typename _Value>
1050void point_quad_tree<_Key, _Value>::count_all_nodes(const node* p, size_t& node_count) const
1051{
1052 if (!p)
1053 return;
1054
1055 ++node_count;
1056
1057 count_all_nodes(p->northeast.get(), node_count);
1058 count_all_nodes(p->northwest.get(), node_count);
1059 count_all_nodes(p->southeast.get(), node_count);
1060 count_all_nodes(p->southwest.get(), node_count);
1061}
1062
1063template<typename _Key, typename _Value>
1064void point_quad_tree<_Key, _Value>::insert_data_from(const point_quad_tree& r)
1065{
1066 using namespace std;
1067 vector<node_data> all_data;
1068 r.get_all_stored_data(all_data);
1069 for_each(all_data.begin(), all_data.end(), data_inserter(*this));
1070}
1071
1072template<typename _Key, typename _Value>
1073bool point_quad_tree<_Key, _Value>::verify_data(::std::vector<node_data>& expected) const
1074{
1075 ::std::vector<node_data> stored;
1076 get_all_stored_data(stored);
1077 return equals(stored, expected);
1078}
1079
1080template<typename _Key, typename _Value>
1081bool point_quad_tree<_Key, _Value>::verify_node_iterator(const node_access& nac) const
1082{
1083 return verify_node_iterator(nac, m_root.get());
1084}
1085
1086template<typename _Key, typename _Value>
1087bool point_quad_tree<_Key, _Value>::verify_node_iterator(const node_access& nac, const node* p)
1088{
1089 if (!nac)
1090 return (p == nullptr);
1091
1092 if (!p)
1093 return false;
1094
1095 if (!verify_node_iterator(nac.northeast(), p->northeast.get()))
1096 return false;
1097 if (!verify_node_iterator(nac.northwest(), p->northwest.get()))
1098 return false;
1099 if (!verify_node_iterator(nac.southeast(), p->southeast.get()))
1100 return false;
1101 if (!verify_node_iterator(nac.southwest(), p->southwest.get()))
1102 return false;
1103
1104 return true;
1105}
1106
1107template<typename _Key, typename _Value>
1108void point_quad_tree<_Key, _Value>::get_all_stored_data(const node* p, ::std::vector<node_data>& stored_data) const
1109{
1110 if (!p)
1111 return;
1112
1113 stored_data.push_back(node_data(p->x, p->y, p->data));
1114
1115 get_all_stored_data(p->northeast.get(), stored_data);
1116 get_all_stored_data(p->northwest.get(), stored_data);
1117 get_all_stored_data(p->southeast.get(), stored_data);
1118 get_all_stored_data(p->southwest.get(), stored_data);
1119}
1120
1121template<typename _Key, typename _Value>
1122typename point_quad_tree<_Key, _Value>::node_ptr point_quad_tree<_Key, _Value>::find_node(key_type x, key_type y) const
1123{
1124 node_ptr cur_node = m_root;
1125 while (cur_node)
1126 {
1127 if (cur_node->x == x && cur_node->y == y)
1128 {
1129 // Found the node.
1130 return cur_node;
1131 }
1132
1133 node_quadrant_t quad = cur_node->get_quadrant(x, y);
1134 switch (quad)
1135 {
1136 case quad_northeast:
1137 if (!cur_node->northeast)
1138 return node_ptr();
1139 cur_node = cur_node->northeast;
1140 break;
1141 case quad_northwest:
1142 if (!cur_node->northwest)
1143 return node_ptr();
1144 cur_node = cur_node->northwest;
1145 break;
1146 case quad_southeast:
1147 if (!cur_node->southeast)
1148 return node_ptr();
1149 cur_node = cur_node->southeast;
1150 break;
1151 case quad_southwest:
1152 if (!cur_node->southwest)
1153 return node_ptr();
1154 cur_node = cur_node->southwest;
1155 break;
1156 default:
1157 throw general_error("unknown quadrant");
1158 }
1159 }
1160 return node_ptr();
1161}
1162
1163template<typename _Key, typename _Value>
1164const typename point_quad_tree<_Key, _Value>::node* point_quad_tree<_Key, _Value>::find_node_ptr(
1165 key_type x, key_type y) const
1166{
1167 const node* cur_node = m_root.get();
1168 while (cur_node)
1169 {
1170 if (cur_node->x == x && cur_node->y == y)
1171 {
1172 // Found the node.
1173 return cur_node;
1174 }
1175
1176 node_quadrant_t quad = cur_node->get_quadrant(x, y);
1177 switch (quad)
1178 {
1179 case quad_northeast:
1180 if (!cur_node->northeast)
1181 return nullptr;
1182 cur_node = cur_node->northeast.get();
1183 break;
1184 case quad_northwest:
1185 if (!cur_node->northwest)
1186 return nullptr;
1187 cur_node = cur_node->northwest.get();
1188 break;
1189 case quad_southeast:
1190 if (!cur_node->southeast)
1191 return nullptr;
1192 cur_node = cur_node->southeast.get();
1193 break;
1194 case quad_southwest:
1195 if (!cur_node->southwest)
1196 return nullptr;
1197 cur_node = cur_node->southwest.get();
1198 break;
1199 default:
1200 throw general_error("unknown quadrant");
1201 }
1202 }
1203 return nullptr;
1204}
1205
1206template<typename _Key, typename _Value>
1207typename point_quad_tree<_Key, _Value>::node_ptr point_quad_tree<_Key, _Value>::find_replacement_node(
1208 key_type x, key_type y, const node_ptr& delete_node) const
1209{
1210 using namespace std;
1211
1212 // Try to get a replacement candidate in each quadrant.
1213 node_distance dx_node, dy_node, min_city_block_node;
1214
1215#if DEBUG_POINT_QUAD_TREE
1216 cout << "northeast" << endl;
1217#endif
1218 find_candidate_in_quad(x, y, dx_node, dy_node, min_city_block_node, delete_node, quad_northeast);
1219
1220#if DEBUG_POINT_QUAD_TREE
1221 cout << "northwest" << endl;
1222#endif
1223 find_candidate_in_quad(x, y, dx_node, dy_node, min_city_block_node, delete_node, quad_northwest);
1224
1225#if DEBUG_POINT_QUAD_TREE
1226 cout << "southwest" << endl;
1227#endif
1228 find_candidate_in_quad(x, y, dx_node, dy_node, min_city_block_node, delete_node, quad_southwest);
1229
1230#if DEBUG_POINT_QUAD_TREE
1231 cout << "southeast" << endl;
1232#endif
1233 find_candidate_in_quad(x, y, dx_node, dy_node, min_city_block_node, delete_node, quad_southeast);
1234
1235 // Check Criterion 1.
1236
1237#if DEBUG_POINT_QUAD_TREE
1238 if (dx_node.node)
1239 cout << "node closest to x axis: " << *dx_node.node->data << " (dx=" << dx_node.dist << ")" << endl;
1240
1241 if (dy_node.node)
1242 cout << "node closest to y axis: " << *dy_node.node->data << " (dy=" << dy_node.dist << ")" << endl;
1243#endif
1244
1245 if (dx_node.node == dy_node.node && ((dx_node.quad == quad_northwest) || (dx_node.quad == quad_southeast)))
1246 {
1247#if DEBUG_POINT_QUAD_TREE
1248 cout << "node that satisfies Criterion 1: " << *dx_node.node->data << endl;
1249#endif
1250 return dx_node.node;
1251 }
1252 else
1253 {
1254#if DEBUG_POINT_QUAD_TREE
1255 cout << "unable to find node that satisfies Criterion 1." << endl;
1256#endif
1257 }
1258
1259 // Move on to Criterion 2.
1260
1261 if (min_city_block_node.node)
1262 {
1263#if DEBUG_POINT_QUAD_TREE
1264 cout << "node that satisfies Criterion 2: " << *min_city_block_node.node->data
1265 << " (dist=" << min_city_block_node.dist << ")" << endl;
1266#endif
1267 return min_city_block_node.node;
1268 }
1269
1270 return node_ptr();
1271}
1272
1273template<typename _Key, typename _Value>
1274void point_quad_tree<_Key, _Value>::find_candidate_in_quad(
1275 key_type x, key_type y, node_distance& dx_node, node_distance& dy_node, node_distance& min_city_block_node,
1276 const node_ptr& delete_node, node_quadrant_t quad) const
1277{
1278 using namespace std;
1279
1280 node_ptr repl_node = delete_node->get_quadrant_node(quad);
1281 if (!repl_node)
1282 {
1283 // No candidate in this quadrant.
1284#if DEBUG_POINT_QUAD_TREE
1285 cout << " no candidate in this quadrant" << endl;
1286#endif
1287 return;
1288 }
1289
1290 node_quadrant_t oppo_quad = opposite(quad);
1291 while (repl_node->has_quadrant_node(oppo_quad))
1292 repl_node = repl_node->get_quadrant_node(oppo_quad);
1293
1294#if DEBUG_POINT_QUAD_TREE
1295 cout << " candidate: " << repl_node->x << "," << repl_node->y << " (" << *repl_node->data << ")" << endl;
1296#endif
1297
1298 // Calculate its distance to each of the borders.
1299 key_type dx = repl_node->x > x ? repl_node->x - x : x - repl_node->x;
1300 key_type dy = repl_node->y > y ? repl_node->y - y : y - repl_node->y;
1301#if DEBUG_POINT_QUAD_TREE
1302 cout << " dx = " << dx << ", dy = " << dy << endl;
1303#endif
1304
1305 if (!dx_node.node || dx_node.dist > dx)
1306 dx_node = node_distance(quad, dx, repl_node);
1307 if (!dy_node.node || dy_node.dist > dy)
1308 dy_node = node_distance(quad, dy, repl_node);
1309
1310 if (!min_city_block_node.node || min_city_block_node.dist > (dx + dy))
1311 min_city_block_node = node_distance(quad_unspecified, dx + dy, repl_node);
1312}
1313
1314template<typename _Key, typename _Value>
1315void point_quad_tree<_Key, _Value>::adjust_quad(
1316 const key_range_type& hatched_xrange, const key_range_type& hatched_yrange, node_ptr quad_root, direction_t dir,
1317 reinsert_tree_array_type& insert_list)
1318{
1319 using namespace std;
1320
1321 if (!quad_root)
1322 return;
1323
1324#if DEBUG_POINT_QUAD_TREE
1325 cout << "adjust_quad: checking " << *quad_root->data << " (" << quad_root->x << "," << quad_root->y << ")" << endl;
1326#endif
1327
1328 if ((hatched_xrange.first <= quad_root->x && quad_root->x <= hatched_xrange.second) ||
1329 (hatched_yrange.first <= quad_root->y && quad_root->y <= hatched_yrange.second))
1330 {
1331#if DEBUG_POINT_QUAD_TREE
1332 cout << " " << *quad_root->data << " is in the hatched region" << endl;
1333#endif
1334 // Insert the whole tree, including the root, into the insert list.
1335 disconnect_node_from_parent(quad_root);
1336 quad_root->parent.reset();
1337 insert_list.push_back(quad_root);
1338 return;
1339 }
1340
1341 switch (dir)
1342 {
1343 case dir_east:
1344 adjust_quad(hatched_xrange, hatched_yrange, quad_root->northeast, dir_east, insert_list);
1345 adjust_quad(hatched_xrange, hatched_yrange, quad_root->southeast, dir_east, insert_list);
1346 break;
1347 case dir_north:
1348 adjust_quad(hatched_xrange, hatched_yrange, quad_root->northeast, dir_north, insert_list);
1349 adjust_quad(hatched_xrange, hatched_yrange, quad_root->northwest, dir_north, insert_list);
1350 break;
1351 case dir_south:
1352 adjust_quad(hatched_xrange, hatched_yrange, quad_root->southeast, dir_south, insert_list);
1353 adjust_quad(hatched_xrange, hatched_yrange, quad_root->southwest, dir_south, insert_list);
1354 break;
1355 case dir_west:
1356 adjust_quad(hatched_xrange, hatched_yrange, quad_root->northwest, dir_west, insert_list);
1357 adjust_quad(hatched_xrange, hatched_yrange, quad_root->southwest, dir_west, insert_list);
1358 break;
1359 default:;
1360 }
1361}
1362
1363template<typename _Key, typename _Value>
1364void point_quad_tree<_Key, _Value>::set_new_root(
1365 const key_range_type& hatched_xrange, const key_range_type& hatched_yrange, node_ptr& quad_root,
1366 node_quadrant_t dir, reinsert_tree_array_type& insert_list)
1367{
1368 node_ptr cur_node = quad_root;
1369 while (cur_node)
1370 {
1371 switch (dir)
1372 {
1373 case quad_northeast:
1374 adjust_quad(hatched_xrange, hatched_yrange, cur_node->southeast, dir_east, insert_list);
1375 adjust_quad(hatched_xrange, hatched_yrange, cur_node->northwest, dir_north, insert_list);
1376 break;
1377 case quad_northwest:
1378 adjust_quad(hatched_xrange, hatched_yrange, cur_node->northeast, dir_north, insert_list);
1379 adjust_quad(hatched_xrange, hatched_yrange, cur_node->southwest, dir_west, insert_list);
1380 break;
1381 case quad_southeast:
1382 adjust_quad(hatched_xrange, hatched_yrange, cur_node->northeast, dir_east, insert_list);
1383 adjust_quad(hatched_xrange, hatched_yrange, cur_node->southwest, dir_south, insert_list);
1384 break;
1385 case quad_southwest:
1386 adjust_quad(hatched_xrange, hatched_yrange, cur_node->northwest, dir_west, insert_list);
1387 adjust_quad(hatched_xrange, hatched_yrange, cur_node->southeast, dir_south, insert_list);
1388 break;
1389 default:
1390 throw general_error("unspecified quadrant");
1391 }
1392 cur_node = cur_node->get_quadrant_node(dir);
1393 }
1394}
1395
1396template<typename _Key, typename _Value>
1397void point_quad_tree<_Key, _Value>::insert_node(node_ptr& dest, node_ptr& this_node)
1398{
1399 node_ptr cur_node = dest;
1400 while (true)
1401 {
1402 if (cur_node->x == this_node->x && cur_node->y == this_node->y)
1403 {
1404 // When inserting a node instance directly (likely as part of tree
1405 // re-insertion), we are not supposed to have another node at
1406 // identical position.
1407 throw general_error("node with identical position encountered.");
1408 }
1409
1410 node_quadrant_t quad = cur_node->get_quadrant(this_node->x, this_node->y);
1411 switch (quad)
1412 {
1413 case quad_northeast:
1414 if (cur_node->northeast)
1415 cur_node = cur_node->northeast;
1416 else
1417 {
1418 cur_node->northeast = this_node;
1419 this_node->parent = cur_node;
1420 return;
1421 }
1422 break;
1423 case quad_northwest:
1424 if (cur_node->northwest)
1425 cur_node = cur_node->northwest;
1426 else
1427 {
1428 cur_node->northwest = this_node;
1429 this_node->parent = cur_node;
1430 return;
1431 }
1432 break;
1433 case quad_southeast:
1434 if (cur_node->southeast)
1435 cur_node = cur_node->southeast;
1436 else
1437 {
1438 cur_node->southeast = this_node;
1439 this_node->parent = cur_node;
1440 return;
1441 }
1442 break;
1443 case quad_southwest:
1444 if (cur_node->southwest)
1445 cur_node = cur_node->southwest;
1446 else
1447 {
1448 cur_node->southwest = this_node;
1449 this_node->parent = cur_node;
1450 return;
1451 }
1452 break;
1453 default:
1454 throw general_error("unknown quadrant");
1455 }
1456 }
1457 assert(!"This should never be reached.");
1458}
1459
1460template<typename _Key, typename _Value>
1461void point_quad_tree<_Key, _Value>::reinsert_tree(node_ptr& dest, node_ptr& root)
1462{
1463 assert(dest); // Destination node should not be null.
1464
1465 if (!root)
1466 // Nothing to re-insert. Bail out.
1467 return;
1468
1469 if (root->northeast)
1470 {
1471 reinsert_tree(dest, root->northeast);
1472 root->northeast.reset();
1473 }
1474 if (root->northwest)
1475 {
1476 reinsert_tree(dest, root->northwest);
1477 root->northwest.reset();
1478 }
1479 if (root->southeast)
1480 {
1481 reinsert_tree(dest, root->southeast);
1482 root->southeast.reset();
1483 }
1484 if (root->southwest)
1485 {
1486 reinsert_tree(dest, root->southwest);
1487 root->southwest.reset();
1488 }
1489
1490 root->parent.reset();
1491 insert_node(dest, root);
1492}
1493
1494template<typename _Key, typename _Value>
1495void point_quad_tree<_Key, _Value>::reinsert_tree(node_ptr& dest, node_quadrant_t quad, node_ptr& root)
1496{
1497 if (!root)
1498 // Nothing to re-insert. Bail out.
1499 return;
1500
1501 switch (quad)
1502 {
1503 case quad_northeast:
1504 if (dest->northeast)
1505 reinsert_tree(dest->northeast, root);
1506 else
1507 {
1508 dest->northeast = root;
1509 root->parent = dest;
1510 }
1511 break;
1512 case quad_northwest:
1513 if (dest->northwest)
1514 reinsert_tree(dest->northwest, root);
1515 else
1516 {
1517 dest->northwest = root;
1518 root->parent = dest;
1519 }
1520 break;
1521 case quad_southeast:
1522 if (dest->southeast)
1523 reinsert_tree(dest->southeast, root);
1524 else
1525 {
1526 dest->southeast = root;
1527 root->parent = dest;
1528 }
1529 break;
1530 case quad_southwest:
1531 if (dest->southwest)
1532 reinsert_tree(dest->southwest, root);
1533 else
1534 {
1535 dest->southwest = root;
1536 root->parent = dest;
1537 }
1538 break;
1539 default:
1540 throw general_error("reinsert_tree: quadrant unspecified");
1541 }
1542}
1543
1544template<typename _Key, typename _Value>
1545void point_quad_tree<_Key, _Value>::clear_all_nodes()
1546{
1547 ::mdds::disconnect_all_nodes(m_root);
1548 m_root.reset();
1549}
1550
1551} // namespace mdds
Definition global.hpp:60
Definition point_quad_tree.hpp:93
Definition point_quad_tree.hpp:134
Definition point_quad_tree.hpp:201
search_results search_region(key_type x1, key_type y1, key_type x2, key_type y2) const
Definition point_quad_tree.hpp:730
void insert(key_type x, key_type y, value_type data)
Definition point_quad_tree.hpp:645
void swap(point_quad_tree &r)
Definition point_quad_tree.hpp:892
bool empty() const
Definition point_quad_tree.hpp:906
size_t size() const
Definition point_quad_tree.hpp:912
void search_region(key_type x1, key_type y1, key_type x2, key_type y2, data_array_type &result) const
Definition point_quad_tree.hpp:720
void clear()
Definition point_quad_tree.hpp:900
void remove(key_type x, key_type y)
Definition point_quad_tree.hpp:751
node_access get_node_access() const
Definition point_quad_tree.hpp:920
value_type find(key_type x, key_type y) const
Definition point_quad_tree.hpp:742
Definition point_quad_tree.hpp:513
Definition quad_node.hpp:94
quad_node_base & operator=(const quad_node_base &r)
Definition quad_node.hpp:145