FlightGear next
QuadTree.hxx
Go to the documentation of this file.
1// QuadTree.hxx - Implimentation of the FlightGear Ground radar
2//
3// Written by Keith Paterson, started Feb 2023.
4//
5// Copyright (C) 2023 Keith Paterson.
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21#pragma once
22#include <simgear/math/SGGeod.hxx>
23#include <simgear/math/SGBox.hxx>
24#include <simgear/math/SGRect.hxx>
25#include <simgear/structure/SGSharedPtr.hxx>
26#include <simgear/debug/logstream.hxx>
27#include <simgear/io/iostreams/sgstream.hxx>
28#include <simgear/structure/exception.hxx>
29#include <simgear/timing/sg_time.hxx>
30
31#include <Main/globals.hxx>
32
33#include <algorithm>
34#include <array>
35#include <type_traits>
36#include <memory>
37#include <vector>
38#include <iostream>
39#include <string>
40
44
45namespace quadtree {
46
48
49template <class T, typename GetBox, typename Equal>
50class Node {
51 private:
52 const std::size_t MAX_DEPTH = 8;
53 const std::size_t SPLIT_THRESHOLD = 10;
54 const std::size_t depth;
55 SGRectd bounds;
56 std::array<std::unique_ptr<quadtree::Node<T,GetBox,Equal>>, 4> children;
57 std::vector<SGSharedPtr<T>> data;
58 const int quadrant;
59 public:
60
61 Node(std::size_t depth, int fQuadtrant): depth(depth), data(), quadrant(fQuadtrant) {
62 }
63
64 size_t size() {
65 if (children[0] == nullptr) {
66 return data.size();
67 } else {
68 int childrenSize = 0;
69 for (auto& n : children) {
70 childrenSize += n->size();
71 }
72 return childrenSize;
73 }
74 }
75
76 bool isLeaf() {return children[0] == nullptr;};
77
78 void resize( const SGRectd& bounds ) {
79 if (data.size()>0) {
80 SG_LOG(SG_ATC, SG_ALERT, "Resizing Quadtree with data not supported");
81 }
82 this->bounds = bounds;
83 SG_LOG(SG_ATC, SG_BULK , "Resizing Quadtree " << quadrant << " to " << bounds.x() << "\t" << bounds.y() << "\t Width : " << bounds.width() << "\t Height : " << bounds.height());
84 }
85
86 bool add(const SGRectd& pos, SGSharedPtr<T> value, const Equal& equalFkt, const GetBox& getBoxFunction)
87 {
88 if (equalFkt==nullptr || getBoxFunction==nullptr) {
89 SG_LOG(SG_ATC, SG_BULK , "equalFkt " << equalFkt << " getBoxFunction " << getBoxFunction);
90 }
91 if (isLeaf())
92 {
93 if (!bounds.contains(pos.x(), pos.y())) {
94 SG_LOG(SG_ATC, SG_ALERT , "Not in node Quadrant " << quadrant << " to bounds " << bounds.x() << "\t" << bounds.y() << "\t" << (bounds.x()+bounds.width()) << "\t" << (bounds.y()+bounds.height()) << "\t Pos : \t" << pos.x() << "\t" << pos.y() );
95 return false;
96 }
97 if (depth >= MAX_DEPTH || data.size() < SPLIT_THRESHOLD) {
98 //
99 if (depth >= MAX_DEPTH) {
100 SG_LOG(SG_ATC, SG_BULK , "Max Depth reached");
101 }
102 //
103 auto it = std::find_if(std::begin(data), std::end(data),
104 [equalFkt, value](auto rhs){ return equalFkt(value, rhs); });
105 if (it == std::end(data)) {
106 data.push_back(value);
107 SG_LOG(SG_ATC, SG_DEBUG , "Added " << value << " to level " << depth << " Size : " << data.size());
108 return true;
109 } else {
110 int sizeBefore = data.size();
111 it = data.erase(it);
112 int sizeBefore2 = data.size();
113 data.push_back(value);
114 int sizeAfter = data.size();
115 SG_LOG(SG_ATC, SG_DEBUG , "Not readded " << value << " to level " << depth << " " << sizeBefore<< " " << sizeBefore2 << " " << sizeAfter);
116 return true;
117 }
118 }
119 else
120 {
121 auto i = split(pos, equalFkt, getBoxFunction);
122 if (i != UNKNOWN) {
123 return children[static_cast<std::size_t>(i)].get()->add(pos, value, equalFkt, getBoxFunction);
124 }
125 else {
126 return false;
127 }
128 }
129 }
130 else
131 {
132 auto i = getQuadrant(bounds, pos);
133 if (i != UNKNOWN) {
134 return children[static_cast<std::size_t>(i)].get()->add(pos, value, equalFkt, getBoxFunction);
135 }
136 else {
137 return false;
138 }
139 }
140 };
141
142 bool move(const SGRectd& newPos, const SGRectd& oldPos, SGSharedPtr<T> value, const Equal& equalFkt, const GetBox& getBoxFunction)
143 {
144 SGRectd realPos = getBoxFunction(value);
145 double dist = SGGeodesy::distanceM(SGGeod::fromDegM(oldPos.y(), oldPos.x(), 0), SGGeod::fromDegM(realPos.y(), realPos.x(), 0) );
146 SG_LOG(SG_ATC, SG_BULK,
147 "Moving " << oldPos.x() << ":" << oldPos.y() << " to " << newPos.x() << ":" << newPos.y() << (isLeaf()?" leaf ":" ") << dist );
148
149
150 // finding
151 if (isLeaf())
152 {
153 auto it = std::find_if(std::begin(data), std::end(data),
154 [equalFkt, value](auto rhs){ return equalFkt(value, rhs); });
155 if (it == std::end(data)) {
156 SG_LOG(SG_ATC, SG_DEBUG , "Trying to move non existant data " << value << " " << data.size() );
157 return false;
158 }
159 // No need to do anything since in same node
160// removeValue(value, equalFkt);
161 return true;
162 }
163 else
164 {
165 auto oldQuadrant = getQuadrant(bounds, oldPos);
166 auto newQuadrant = getQuadrant(bounds, newPos);
167 if (oldQuadrant != UNKNOWN) {
168 if (oldQuadrant != newQuadrant) {
169 SG_LOG(SG_ATC, SG_BULK,
170 "Moving from quadrant " << oldQuadrant << " to quadrant " << newQuadrant << " Level " << depth );
171 bool removed = children[static_cast<std::size_t>(oldQuadrant)].get()->remove(oldPos, value, equalFkt);
172 bool added = children[static_cast<std::size_t>(newQuadrant)].get()->add(newPos, value, equalFkt, getBoxFunction);
173 if (!removed || !added)
174 {
175 SG_LOG(SG_ATC, SG_ALERT,
176 "Error moving " << (removed?" true ":" false ") << (added?" true ":" false "));
177 }
178 return removed && added;
179
180 } else {
181 return children[static_cast<std::size_t>(oldQuadrant)].get()->move(newPos, oldPos, value, equalFkt, getBoxFunction);
182 }
183 } else {
184 SG_LOG(SG_ATC, SG_WARN,
185 "Failed Moving from quadrant " << oldQuadrant << " to quadrant " << newQuadrant << " Level " << depth );
186 }
187 return false;
188 }
189 };
190
191 bool removeValue(SGSharedPtr<T> value, const Equal& equalFkt) {
192 // Find the value in data
193 auto it = std::find_if(std::begin(data), std::end(data),
194 [equalFkt, value](auto rhs){ return equalFkt(value, rhs); });
195 if (it == std::end(data)) {
196 SG_LOG(SG_ATC, SG_DEV_ALERT , "Trying to remove non existant data " << data.size());
197 return false;
198 }
199 // Swap with the last element and pop back
200 it = data.erase(it);
201 return true;
202 }
203
204 bool remove(const SGRectd& pos, SGSharedPtr<T> value, const Equal& equalFunction) {
205 if (isLeaf()) {
206 return removeValue(value, equalFunction);
207 } else {
208 // Remove the value in a child if the value is entirely contained in it
209 auto i = getQuadrant(bounds, pos);
210 SG_LOG(SG_ATC, SG_BULK , "Remove from quadrant " << i << " Depth " << depth);
211 if (i != UNKNOWN) {
212 if (children[static_cast<std::size_t>(i)].get()->remove(computeBox(pos, i), value, equalFunction)) {
213 return tryMerge();
214 } else {
215 bool found = children[static_cast<std::size_t>(i)].get()->findFullScan(value, equalFunction, "Error /");
216 SG_LOG(SG_ATC, SG_DEBUG , "Trying to find misplaced data " << found);
217 }
218 // Otherwise, we remove the value from the current node
219 } else {
220 SG_LOG(SG_ATC, SG_ALERT , "Trying to remove from UNKNOWN non leaf " );
221 return removeValue(value, equalFunction);
222 }
223 return false;
224 }
225 }
226
230
231 bool findFullScan(SGSharedPtr<T> value, const Equal& equalFkt, const std::string& path) {
232 if (isLeaf()) {
233 auto it = std::find_if(std::begin(data), std::end(data),
234 [equalFkt, value](auto rhs){ return equalFkt(value, rhs); });
235 if (it == std::end(data)) {
236// SG_LOG(SG_ATC, SG_ALERT , "Not found " << path << " " );
237 return false;
238 } else {
239 SG_LOG(SG_ATC, SG_DEBUG , "Found in path node " << path << " " );
240 return true;
241 }
242 } else {
243 for (size_t i = 0; i < 4; i++) {
244 std::string subpath = path + std::to_string(i) + "/";
245 bool found = children[static_cast<std::size_t>(i)].get()->findFullScan(value, equalFkt, subpath);
246 if (found) {
247 return true;
248 }
249 }
250 // Not found in a subnode
251 return false;
252 }
253 }
254
258
259 bool removeFullScan(SGSharedPtr<T> value, const Equal& equalFkt, const std::string& path) {
260 if (isLeaf()) {
261 auto it = std::find_if(std::begin(data), std::end(data),
262 [equalFkt, value](auto rhs){ return equalFkt(value, rhs); });
263 if (it == std::end(data)) {
264// SG_LOG(SG_ATC, SG_ALERT , "Not found " << path << " " );
265 return false;
266 } else {
267 SG_LOG(SG_ATC, SG_DEBUG , "Found in path node " << path << " removing " );
268 data.erase(it);
269 return true;
270 }
271 } else {
272 for (size_t i = 0; i < 4; i++) {
273 std::string subpath = path + std::to_string(i) + "/";
274 bool found = children[static_cast<std::size_t>(i)].get()->removeFullScan(value, equalFkt, subpath);
275 if (found) {
276 return true;
277 }
278 }
279 // Not found in a subnode
280 return false;
281 }
282 }
283
284 bool printPath(const SGRectd& pos, SGSharedPtr<T> value, const Equal& equalFkt, const std::string& path) {
285 if (isLeaf()) {
286 SG_LOG(SG_ATC, SG_BULK , path );
287 auto it = std::find_if(std::begin(data), std::end(data),
288 [equalFkt, value](auto rhs){ return equalFkt(value, rhs); });
289 if (it == std::end(data)) {
290 SG_LOG(SG_ATC, SG_DEBUG , "Not found when printing path " << value);
291 return false;
292 } else {
293 return true;
294 }
295 } else {
296 auto i = getQuadrant(bounds, pos);
297 if (i != UNKNOWN) {
298 std::string subpath = path + std::to_string(i) + "/";
299 return children[static_cast<std::size_t>(i)].get()->printPath(computeBox(pos, i), value, equalFkt, subpath);
300 } else {
301 SG_LOG(SG_ATC, SG_ALERT , "Unkown quadrant " );
302 }
303 return false;
304 }
305 }
306
307 bool printPath(const SGRectd& pos, const std::string& path) {
308 if (isLeaf()) {
309 SG_LOG(SG_ATC, SG_DEBUG , path );
310 return true;
311 } else {
312 auto i = getQuadrant(bounds, pos);
313 if (i != UNKNOWN) {
314 std::string subpath = path + std::to_string(i) + "/";
315 return children[static_cast<std::size_t>(i)].get()->printPath(computeBox(pos, i), subpath);
316 } else {
317 SG_LOG(SG_ATC, SG_ALERT , "Unkown quadrant " );
318 }
319 return false;
320 }
321 }
322
323 bool tryMerge() {
324 auto nbValues = size();
325 for (const auto& child : children)
326 {
327 SG_LOG(SG_ATC, SG_DEBUG , "Leaf " << child.get()->isLeaf());
328 /*
329 if (!child.get()->isLeaf())
330 return true;
331 */
332 nbValues += child.get()->size();
333 }
334 SG_LOG(SG_ATC, SG_DEBUG , "Trying to merge Quadtree " << nbValues);
335 return true;
336 }
337
338
339 int split(const SGRectd& pos, const Equal& equalFkt, const GetBox& getBoxFunction) {
340 // Create children
341 SG_LOG(SG_ATC, SG_BULK, "Splitting Quadtree Size : " << data.size() << " Depth : " << depth);
342
343 for (size_t i = 0; i < 4; i++) {
344 children[i] = std::make_unique<Node>(depth+1, i);
345 children[i].get()->resize(computeBox(bounds, i));
346 }
347 // Assign values to children
348 auto newValues = std::vector<SGSharedPtr<T>>(); // New values for this node
349 for (auto value : data)
350 {
351 auto i = getQuadrant(bounds, getBoxFunction(value));
352 if (i != UNKNOWN) {
353 children[static_cast<std::size_t>(i)].get()->add(getBoxFunction(value), value, equalFkt, getBoxFunction);
354 }
355 else {
356 newValues.push_back(value);
357 }
358 }
359 data = std::move(newValues);
360 return getQuadrant(bounds, pos);
361 };
362
363 SGRectd computeBox(const SGRectd& box, int i) const
364 {
365 auto origin = box.getMin();
366 auto childSize = box.size();
367 childSize /= 2.0;
368 switch (i)
369 {
370 case SOUTH_WEST:
371 return SGRectd(SGVec2d(origin.x(), origin.y()), SGVec2d(origin.x() + childSize.x(), origin.y() + childSize.y()));
372 case NORTH_WEST:
373 return SGRectd(SGVec2d(origin.x(), origin.y() + childSize.y()), SGVec2d(origin.x() + childSize.x(), origin.y() + 2*childSize.y()));
374 case SOUTH_EAST:
375 return SGRectd(SGVec2d(origin.x() + childSize.x(), origin.y()), SGVec2d(origin.x() + 2*childSize.x(), origin.y() + childSize.y()));
376 case NORTH_EAST:
377 return SGRectd(SGVec2d(origin.x() + childSize.x(), origin.y() + childSize.y()), SGVec2d(origin.x() + 2*childSize.x(), origin.y() + 2*childSize.y()));
378 default:
379 assert(false && "Invalid quadrant index");
380 return SGRectd();
381 }
382 };
383
384 SGRectd computeBoxCenter(const SGRectd& box, int i) const
385 {
386 auto origin = box.getMin();
387 auto childSize = box.size();
388 childSize /= 4.0;
389 switch (i)
390 {
391 case SOUTH_WEST:
392 return SGRectd(SGVec2d(origin.x() + childSize.x(), origin.y() + childSize.y()), SGVec2d(origin.x() + childSize.x(), origin.y() + childSize.y()));
393 case NORTH_WEST:
394 return SGRectd(SGVec2d(origin.x() + childSize.x(), origin.y() + 3*childSize.y()), SGVec2d(origin.x() + childSize.x(), origin.y() + 3*childSize.y()));
395 case SOUTH_EAST:
396 return SGRectd(SGVec2d(origin.x() + 3*childSize.x(), origin.y() + childSize.y()), SGVec2d(origin.x() + 3*childSize.x(), origin.y() + childSize.y()));
397 case NORTH_EAST:
398 return SGRectd(SGVec2d(origin.x() + 3*childSize.x(), origin.y() + 3*childSize.y()), SGVec2d(origin.x() + 3*childSize.x(), origin.y() + 3*childSize.y()));
399 default:
400 assert(false && "Invalid quadrant index");
401 return SGRectd();
402 }
403 };
404
405 void query(const SGRectd& queryBox, const GetBox& getBoxFunction, std::vector<SGSharedPtr<T>>& values)
406 {
407 SG_LOG(SG_ATC, SG_BULK, "Query Quadtree " << queryBox.getMin().x() << "\t" << queryBox.getMin().y() << "\t"
408 << queryBox.getMax().x() << "\t" << queryBox.getMax().y()
409 << " depth " << depth << " Leaf : " << (isLeaf()?"true":"false"));
410 for (auto value : data)
411 {
412 auto pos = getBoxFunction(value);
413 SG_LOG(SG_ATC, SG_BULK, "Query Quadtree " << pos.x() << "\t" << pos.y());
414 if (queryBox.contains(pos.x(), pos.y())) {
415 values.push_back(value);
416 }
417 }
418 if (!isLeaf())
419 {
420 if (children.size()!=4) {
421 SG_LOG(SG_ATC, SG_ALERT, "Wrong Box Size" );
422 }
423 for (auto i = std::size_t(0); i < children.size(); i++)
424 {
425 auto childBox = computeBox(bounds, static_cast<int>(i));
426 SG_LOG(SG_ATC, SG_BULK, "Query Quadtree center " << i << "\t" << childBox.x() << "\t" << childBox.y() << "\t" << childBox.width() << "\t" << childBox.height() );
427 if (intersection(queryBox, childBox)) {
428 children[i].get()->query(queryBox, getBoxFunction, values);
429 } else {
430 SG_LOG(SG_ATC, SG_BULK, "Query Quadtree center " << i << " not found " );
431 SG_LOG(SG_ATC, SG_BULK, "QueryBox " << queryBox.getMin().x() << "," << queryBox.getMin().y() << "\t" << queryBox.getMax().x() << "," << queryBox.getMax().y() );
432 SG_LOG(SG_ATC, SG_BULK, "ChildBox " << childBox.getMin().x() << "," << childBox.getMin().y() << "\t" << childBox.getMax().x() << "," << childBox.getMax().y() );
433 SG_LOG(SG_ATC, SG_BULK, "MinMax " << ((childBox.getMax().y() > queryBox.getMin().y())?"true":"false"));
434 }
435 }
436 }
437 };
438
439
440 Quadrant getQuadrant(const SGRectd& nodeBox, const SGRectd& valueBox) const
441 {
442 auto center = nodeBox.getMin();
443 // West
444 if (valueBox.x() < nodeBox.x() + nodeBox.width()/2)
445 {
446 if (valueBox.y() < nodeBox.y() + nodeBox.height()/2)
447 return SOUTH_WEST;
448 else if (valueBox.y() + valueBox.height() >= nodeBox.y() + nodeBox.height()/2)
449 return NORTH_WEST;
450 // Not contained in any quadrant
451 else
452 return UNKNOWN;
453 }
454 // East
455 else if (valueBox.x() >= nodeBox.x() + nodeBox.width()/2)
456 {
457 if (valueBox.y() < nodeBox.y() + nodeBox.height()/2)
458 return SOUTH_EAST;
459 else if (valueBox.y() + valueBox.height() >= nodeBox.y() + nodeBox.height()/2)
460 return NORTH_EAST;
461 // Not contained in any quadrant
462 else
463 return UNKNOWN;
464 }
465 // Not contained in any quadrant
466 else
467 return UNKNOWN;
468 };
469
470 SGRectd getBounds() {
471 return bounds;
472 };
473
474 bool intersection(const SGRectd& firstBox, const SGRectd& secondBox) {
475 return firstBox.getMax().x() > secondBox.getMin().x() &&
476 firstBox.getMin().x() < secondBox.getMax().x() &&
477 firstBox.getMax().y() > secondBox.getMin().y() &&
478 firstBox.getMin().y() < secondBox.getMax().y();
479 };
480
481 void dumpGeoJson(const std::unique_ptr<sg_ofstream>& o, const SGRectd& box) {
482 (*o) << ",{ \"type\": \"Feature\"," << std::endl;
483 (*o) << "\"properties\": {}," << std::endl;
484 (*o) << " \"geometry\": { \"type\": \"Polygon\"," << std::endl;
485 (*o) << "\"coordinates\": [ [" << std::endl;
486 (*o) << "[" << box.getMin().y() << "," << box.getMin().x() << "]," << std::endl;
487 (*o) << "[" << box.getMax().y() << "," << box.getMin().x() << "]," << std::endl;
488 (*o) << "[" << box.getMax().y() << "," << box.getMax().x() << "]," << std::endl;
489 (*o) << "[" << box.getMin().y() << "," << box.getMax().x() << "]," << std::endl;
490 (*o) << "[" << box.getMin().y() << "," << box.getMin().x() << "]]]" << std::endl;
491 (*o) << "}}" << std::endl;
492 };
493
494 void dumpGeoJson(const std::unique_ptr<sg_ofstream>& o, const GetBox& getBoxFunction) {
495 (*o) << "{ \"type\": \"Feature\"," << std::endl;
496 (*o) << "\"properties\": {}," << std::endl;
497 (*o) << " \"geometry\": { \"type\": \"Polygon\"," << std::endl;
498 (*o) << "\"coordinates\": [ [" << std::endl;
499 (*o) << "[" << bounds.getMin().y() << "," << bounds.getMin().x() << "]," << std::endl;
500 (*o) << "[" << bounds.getMax().y() << "," << bounds.getMin().x() << "]," << std::endl;
501 (*o) << "[" << bounds.getMax().y() << "," << bounds.getMax().x() << "]," << std::endl;
502 (*o) << "[" << bounds.getMin().y() << "," << bounds.getMax().x() << "]," << std::endl;
503 (*o) << "[" << bounds.getMin().y() << "," << bounds.getMin().x() << "]]]" << std::endl;
504 (*o) << "}}" << std::endl;
505 if (isLeaf()) {
506 for (const auto& node : data)
507 {
508 (*o) << ",";
509 (*o) << "{ \"type\": \"Feature\","<< std::endl;
510 (*o) << "\"properties\": { \"id\": \"" << node << "\"}," << std::endl;
511 (*o) << " \"geometry\": { \"type\": \"Point\"," << std::endl;
512 (*o) << "\"coordinates\": " << std::endl;
513 auto coords = getBoxFunction(node);
514 (*o) << "[" << coords.getMin().y() << "," << coords.getMin().x() << "]" << std::endl;
515 (*o) << "}}" << std::endl;
516 }
517
518 } else {
519 for (const auto& child : children)
520 {
521 (*o) << "," << std::endl;
522 child.get()->dumpGeoJson(o, getBoxFunction);
523 }
524 }
525 };
526};
527
528template <class T, typename GetBox, typename Equal>
529class QuadTree {
530 private:
531 std::unique_ptr<quadtree::Node<T, GetBox, Equal>> rootNode;
532 SGRectd rootRect;
533 GetBox getBoxFunction;
534 Equal equalFunction;
535 std::unique_ptr<sg_ofstream> geoJsonFile;
536 public:
537 QuadTree(const GetBox& getBox,
538 const Equal& equal
539 ): rootNode(std::make_unique<quadtree::Node<T,GetBox, Equal>>(0, UNKNOWN)), getBoxFunction(getBox), equalFunction(equal),
540 geoJsonFile{std::make_unique<sg_ofstream>()}
541 {}
542
543 void exportJson(const SGRectd& bounds) {
544 char fname[160];
545 time_t t = time(0); // get time now
546 snprintf(fname, sizeof(fname), "%ld_%f.json", t, globals->get_sim_time_sec());
547 SG_LOG(SG_ATC, SG_ALERT , "Exported " << fname );
548
549 SGPath p = globals->get_download_dir() / fname;
550 geoJsonFile->open(p);
551 (*geoJsonFile) << "{ \"type\": \"FeatureCollection\", \"features\": [";
552 rootNode.get()->dumpGeoJson(geoJsonFile, getBoxFunction);
553 rootNode.get()->dumpGeoJson(geoJsonFile, bounds);
554 (*geoJsonFile) << "]}";
555 geoJsonFile->close();
556 }
557
558 void resize( const SGRectd& bounds ) {
559 rootNode.get()->resize(bounds);
560 }
561
562 bool add(SGSharedPtr<T> value)
563 {
564 if (rootNode.get()!=nullptr) {
565 SGRectd pos = getBoxFunction(value);
566 SGRectd bounds = rootNode.get()->getBounds();
567 if (!bounds.contains(pos.x(), pos.y())) {
568 SG_LOG(SG_ATC, SG_DEV_ALERT , "Not in index Bounds : " << bounds.x() << "x" << bounds.y() << "\t" << (bounds.x()+bounds.width()) << "x" << (bounds.y()+bounds.height()) << value << " Pos : " << pos );
569 return false;
570 }
571 bool ret = rootNode.get()->add(getBoxFunction(value), value, equalFunction, getBoxFunction);
572 if (ret) {
573 bool printed = printPath(value);
574 if (!printed) {
575 SG_LOG(SG_ATC, SG_ALERT , "Not printed " << value );
576 }
577 } else {
578 SG_LOG(SG_ATC, SG_ALERT , "Not added " << value );
579 }
580// exportJson();
581 return ret;
582 }
583 return false;
584 }
585
586 bool move(const SGRectd& newPos, SGSharedPtr<T> value)
587 {
588 /*
589 bool found = rootNode.get()->printPath(getBoxFunction(value), value, equalFunction, "Start/");
590 if (!found) {
591 rootNode.get()->findFullScan(value, equalFunction, "Error/");
592 }
593 */
594 bool moved = rootNode.get()->move(newPos, getBoxFunction(value), value, equalFunction, getBoxFunction);
595 if(!moved) {
596 bool found = rootNode.get()->printPath(getBoxFunction(value), value, equalFunction, "Start/");
597
598 if (!found) {
599 rootNode.get()->printPath(getBoxFunction(value), "Error/");
600 rootNode.get()->findFullScan(value, equalFunction, "Error/");
601 }
602 bool removed = rootNode.get()->removeFullScan(value, equalFunction, "Error/");
603 if (!removed) {
604 SG_LOG(SG_ATC, SG_ALERT , "Not removed " << value);
605 rootNode.get()->findFullScan(value, equalFunction, "Error/");
606 }
607 return rootNode.get()->add(getBoxFunction(value), value, equalFunction, getBoxFunction);
608 }
609 /*
610 rootNode.get()->printPath(newPos, value, equalFunction, "End/");
611 */
612// exportJson();
613 return moved;
614 }
615
616 bool remove(SGSharedPtr<T> value)
617 {
618 if (value==nullptr) {
619 return false;
620 }
621 return rootNode.get()->remove(getBoxFunction(value), value, equalFunction);
622 }
623
624 bool printPath(SGSharedPtr<T> value)
625 {
626 return rootNode.get()->printPath(getBoxFunction(value), value, equalFunction, "/");
627 }
628
629 void query(SGSharedPtr<T> value, std::vector<SGSharedPtr<T>>& values)
630 {
631 return rootNode.get()->query(getBoxFunction(value), getBoxFunction, values);
632 }
633
634 void query(const SGRectd& queryBox, std::vector<SGSharedPtr<T>>& values)
635 {
636 return rootNode.get()->query(queryBox, getBoxFunction, values);
637 }
638
639 size_t size() const {return rootNode.get()->size();}
640};
641}
642
643
#define p(x)
#define i(x)
QuadTree(const GetBox &getBox, const Equal &equal)
Definition QuadTree.hxx:537
bool add(const SGRectd &pos, SGSharedPtr< T > value, const Equal &equalFkt, const GetBox &getBoxFunction)
Definition QuadTree.hxx:86
bool printPath(const SGRectd &pos, const std::string &path)
Definition QuadTree.hxx:307
Quadrant getQuadrant(const SGRectd &nodeBox, const SGRectd &valueBox) const
Definition QuadTree.hxx:440
bool remove(const SGRectd &pos, SGSharedPtr< T > value, const Equal &equalFunction)
Definition QuadTree.hxx:204
void dumpGeoJson(const std::unique_ptr< sg_ofstream > &o, const GetBox &getBoxFunction)
Definition QuadTree.hxx:494
SGRectd computeBoxCenter(const SGRectd &box, int i) const
Definition QuadTree.hxx:384
int split(const SGRectd &pos, const Equal &equalFkt, const GetBox &getBoxFunction)
Definition QuadTree.hxx:339
bool removeValue(SGSharedPtr< T > value, const Equal &equalFkt)
Definition QuadTree.hxx:191
Node(std::size_t depth, int fQuadtrant)
Definition QuadTree.hxx:61
size_t size()
Definition QuadTree.hxx:64
SGRectd getBounds()
Definition QuadTree.hxx:470
void dumpGeoJson(const std::unique_ptr< sg_ofstream > &o, const SGRectd &box)
Definition QuadTree.hxx:481
bool intersection(const SGRectd &firstBox, const SGRectd &secondBox)
Definition QuadTree.hxx:474
bool findFullScan(SGSharedPtr< T > value, const Equal &equalFkt, const std::string &path)
For debugging.
Definition QuadTree.hxx:231
bool printPath(const SGRectd &pos, SGSharedPtr< T > value, const Equal &equalFkt, const std::string &path)
Definition QuadTree.hxx:284
bool removeFullScan(SGSharedPtr< T > value, const Equal &equalFkt, const std::string &path)
For debugging.
Definition QuadTree.hxx:259
SGRectd computeBox(const SGRectd &box, int i) const
Definition QuadTree.hxx:363
bool move(const SGRectd &newPos, const SGRectd &oldPos, SGSharedPtr< T > value, const Equal &equalFkt, const GetBox &getBoxFunction)
Definition QuadTree.hxx:142
void resize(const SGRectd &bounds)
Definition QuadTree.hxx:78
void query(const SGRectd &queryBox, const GetBox &getBoxFunction, std::vector< SGSharedPtr< T > > &values)
Definition QuadTree.hxx:405
void exportJson(const SGRectd &bounds)
Definition QuadTree.hxx:543
void query(const SGRectd &queryBox, std::vector< SGSharedPtr< T > > &values)
Definition QuadTree.hxx:634
bool move(const SGRectd &newPos, SGSharedPtr< T > value)
Definition QuadTree.hxx:586
bool printPath(SGSharedPtr< T > value)
Definition QuadTree.hxx:624
void resize(const SGRectd &bounds)
Definition QuadTree.hxx:558
bool remove(SGSharedPtr< T > value)
Definition QuadTree.hxx:616
QuadTree(const GetBox &getBox, const Equal &equal)
Definition QuadTree.hxx:537
void query(SGSharedPtr< T > value, std::vector< SGSharedPtr< T > > &values)
Definition QuadTree.hxx:629
size_t size() const
Definition QuadTree.hxx:639
bool add(SGSharedPtr< T > value)
Definition QuadTree.hxx:562
FGGlobals * globals
Definition globals.cxx:142
Class .
Definition QuadTree.hxx:45