mdds
Loading...
Searching...
No Matches
quad_node.hpp
1// SPDX-FileCopyrightText: 2010 - 2025 Kohei Yoshida
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include "mdds/global.hpp"
8
9#include <cassert>
10
11#include <boost/intrusive_ptr.hpp>
12
13namespace mdds {
14
15#ifdef MDDS_DEBUG_NODE_BASE
16size_t node_instance_count = 0;
17inline size_t get_node_instance_count()
18{
19 return node_instance_count;
20}
21#endif
22
28enum node_quadrant_t
29{
30 quad_northeast,
31 quad_northwest,
32 quad_southeast,
33 quad_southwest,
34 quad_unspecified
35};
36
44enum search_region_space_t
45{
46 region_northwest,
47 region_north,
48 region_northeast,
49 region_east,
50 region_southeast,
51 region_south,
52 region_southwest,
53 region_west,
54 region_center
55};
56
66enum direction_t
67{
68 dir_north,
69 dir_west,
70 dir_south,
71 dir_east
72};
73
74inline node_quadrant_t opposite(node_quadrant_t quad)
75{
76 switch (quad)
77 {
78 case quad_northeast:
79 return quad_southwest;
80 case quad_northwest:
81 return quad_southeast;
82 case quad_southeast:
83 return quad_northwest;
84 case quad_southwest:
85 return quad_northeast;
86 case quad_unspecified:
87 default:;
88 }
89 return quad_unspecified;
90}
91
92template<typename _NodePtr, typename _NodeType, typename _Key>
93struct quad_node_base
94{
95 typedef _Key key_type;
96 typedef _NodePtr node_ptr;
97 typedef _NodeType node_type;
98
99 size_t refcount;
100
101 node_ptr parent;
102 node_ptr northeast;
103 node_ptr northwest;
104 node_ptr southeast;
105 node_ptr southwest;
106
107 key_type x;
108 key_type y;
109
110 quad_node_base(key_type _x, key_type _y)
111 : refcount(0), parent(nullptr), northeast(nullptr), northwest(nullptr), southeast(nullptr), southwest(nullptr),
112 x(_x), y(_y)
113 {
114#ifdef MDDS_DEBUG_NODE_BASE
115 ++node_instance_count;
116#endif
117 }
118
123 quad_node_base(const quad_node_base& r)
124 : refcount(0), parent(nullptr), northeast(nullptr), northwest(nullptr), southeast(nullptr), southwest(nullptr),
125 x(r.x), y(r.y)
126 {
127#ifdef MDDS_DEBUG_NODE_BASE
128 ++node_instance_count;
129#endif
130 }
131
132 bool leaf() const
133 {
134 return !northeast && !northwest && !southeast && !southwest;
135 }
136
137 bool operator==(const quad_node_base& r) const
138 {
139 return x == r.x && y == r.y;
140 }
141
145 quad_node_base& operator=(const quad_node_base& r)
146 {
147 if (this == &r)
148 // assignment to self.
149 return *this;
150
151 x = r.x;
152 y = r.y;
153 return *this;
154 }
155
157 {
158#ifdef MDDS_DEBUG_NODE_BASE
159 --node_instance_count;
160#endif
161 static_cast<node_type*>(this)->dispose();
162 }
163
170 node_quadrant_t get_quadrant(key_type other_x, key_type other_y) const
171 {
172 if (other_x < x)
173 // west
174 return other_y < y ? quad_northwest : quad_southwest;
175
176 // east
177 return other_y < y ? quad_northeast : quad_southeast;
178 }
179
180 bool has_quadrant_node(node_quadrant_t quad) const
181 {
182 switch (quad)
183 {
184 case quad_northeast:
185 return northeast.get() != nullptr;
186 case quad_northwest:
187 return northwest.get() != nullptr;
188 case quad_southeast:
189 return southeast.get() != nullptr;
190 case quad_southwest:
191 return southwest.get() != nullptr;
192 default:
193 throw general_error("unknown quadrant type");
194 }
195 return false;
196 }
197
198 node_ptr get_quadrant_node(node_quadrant_t quad) const
199 {
200 node_ptr ret;
201 switch (quad)
202 {
203 case quad_northeast:
204 ret = northeast;
205 break;
206 case quad_northwest:
207 ret = northwest;
208 break;
209 case quad_southeast:
210 ret = southeast;
211 break;
212 case quad_southwest:
213 ret = southwest;
214 break;
215 default:
216 throw general_error("unknown quadrant type");
217 }
218 return ret;
219 }
220};
221
222template<typename _NodePtr, typename _NodeType, typename _Key>
223inline void intrusive_ptr_add_ref(::mdds::quad_node_base<_NodePtr, _NodeType, _Key>* p)
224{
225 ++p->refcount;
226}
227
228template<typename _NodePtr, typename _NodeType, typename _Key>
229inline void intrusive_ptr_release(::mdds::quad_node_base<_NodePtr, _NodeType, _Key>* p)
230{
231 --p->refcount;
232 if (!p->refcount)
233 delete p;
234}
235
236template<typename _NodePtr>
237void disconnect_node_from_parent(_NodePtr p)
238{
239 if (!p || !p->parent)
240 // Nothing to do.
241 return;
242
243 _NodePtr& parent = p->parent;
244 if (parent->northeast && parent->northeast == p)
245 {
246 parent->northeast.reset();
247 }
248 else if (parent->northwest && parent->northwest == p)
249 {
250 parent->northwest.reset();
251 }
252 else if (parent->southwest && parent->southwest == p)
253 {
254 parent->southwest.reset();
255 }
256 else if (parent->southeast && parent->southeast == p)
257 {
258 parent->southeast.reset();
259 }
260 else
261 throw general_error("parent node doesn't lead to the deleted node.");
262}
263
264template<typename _NodePtr>
265void disconnect_all_nodes(_NodePtr p)
266{
267 if (!p)
268 return;
269
270 if (p->northeast)
271 {
272 disconnect_all_nodes(p->northeast);
273 p->northeast.reset();
274 }
275
276 if (p->northwest)
277 {
278 disconnect_all_nodes(p->northwest);
279 p->northwest.reset();
280 }
281
282 if (p->southeast)
283 {
284 disconnect_all_nodes(p->southeast);
285 p->southeast.reset();
286 }
287
288 if (p->southwest)
289 {
290 disconnect_all_nodes(p->southwest);
291 p->southwest.reset();
292 }
293
294 p->parent.reset();
295}
296
297template<typename _NodeType, typename _Key>
298search_region_space_t get_search_region_space(_NodeType* p, _Key x1, _Key y1, _Key x2, _Key y2)
299{
300 typedef _Key key_type;
301
302 key_type x = p->x, y = p->y;
303 if (x < x1)
304 {
305 // western region
306 if (y < y1)
307 {
308 return region_northwest;
309 }
310 else if (y1 <= y && y <= y2)
311 {
312 return region_west;
313 }
314
315 assert(y2 < y);
316 return region_southwest;
317 }
318 else if (x1 <= x && x <= x2)
319 {
320 // central region
321 if (y < y1)
322 {
323 return region_north;
324 }
325 else if (y1 <= y && y <= y2)
326 {
327 return region_center;
328 }
329
330 assert(y2 < y);
331 return region_south;
332 }
333
334 // eastern region
335 assert(x2 < x);
336 if (y < y1)
337 {
338 return region_northeast;
339 }
340 else if (y1 <= y && y <= y2)
341 {
342 return region_east;
343 }
344
345 assert(y2 < y);
346 return region_southeast;
347}
348
349} // namespace mdds
Definition global.hpp:60
Definition quad_node.hpp:94
quad_node_base(const quad_node_base &r)
Definition quad_node.hpp:123
quad_node_base & operator=(const quad_node_base &r)
Definition quad_node.hpp:145
node_quadrant_t get_quadrant(key_type other_x, key_type other_y) const
Definition quad_node.hpp:170