Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/router/KDTreePartition.h
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file KDTreePartition.h
15
/// @author Ruediger Ebendt
16
/// @date 01.11.2023
17
///
18
// Class for partitioning the router's network's nodes wrt a k-d tree subdivision scheme.
19
// All nodes are inserted at once at creation. Offers an O(log n) method to search a
20
// node within the bottom / leaf cells (i.e., the cell containing the respective node
21
// is returned). Here, n denotes the number of cells.
22
/****************************************************************************/
23
#pragma once
24
#include <config.h>
25
#include <vector>
26
#include <unordered_set>
27
#include <math.h>
28
#include <cmath>
29
#include <limits>
30
#include <stdexcept>
31
#include <string>
32
#include <cinttypes>
33
#include <utility>
34
35
#define KDTP_EXCLUDE_INTERNAL_EDGES
36
// Use KDTP_KEEP_OUTGOING_BOUNDARY_EDGES and KDTP_KEEP_BOUNDARY_FROM_NODES on a reversed graph to build arc infos
37
// for the arc flag shortest path routing algorithm
38
#define KDTP_KEEP_OUTGOING_BOUNDARY_EDGES
39
// Use KDTP_KEEP_INCOMING_BOUNDARY_EDGES on a forward graph to apply arc flag shortest path routing algorithm
40
#define KDTP_KEEP_INCOMING_BOUNDARY_EDGES
41
//#define KDTP_KEEP_BOUNDARY_EDGES
42
//#define KDTP_KEEP_BOUNDARY_NODES
43
// Use KDTP_KEEP_BOUNDARY_FROM_NODES on a reversed graph to build arc infos
44
// for the arc flag shortest path routing algorithm
45
#define KDTP_KEEP_BOUNDARY_FROM_NODES
46
//#define KDTP_KEEP_BOUNDARY_TO_NODES
47
//#define KDTP_FOR_SYNTHETIC_NETWORKS
48
// Use KDTP_WRITE_QGIS_FILTERS to filter boundary nodes of cells in QGIS operating on a (e.g. PostGreSQL) database of
49
// the (e.g. OSM) network
50
//#define KDTP_WRITE_QGIS_FILTERS
51
#ifdef KDTP_WRITE_QGIS_FILTERS
52
#include <fstream>
53
#include <sstream>
54
#endif
55
56
//#define KDTP_DEBUG_LEVEL_0
57
//#define KDTP_DEBUG_LEVEL_1
58
//#define KDTP_DEBUG_LEVEL_2
59
60
#ifdef KDTP_DEBUG_LEVEL_2
61
#define KDTP_DEBUG_LEVEL_1
62
#endif
63
64
#ifdef KDTP_DEBUG_LEVEL_1
65
#define KDTP_DEBUG_LEVEL_0
66
#endif
67
68
// uncomment to disable assert()
69
// #define NDEBUG
70
#include <cassert>
71
72
// ===========================================================================
73
// class definitions
74
// ===========================================================================
75
76
/**
77
* @class KDTreePartition
78
* @brief Partitions the router's network wrt a k-d tree subdivision scheme
79
*
80
* The template parameters are:
81
* @param E The edge class to use (MSEdge/ROEdge)
82
* @param N The node class to use (MSJunction/RONode)
83
* @param V The vehicle class to use (MSVehicle/ROVehicle)
84
*/
85
template<class E, class N, class V>
86
class KDTreePartition {
87
public:
88
/// @brief Enum type for cell axis
89
enum class Axis {
90
X, Y
91
};
92
93
/**
94
* @class NodeXComparator
95
* Class to compare (and so sort) nodes by x-coordinate value
96
*/
97
class NodeXComparator {
98
public:
99
/** @brief Comparing method for X-axis
100
* @param[in] firstNode The first node
101
* @param[in] secondNode The second node
102
* @return true iff first node's x-coordinate is smaller than that of the second
103
* @note In case of ties: true iff integer interpretation of first node's id is smaller than that of the second
104
*/
105
bool operator()(const N* firstNode, const N* secondNode) const {
106
if (firstNode->getPosition().x() == secondNode->getPosition().x()) { // tie
107
std::string str = firstNode->getID();
108
std::intmax_t firstValue = std::strtoimax(str.c_str(), nullptr, 10);
109
str = secondNode->getID();
110
std::intmax_t secondValue = std::strtoimax(str.c_str(), nullptr, 10);
111
return firstValue < secondValue;
112
}
113
return firstNode->getPosition().x() < secondNode->getPosition().x();
114
}
115
};
116
117
/**
118
* @class NodeYComparator
119
* Class to compare (and so sort) nodes by y-coordinate value
120
*/
121
class NodeYComparator {
122
public:
123
/** @brief Comparing method for Y-axis
124
* @param[in] firstNode The first node
125
* @param[in] secondNode The second node
126
* @return true iff first node's y-coordinate is smaller than that of the second
127
* @note In case of ties: true iff integer interpretation of first node's id is smaller than that of the second
128
*/
129
bool operator()(const N* firstNode, const N* secondNode) const {
130
if (firstNode->getPosition().y() == secondNode->getPosition().y()) { // tie
131
std::string str = firstNode->getID();
132
std::intmax_t firstValue = std::strtoimax(str.c_str(), nullptr, 10);
133
str = secondNode->getID();
134
std::intmax_t secondValue = std::strtoimax(str.c_str(), nullptr, 10);
135
return firstValue < secondValue;
136
}
137
return firstNode->getPosition().y() < secondNode->getPosition().y();
138
}
139
};
140
141
/**
142
* @class Cell
143
* @brief Represents an element of the node partition (i.e. a node set)
144
*/
145
class Cell {
146
public:
147
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
148
/** @brief Constructor
149
* @note Works recursively, builds the median-based k-d tree
150
* @param[in] cells The vector of all cells
151
* @param[in] sortedNodes The vector of nodes
152
* @note Initially unsorted, gets sorted wrt to the divisional scheme of the k-dtree after instantiation of the k-d tree
153
* @param[in] numberOfLevels The number of levels
154
* @param[in] level The level
155
* @param[in] levelCells The vector of all level cell vectors
156
* @param[in] axis The axis (X or X)
157
* @param[in] fromInclusive The from-index (inclusive)
158
* @param[in] toExclusive The to-index (exclusive)
159
* @param[in] supercell The supercell
160
* @param[in] minX The minimum X-value of nodes in the cell
161
* @param[in] maxX The maximum X-value of nodes in the cell
162
* @param[in] minY The minimum Y-value of nodes in the cell
163
* @param[in] maxY The maximum Y-value of nodes in the cell
164
* @param[in] northernConflictNodes The northern spatial conflict nodes
165
* @param[in] easternConflictNodes The eastern spatial conflict nodes
166
* @param[in] southernConflictNodes The southern spatial conflict nodes
167
* @param[in] westernConflictNodes The western spatial conflict nodes
168
* @param[in] isLeftOrLowerCell Boolean flag indicating whether this cell is a left or lower cell or not
169
* @param[in] vehicle The vehicle.
170
* @param[in] havePermissions The boolean flag indicating whether edge permissions need to be considered.
171
* @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered.
172
*/
173
Cell(std::vector<const Cell*>* cells, std::vector<std::vector<const Cell*>>* levelCells, std::vector<const N*>* sortedNodes, int numberOfLevels,
174
int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY,
175
std::unordered_set<const N*>* northernConflictNodes, std::unordered_set<const N*>* easternConflictNodes,
176
std::unordered_set<const N*>* southernConflictNodes, std::unordered_set<const N*>* westernConflictNodes,
177
bool isLeftOrLowerCell, const V* const vehicle, const bool havePermissions, const bool haveRestrictions);
178
#else
179
/** @brief Constructor
180
* @note Works recursively, builds the median-based k-d tree
181
* @param[in] cells The vector of all cells
182
* @param[in] levelCells The vector of all level cell vectors
183
* @param[in] sortedNodes The vector of nodes
184
* @note Initially unsorted, after instantiation gets sorted wrt to the k-d tree subdivision scheme
185
* @param[in] numberOfLevels The number of levels
186
* @param[in] level The level
187
* @param[in] axis The axis (X or X)
188
* @param[in] fromInclusive The from-index (inclusive)
189
* @param[in] toExclusive The to-index (exclusive)
190
* @param[in] supercell The supercell
191
* @param[in] minX The minimum X-value of nodes in the cell
192
* @param[in] maxX The maximum X-value of nodes in the cell
193
* @param[in] minY The minimum Y-value of nodes in the cell
194
* @param[in] maxY The maximum Y-value of nodes in the cell
195
* @param[in] isLeftOrLowerCell Boolean flag indicating whether this cell is a left or lower cell or not
196
* @param[in] vehicle The vehicle
197
* @param[in] havePermissions The boolean flag indicating whether edge permissions need to be considered or not
198
* @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered or not
199
*/
200
Cell(std::vector<const Cell*>* cells, std::vector<std::vector<const Cell*>>* levelCells, std::vector<const N*>* sortedNodes,
201
int numberOfLevels, int level, Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX,
202
double minY, double maxY, bool isLeftOrLowerCell, const V* const vehicle, const bool havePermissions, const bool haveRestrictions);
203
#endif
204
205
/// @brief Destructor
206
virtual ~Cell() {
207
delete myLeftOrLowerSubcell;
208
delete myRightOrUpperSubcell;
209
}
210
211
/// @brief Returns the axis of the cell's spatial extension (x or y)
212
Axis getAxis() const {
213
return myAxis;
214
};
215
/**
216
* @brief Returns all edges situated inside the cell
217
* @param[in] vehicle The vehicle
218
*/
219
std::unordered_set<const E*>* edgeSet(const V* const vehicle) const;
220
/**
221
* @brief Returns the number of edges ending in the cell
222
* @param[in] vehicle The vehicle.
223
*/
224
size_t numberOfEdgesEndingInCell(const V* const vehicle) const;
225
/**
226
* @brief Returns the number of edges starting in the cell
227
* @param[in] vehicle The vehicle.
228
*/
229
size_t numberOfEdgesStartingInCell(const V* const vehicle) const;
230
/// @brief Returns the cell's number
231
int getNumber() const {
232
return myNumber;
233
}
234
/// @brief Returns the cell's level
235
// @note Level 0: root
236
int getLevel() const {
237
return myLevel;
238
}
239
/** @brief Returns the number of cells
240
* @return The number of the cells
241
*/
242
int getNumberOfCells() const {
243
return cellCounter();
244
}
245
/** @brief Returns a pair of iterators (first, last) to iterate over the nodes of the cell
246
* @return A pair of iterators (first, last) to iterate over the nodes of the cell
247
*/
248
std::pair<typename std::vector<const N*>::const_iterator,
249
typename std::vector<const N*>::const_iterator> nodeIterators() const;
250
/** @brief Returns a new vector of nodes in the cell
251
* @return A new vector of nodes in the cell
252
*/
253
std::vector<const N*>* nodes() const;
254
#ifdef KDTP_KEEP_BOUNDARY_NODES
255
/// @brief Returns the vector of boundary nodes
256
const std::vector<const N*>& getBoundaryNodes() const {
257
return myBoundaryNodes;
258
}
259
#endif
260
#ifdef KDTP_KEEP_BOUNDARY_FROM_NODES
261
/// @brief Returns the vector of boundary nodes which are from-nodes of outgoing boundary edges
262
const std::vector<const N*>& getBoundaryFromNodes() const {
263
return myBoundaryFromNodes;
264
}
265
#endif
266
#ifdef KDTP_KEEP_BOUNDARY_TO_NODES
267
/// @brief Returns the vector of boundary nodes which are to-nodes of incoming boundary edges
268
const std::vector<const N*>& getBoundaryToNodes() const {
269
return myBoundaryToNodes;
270
}
271
#endif
272
#ifdef KDTP_KEEP_BOUNDARY_EDGES
273
/// @brief Returns the set of boundary edges
274
const std::unordered_set<const E*>& getBoundaryEdges() const {
275
return myBoundaryEdges;
276
}
277
#endif
278
#ifdef KDTP_KEEP_INCOMING_BOUNDARY_EDGES
279
/// @brief Returns the set of incoming boundary edges
280
const std::unordered_set<const E*>& getIncomingBoundaryEdges() const {
281
return myIncomingBoundaryEdges;
282
}
283
#endif
284
#ifdef KDTP_KEEP_OUTGOING_BOUNDARY_EDGES
285
/// @brief Returns the set of outgoing boundary edges
286
const std::unordered_set<const E*>& getOutgoingBoundaryEdges() const {
287
return myOutgoingBoundaryEdges;
288
}
289
#endif
290
/// @brief Returns the left (cell's axis is X) or lower (cell's axis is Y) subcell
291
const Cell* getLeftOrLowerSubcell() const {
292
return myLeftOrLowerSubcell;
293
}
294
/// @brief Returns the right (cell's axis is X) or upper (cell's axis is Y) subcell
295
const Cell* getRightOrUpperSubcell() const {
296
return myRightOrUpperSubcell;
297
}
298
/// @brief Returns the supercell
299
const Cell* getSupercell() const {
300
return mySupercell;
301
}
302
/// @brief Returns the minimum coordinate of a cell node in X-direction (aka left border coordinate)
303
double getMinX() const {
304
return myMinX;
305
}
306
/// @brief Returns the maximum coordinate of a cell node in X-direction (aka right border coordinate)
307
double getMaxX() const {
308
return myMaxX;
309
}
310
/// @brief Returns the minimum coordinate of a cell node in Y-direction (aka lower border coordinate)
311
double getMinY() const {
312
return myMinY;
313
}
314
/// @brief Returns the maximum coordinate of a cell node in Y-direction (aka upper border coordinate)
315
double getMaxY() const {
316
return myMaxY;
317
}
318
/** @brief Tests whether the given node belongs to the cell
319
* @param node The node
320
* @return true iff the given node belongs to the cell
321
*/
322
bool contains(const N* node) const;
323
/// @brief Returns the boolean flag indicating whether this cell is a left or lower cell or not
324
bool isLeftOrLowerCell() const {
325
return myIsLeftOrLowerCell;
326
}
327
/// @brief Returns the median coordinate
328
double getMedianCoordinate() const {
329
return myMedianCoordinate;
330
}
331
332
private:
333
/** @brief Performs one partition step on the set of nodes sorted wrt to the k-d tree subdivision scheme
334
* @returns The median index
335
*/
336
size_t partition();
337
/** @brief Returns the global cell counter
338
* @return The global cell counter
339
*/
340
341
static int& cellCounter() {
342
static int cellCounter{ 0 };
343
return cellCounter;
344
}
345
346
/** @brief Returns true iff driving the given vehicle on the given edge is prohibited
347
* @param[in] edge The edge
348
* @param[in] vehicle The vehicle
349
* @return true iff driving the given vehicle on the given edge is prohibited
350
*/
351
bool isProhibited(const E* const edge, const V* const vehicle) const {
352
return (myHavePermissions && edge->prohibits(vehicle)) || (myHaveRestrictions && edge->restricts(vehicle));
353
}
354
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
355
/** @brief Returns a pair with sets of spatial conflict nodes for a) the left / lower subcell and b) the right / upper subcell
356
* @param medianIndex The index into mySortedNodes dividing the cell nodes into two halves of equal size
357
* @return A pair with sets of spatial conflict nodes for a) the left / lower subcell and b) the right / upper subcell
358
*/
359
std::pair<std::unordered_set<const N*>*, std::unordered_set<const N*>*> spatialConflictNodes(size_t medianIndex) const;
360
#endif
361
/** @brief Tests whether a given node is situated within the spatial bounds of the cell
362
* @param node The node
363
* @return true iff a given node is situated within the spatial bounds of the cell
364
*/
365
bool isInBounds(const N* node) const;
366
/// @brief Completes the information about the spatial extent
367
void completeSpatialInfo();
368
/** @brief Returns the minimum coordinate of the cell nodes' positions, in the direction of the given axis (X or Y)
369
* @param axis The axis
370
* @return The minimum coordinate of the cell nodes' positions, in the direction of the given axis (X or Y)
371
*/
372
double minAxisValue(Axis axis) const;
373
/** @brief Returns the minimum coordinate of the cell nodes' positions, in the direction of the cell's axis (X or Y)
374
* @return The minimum coordinate of the cell nodes' positions, in the direction of the cell's axis(X or Y)
375
*/
376
double minAxisValue() const;
377
/** @brief Returns the maximum coordinate of the cell nodes' positions, in the direction of the given axis (X or Y)
378
* @param axis The axis
379
* @return The maximum coordinate of the cell nodes' positions, in the direction of the given axis (X or Y)
380
*/
381
double maxAxisValue(Axis axis) const;
382
/** @brief Returns the maximum coordinate of the cell nodes' positions, in the direction of the cell's axis (X or Y)
383
* @return The minimum coordinate of the cell nodes' positions, in the direction of the cell's axis(X or Y)
384
*/
385
double maxAxisValue() const;
386
/// @brief The cells
387
std::vector<const Cell*>* myCells;
388
/// @brief The cells of all partitions at all levels of the k-d tree subdivisional scheme
389
std::vector<std::vector<const Cell*>>* myLevelCells;
390
/// @brief The container with all nodes, sorted wrt to the k-d tree subdivisional scheme
391
std::vector<const N*>* mySortedNodes;
392
/// @brief The total number of levels of the k-d tree
393
const int myNumberOfLevels;
394
/// @brief The level
395
const int myLevel;
396
/// @brief The number
397
const int myNumber;
398
/// @brief The axis of the spatial extension
399
const Axis myAxis;
400
/// @brief The from-index (inclusive)
401
const size_t myFromInclusive;
402
/// @brief The to-index (exclusive)
403
const size_t myToExclusive;
404
#if defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS)
405
/// @brief The nodes on the cell boundary
406
std::vector<const N*> myBoundaryNodes;
407
#endif
408
#ifdef KDTP_KEEP_BOUNDARY_FROM_NODES
409
/// @brief Those nodes on the cell boundary, which are from-nodes of outgoing boundary edges
410
std::vector<const N*> myBoundaryFromNodes;
411
#endif
412
#ifdef KDTP_KEEP_BOUNDARY_TO_NODES
413
/// @brief Those nodes on the cell boundary, which are to-nodes of incoming boundary edges
414
std::vector<const N*> myBoundaryToNodes;
415
#endif
416
#ifdef KDTP_KEEP_INCOMING_BOUNDARY_EDGES
417
/// @brief The incoming edges on the cell boundary
418
std::unordered_set<const E*> myIncomingBoundaryEdges;
419
420
#endif
421
#ifdef KDTP_KEEP_OUTGOING_BOUNDARY_EDGES
422
/// @brief The outgoing edges on the cell boundary
423
// @note Used for arc flag setter's shortest path tree algorithm, working on a reversed graph
424
std::unordered_set<const E*> myOutgoingBoundaryEdges;
425
#endif
426
#ifdef KDTP_KEEP_BOUNDARY_EDGES
427
/// @brief The edges on the cell boundary
428
std::unordered_set<const E*> myBoundaryEdges;
429
#endif
430
/// @brief The super cell
431
Cell* mySupercell;
432
/// @brief The left (cell's axis is X) or lower (cell's axis is Y) subcell
433
Cell* myLeftOrLowerSubcell;
434
/// @brief The right (cell's axis is X) or upper (cell's axis is Y) subcell
435
Cell* myRightOrUpperSubcell;
436
/// @brief The minimum x-value of a node in the cell
437
double myMinX;
438
/// @brief The maximum x-value of a node in the cell
439
double myMaxX;
440
/// @brief The minimum y-value of a node in the cell
441
double myMinY;
442
/// @brief The maximum y-value of a node in the cell
443
double myMaxY;
444
/// @brief The boolean flag indicating whether the information about the cell's spatial extent is complete or not
445
bool myHasCompleteSpatialInfo;
446
/// @brief The boolean flag indicating whether the cell's nodes are sorted wrt to the cell's axis or not
447
bool myHasNodesSortedWrtToMyAxis;
448
/// @brief The boolean flag indicating whether this cell is a left/lower cell or not
449
bool myIsLeftOrLowerCell;
450
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
451
/// @brief The northern spatial conflict nodes
452
std::unordered_set<const N*>* myNorthernConflictNodes;
453
/// @brief The eastern spatial conflict nodes
454
std::unordered_set<const N*>* myEasternConflictNodes;
455
/// @brief The southern spatial conflict nodes
456
std::unordered_set<const N*>* mySouthernConflictNodes;
457
/// @brief The western spatial conflict nodes
458
std::unordered_set<const N*>* myWesternConflictNodes;
459
#endif
460
/// @brief The boolean flag indicating whether edge permissions need to be considered or not
461
const bool myHavePermissions;
462
/// @brief The boolean flag indicating whether edge restrictions need to be considered or not
463
const bool myHaveRestrictions;
464
/// @brief The coordinate in the axis' direction of the node at the median index
465
double myMedianCoordinate;
466
}; // end of class Cell declaration
467
468
/** @brief Constructor
469
* @param[in] numberOfLevels The number of levels
470
* @param[in] edges The container with all edges of the network
471
* @param[in] havePermissions The boolean flag indicating whether edge permissions need to be considered or not
472
* @param[in] haveRestrictions The boolean flag indicating whether edge restrictions need to be considered or not
473
*/
474
KDTreePartition(int numberOfLevels, const std::vector<E*>& edges,
475
const bool havePermissions, const bool haveRestrictions);
476
477
/// @brief Destructor
478
~KDTreePartition() {
479
std::vector<const N*>().swap(mySortedNodes);
480
std::vector<const Cell*>().swap(myCells);
481
std::vector<std::vector<const Cell*>>().swap(myLevelCells);
482
delete myRoot;
483
};
484
485
/** @brief Initialize the k-d tree wrt to the given vehicle's permissions
486
* @param[in] vehicle The vehicle
487
*/
488
void init(const V* const vehicle);
489
/** @brief Delete the k-d tree, and create a new one
490
* param[in] vehicle The vehicle
491
* @note Recreated wrt the network given at construction and the given edge
492
*/
493
void reset(const V* const vehicle) {
494
delete myRoot;
495
init(vehicle);
496
}
497
/// @brief Returns the root of the k-d tree
498
const Cell* getRoot() const {
499
return myRoot;
500
}
501
/// @brief Returns all cells
502
const std::vector<const Cell*>& getCells() {
503
return myCells;
504
}
505
/** @brief Returns the cell with the given number
506
* @note Returns nullptr, if no such cell exists
507
* @param[in] number The cell number
508
* @return The cell with the given number
509
*/
510
const Cell* cell(int number) const;
511
/// @brief Returns all cells of a level
512
const std::vector<const Cell*>& getCellsAtLevel(int level) const {
513
return myLevelCells[level];
514
}
515
/** @brief Returns the numbers of the cells which the given node is situated in
516
* @param[in] node The node
517
* @return The numbers of the cells which the given node is situated in
518
*/
519
std::vector<int>* cellNumbers(const N* node) const;
520
/** @brief Returns the conjugated 2D axis
521
* @note X->Y / Y->X
522
* @param[in] axis The axis
523
* @return The conjugated 2D axis
524
*/
525
static Axis flip(Axis axis) {
526
return axis == Axis::X ? Axis::Y : Axis::X;
527
}
528
/** @brief Returns the number of arc flags required in a multi-level approach
529
* @note E.g.: number of levels := 3 -> 2 + 2 = 4 bits are required
530
* @note No flag(s) for root level 0; each non-leaf cell has two subcells
531
* @return The number of arc flags required in a multi-level approach
532
*/
533
int numberOfArcFlags() const {
534
return 2 * (myNumberOfLevels - 1);
535
}
536
/// @brief Returns the number of levels L incl. the zeroth level
537
// @note Levels go from 0 to L-1
538
int getNumberOfLevels() const {
539
return myNumberOfLevels;
540
}
541
/** @brief Returns the number of cells at all levels
542
* @return The number of cells at all levels
543
*/
544
size_t numberOfCells() const {
545
return static_cast<size_t>(std::lround(std::pow(2, myNumberOfLevels)) - 1);
546
}
547
/** @brief Returns the number of regions, i.e. the number of cells at the shallowest (bottom/leaf) level
548
* @return The number of regions, i.e. the number of cells at the shallowest (bottom/leaf) level
549
*/
550
size_t numberOfRegions() const {
551
return static_cast<size_t>(std::lround(std::pow(2, myNumberOfLevels - 1)));
552
}
553
/// @brief Returns true iff the k-d tree is uninitialized
554
bool isClean() {
555
return myAmClean;
556
}
557
/** @brief Search a node in the bottom cells (i.e., return the respective cell)
558
* @note Uses the position of the node and the divisional structure of the k-d tree for the search.
559
* @note O(log n) where n = number of cells
560
* @param[in] node The node
561
* @return The bottom cell containing the node, or nullptr if the node could not be found
562
*/
563
const Cell* searchNode(const N* node) const;
564
565
private:
566
/** @brief Helper method for {@link #cellNumbers()}.
567
* @param node The node
568
* @param cell The cell
569
* @param level The level
570
* @param nodeCellNumbers The vector of cell numbers for the passed node
571
*/
572
void cellNumbersAux(const N* node, const Cell* cell, int level, std::vector<int>* nodeCellNumbers) const;
573
/// @brief The root of the k-d tree
574
const Cell* myRoot;
575
/// @brief The number of levels
576
const int myNumberOfLevels;
577
/// @brief The reference to a constant container with pointers to edges
578
const std::vector<E*>& myEdges;
579
/// @brief The container with all nodes, sorted wrt to the k-d tree subdivision scheme
580
std::vector<const N*> mySortedNodes;
581
/// @brief The cells
582
std::vector<const Cell*> myCells;
583
/// @brief The cells of all partitions at all levels of the k-d tree subdivision scheme
584
std::vector<std::vector<const Cell*>> myLevelCells;
585
/// @brief The boolean flag indicating whether edge permissions need to be considered or not
586
const bool myHavePermissions;
587
/// @brief The boolean flag indicating whether edge restrictions need to be considered or not
588
const bool myHaveRestrictions;
589
/// @brief The boolean flag indicating whether the k-d tree is a clean (empty, uninitialized) instance or not
590
bool myAmClean;
591
}; // end of class KDTreePartition declaration
592
593
// ===========================================================================
594
// method definitions
595
// ===========================================================================
596
597
template<class E, class N, class V>
598
KDTreePartition<E, N, V>::KDTreePartition(int numberOfLevels, const std::vector<E*>& edges,
599
const bool havePermissions, const bool haveRestrictions) :
600
myNumberOfLevels(numberOfLevels),
601
myEdges(edges),
602
myHavePermissions(havePermissions),
603
myHaveRestrictions(haveRestrictions),
604
myAmClean(true) { /* still uninitialized */
605
if (numberOfLevels <= 0) {
606
throw std::invalid_argument("KDTreePartition::KDTreePartition: zero or negative number of levels has been passed!");
607
}
608
}
609
610
template<class E, class N, class V>
611
void KDTreePartition<E, N, V>::init(const V* const vehicle) {
612
size_t edgeCounter = 0;
613
std::unordered_set<const N*> nodeSet;
614
// extract nodes from edges
615
mySortedNodes.resize(myEdges.size() * 2);
616
#ifdef KDTP_DEBUG_LEVEL_1
617
std::cout << "Extracting nodes from edges..." << std::endl;
618
#endif
619
for (E* edge : myEdges) {
620
if ((myHavePermissions && edge->prohibits(vehicle))
621
|| (myHaveRestrictions && edge->restricts(vehicle))) {
622
continue;
623
}
624
const N* node = edge->getFromJunction();
625
typename std::unordered_set<const N*>::const_iterator it = nodeSet.find(node);
626
if (it == nodeSet.end()) {
627
nodeSet.insert(node);
628
assert(edgeCounter < mySortedNodes.size());
629
mySortedNodes[edgeCounter++] = node;
630
}
631
node = edge->getToJunction();
632
it = nodeSet.find(node);
633
if (it == nodeSet.end()) {
634
nodeSet.insert(node);
635
assert(edgeCounter < mySortedNodes.size());
636
mySortedNodes[edgeCounter++] = node;
637
}
638
}
639
mySortedNodes.shrink_to_fit();
640
#ifdef KDTP_DEBUG_LEVEL_1
641
std::cout << "Nodes extracted from edges." << std::endl;
642
#endif
643
mySortedNodes.resize(edgeCounter);
644
myCells.resize(numberOfCells());
645
myLevelCells.resize(myNumberOfLevels);
646
// call the recursive cell constructor at the root (instantiates the whole k-d tree of cells)
647
#ifdef KDTP_DEBUG_LEVEL_1
648
std::cout << "Calling root cell constructor..." << std::endl;
649
#endif
650
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
651
myRoot = new Cell(&myCells, &myLevelCells, &mySortedNodes, myNumberOfLevels, 0, Axis::Y, 0, mySortedNodes.size(), nullptr, -1, -1, -1, -1,
652
nullptr, nullptr, nullptr, nullptr, false, vehicle, havePermissions, haveRestrictions);
653
#else
654
myRoot = new Cell(&myCells, &myLevelCells, &mySortedNodes, myNumberOfLevels, 0, Axis::Y, 0, mySortedNodes.size(), nullptr, -1, -1, -1, -1,
655
false, vehicle, myHavePermissions, myHaveRestrictions);
656
#endif
657
#ifdef KDTP_DEBUG_LEVEL_1
658
std::cout << "Done." << std::endl;
659
#endif
660
assert(myCells[0] == myRoot);
661
assert(myRoot->getNumber() == 0);
662
// nodes are now sorted wrt to the k-d tree's subdivisional scheme
663
#ifdef KDTP_DEBUG_LEVEL_0
664
const N* node = mySortedNodes[0];
665
std::vector<int>* numbers = cellNumbers(node);
666
int i;
667
for (i = 0; i < myNumberOfLevels; ++i) {
668
std::cout << "Cell numbers of test node: " << (*numbers)[i] << std::endl;
669
}
670
delete numbers;
671
for (i = 0; i < myNumberOfLevels; ++i) {
672
const std::vector<const Cell*>& levelCells = getCellsAtLevel(i);
673
size_t size = levelCells.size();
674
std::cout << "Level " << i << " has " << size << " cells." << std::endl;
675
std::cout << "The numbers of the cells are: " << std::endl;
676
size_t k = 0;
677
for (const Cell* cell : levelCells) {
678
std::cout << cell->getNumber() << (k++ < size ? ", " : "") << std::endl;
679
}
680
}
681
#endif
682
myAmClean = false;
683
}
684
685
template<class E, class N, class V>
686
const typename KDTreePartition<E, N, V>::Cell* KDTreePartition<E, N, V>::cell(int number) const {
687
// for now fast enough since the number of cells is usually small
688
for (const KDTreePartition<E, N, V>::Cell* cell : myCells) {
689
if (cell->getNumber() == number) {
690
return cell;
691
}
692
}
693
return nullptr;
694
}
695
696
template<class E, class N, class V>
697
std::vector<int>* KDTreePartition<E, N, V>::cellNumbers(const N* node) const {
698
std::vector<int>* nodeCellNumbers = new std::vector<int>(myNumberOfLevels);
699
int i;
700
for (i = 0; i < myNumberOfLevels; ++i) {
701
(*nodeCellNumbers)[i] = -1;
702
}
703
cellNumbersAux(node, myCells[0], 0, nodeCellNumbers);
704
#ifdef KDTP_DEBUG_LEVEL_1
705
std::cout << "The following entries in nodeCellNumbers should all be set (!=-1): " << std::endl;
706
for (i = 0; i < myNumberOfLevels; ++i) {
707
assert((*nodeCellNumbers)[i] != -1);
708
std::cout << "nodeCellNumbers[" << i << "]:" << (*nodeCellNumbers)[i] << std::endl;
709
}
710
#endif
711
return nodeCellNumbers;
712
}
713
714
template<class E, class N, class V>
715
void KDTreePartition<E, N, V>::cellNumbersAux(const N* node, const Cell* cell, int level, std::vector<int>* nodeCellNumbers) const {
716
#ifdef KDTP_DEBUG_LEVEL_1
717
std::cout << "Call ...aux, level: " << level << ", cell->getAxis(): " << (cell->getAxis() == Axis::X ? "X" : "Y") << std::endl;
718
#endif
719
assert(level < myNumberOfLevels);
720
#ifdef KDTP_DEBUG_LEVEL_1
721
Axis flippedCellAxis = flip(cell->getAxis());
722
double nodeAxisValue = flippedCellAxis == Axis::Y ? node->getPosition().y() : node->getPosition().x();
723
std::cout << "Flipped axis of cell (=parent cell axis): " << (flippedCellAxis == Axis::X ? "X" : "Y")
724
<< ", cell min axis value in flipped axis: " << (flippedCellAxis == Axis::X ? cell->getMinX() : cell->getMinY())
725
<< ", node axis value in flipped axis: " << nodeAxisValue << ", cell max axis value in flipped axis: "
726
<< (flippedCellAxis == Axis::X ? cell->getMaxX() : cell->getMaxY()) << std::endl;
727
#endif
728
if (cell->contains(node)) {
729
// node is inside the cell, hence cell is one of the cells of node
730
(*nodeCellNumbers)[level] = cell->getNumber();
731
#ifdef KDTP_DEBUG_LEVEL_1
732
std::cout << "Just filled nodeCellNumbers[" << level << "]:" << (*nodeCellNumbers)[level] << std::endl;
733
#endif
734
// only one of the below two calls may actually alter array nodeCellNumbers
735
const Cell* leftOrLowerSubcell = cell->getLeftOrLowerSubcell();
736
if (leftOrLowerSubcell) { // no more calls at shallowest (i.e. leaf) level
737
cellNumbersAux(node, leftOrLowerSubcell, level + 1, nodeCellNumbers);
738
}
739
const Cell* rightOrUpperSubcell = cell->getRightOrUpperSubcell();
740
if (rightOrUpperSubcell) {
741
cellNumbersAux(node, rightOrUpperSubcell, level + 1, nodeCellNumbers);
742
}
743
}
744
#ifdef KDTP_DEBUG_LEVEL_1
745
else { // node is not inside the cell, no need to look for node in subcells (consequently, do nothing more, return)
746
std::cout << "Not inside cell, do nothing." << std::endl;
747
}
748
#endif
749
}
750
751
template<class E, class N, class V>
752
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
753
KDTreePartition<E, N, V>::Cell::Cell(std::vector<const Cell*>* cells, std::vector<std::vector<const Cell*>>* levelCells, std::vector<const N*>* sortedNodes, int numberOfLevels, int level,
754
Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY, std::unordered_set<const N*>* northernConflictNodes,
755
std::unordered_set<const N*>* easternConflictNodes, std::unordered_set<const N*>* southernConflictNodes, std::unordered_set<const N*>* westernConflictNodes, const V* const vehicle,
756
const bool havePermissions, const bool haveRestrictions) :
757
myCells(cells),
758
myLevelCells(levelCells),
759
mySortedNodes(sortedNodes),
760
myNumberOfLevels(numberOfLevels),
761
myLevel(level), myNumber(cellCounter()++),
762
myAxis(axis),
763
myFromInclusive(fromInclusive),
764
myToExclusive(toExclusive),
765
mySupercell(supercell),
766
myMinX(minX),
767
myMaxX(maxX),
768
myMinY(minY),
769
myMaxY(maxY),
770
myNorthernConflictNodes(northernConflictNodes),
771
myEasternConflictNodes(easternConflictNodes),
772
mySouthernConflictNodes(southernConflictNodes),
773
myWesternConflictNodes(westernConflictNodes),
774
myIsLeftOrLowerCell(isLeftOrLowerCell),
775
myHavePermissions(havePermissions),
776
myHaveRestrictions(haveRestrictions),
777
myMedianCoordinate(-1.) {
778
#else
779
KDTreePartition<E, N, V>::Cell::Cell(std::vector<const Cell*>* cells, std::vector<std::vector<const Cell*>>* levelCells, std::vector<const N*>* sortedNodes, int numberOfLevels, int level,
780
Axis axis, size_t fromInclusive, size_t toExclusive, Cell* supercell, double minX, double maxX, double minY, double maxY, bool isLeftOrLowerCell, const V* const vehicle,
781
const bool havePermissions, const bool haveRestrictions) :
782
myCells(cells),
783
myLevelCells(levelCells),
784
mySortedNodes(sortedNodes),
785
myNumberOfLevels(numberOfLevels),
786
myLevel(level),
787
myNumber(cellCounter()++),
788
myAxis(axis),
789
myFromInclusive(fromInclusive),
790
myToExclusive(toExclusive),
791
mySupercell(supercell),
792
myMinX(minX),
793
myMaxX(maxX),
794
myMinY(minY),
795
myMaxY(maxY),
796
myIsLeftOrLowerCell(isLeftOrLowerCell),
797
myHavePermissions(havePermissions),
798
myHaveRestrictions(haveRestrictions),
799
myMedianCoordinate(-1.) {
800
#endif
801
// throw invalid argument exception if fromInclusive is greater than or equal to toExclusive
802
if (myFromInclusive >= myToExclusive) {
803
throw std::invalid_argument("Cell::Cell: myFromInclusive greater than or equal to myToExclusive!");
804
}
805
myHasCompleteSpatialInfo = false;
806
myHasNodesSortedWrtToMyAxis = false;
807
(*myCells)[myNumber] = this;
808
(*myLevelCells)[myLevel].push_back(this);
809
#ifdef KDTP_DEBUG_LEVEL_1
810
std::cout << "Cell number: " << myNumber << ", cell's extent: minX=" << myMinX << ", maxX="
811
<< myMaxX << ", minY=" << myMinY << ", maxY=" << myMaxY << std::endl;
812
std::vector<const N*>* cellNodes = nodes();
813
int cnt = 0;
814
for (const N* node : *cellNodes) {
815
if (++cnt % 10000 == 0) {
816
std::cout << "Testing node " << cnt << std::endl;
817
}
818
assert(contains(node));
819
}
820
delete cellNodes;
821
#endif
822
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
823
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
824
typename std::vector<const N*>::const_iterator iter;
825
#ifdef KDTP_WRITE_QGIS_FILTERS
826
size_t numberOfNodes = myToExclusive - myFromInclusive;
827
size_t k = 0;
828
std::string qgisFilterString = "id IN (";
829
// go through the nodes of the cell
830
for (iter = first; iter != last; iter++) {
831
k++;
832
qgisFilterString += (*iter)->getID() + (k < numberOfNodes ? ", " : "");
833
}
834
qgisFilterString += ")";
835
std::ostringstream pathAndFileName;
836
pathAndFileName << "./filter_nodes_of_cell_" << myNumber << ".qqf";
837
std::ofstream file;
838
file.open(pathAndFileName.str());
839
std::ostringstream content;
840
content << "<Query>" << qgisFilterString << "</Query>";
841
file << content.str();
842
file.close();
843
#endif
844
// compute the set of of edges inside the cell
845
#ifdef KDTP_DEBUG_LEVEL_1
846
std::cout << "Computing the set of of edges inside the cell..." << std::endl;
847
#endif
848
std::unordered_set<const E*>* edgeSet = this->edgeSet(vehicle);
849
#ifdef KDTP_DEBUG_LEVEL_1
850
std::cout << "Done. Now collecting boundary edges..." << std::endl;
851
int i = 0;
852
#endif
853
/// go through the nodes of the cell in order to identify and collect boundary nodes / edges
854
for (iter = first; iter != last; iter++) {
855
#if defined(KDTP_KEEP_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS)
856
std::unordered_set<const E*> nodeEdgeSet;
857
#endif
858
#ifdef KDTP_DEBUG_LEVEL_1
859
if ((i++ % 10000) == 0) {
860
std::cout << i << " cell nodes processed..." << std::endl;
861
}
862
#endif
863
#if defined(KDTP_KEEP_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS)
864
const std::vector<const E*>& incomingEdges = (*iter)->getIncoming();
865
for (const E* incomingEdge : incomingEdges) {
866
if (isProhibited(incomingEdge, vehicle)) {
867
continue;
868
}
869
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
870
if (incomingEdge->isInternal()) {
871
continue;
872
}
873
#endif
874
nodeEdgeSet.insert(incomingEdge);
875
}
876
const std::vector<const E*>& outgoingEdges = (*iter)->getOutgoing();
877
for (const E* outgoingEdge : outgoingEdges) {
878
if (isProhibited(outgoingEdge, vehicle)) {
879
continue;
880
}
881
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
882
if (outgoingEdge->isInternal()) {
883
continue;
884
}
885
#endif
886
nodeEdgeSet.insert(outgoingEdge);
887
}
888
bool containsAll = true;
889
for (const E* nodeEdge : nodeEdgeSet) {
890
if (edgeSet->find(nodeEdge) == edgeSet->end()) {
891
containsAll = false;
892
#ifndef KDTP_KEEP_BOUNDARY_EDGES
893
break; // cancel at first element which is not found
894
#else
895
myBoundaryEdges.insert(nodeEdge); // boundary edge!
896
#endif
897
}
898
}
899
#if defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS)
900
if (!containsAll) {
901
myBoundaryNodes.push_back(*iter);
902
}
903
#endif
904
#endif
905
#if defined(KDTP_KEEP_INCOMING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_TO_NODES)
906
const std::vector<const E*>& incoming = (*iter)->getIncoming();
907
std::unordered_set<const N*> boundaryToNodesSet;
908
for (const E* nodeEdge : incoming) {
909
if (isProhibited(nodeEdge, vehicle)) {
910
continue;
911
}
912
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
913
if (nodeEdge->isInternal()) {
914
continue;
915
}
916
#endif
917
assert(nodeEdge->getToJunction() == *iter);
918
if (edgeSet->find(nodeEdge) == edgeSet->end()) {
919
#ifdef KDTP_KEEP_INCOMING_BOUNDARY_EDGES
920
myIncomingBoundaryEdges.insert(nodeEdge); // incoming boundary edge
921
#endif
922
#ifdef KDTP_KEEP_BOUNDARY_TO_NODES
923
boundaryToNodesSet.insert(*iter); ; // boundary to-node!
924
#endif
925
}
926
}
927
#ifdef KDTP_KEEP_BOUNDARY_TO_NODES
928
std::copy(boundaryToNodesSet.begin(), boundaryToNodesSet.end(),
929
std::back_inserter(myBoundaryToNodes));
930
#endif
931
#endif
932
#if defined(KDTP_KEEP_OUTGOING_BOUNDARY_EDGES) || defined(KDTP_KEEP_BOUNDARY_FROM_NODES)
933
const std::vector<const E*>& outgoing = (*iter)->getOutgoing();
934
std::unordered_set<const N*> boundaryFromNodesSet;
935
for (const E* nodeEdge : outgoing) {
936
if (isProhibited(nodeEdge, vehicle)) {
937
continue;
938
}
939
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
940
if (nodeEdge->isInternal()) {
941
continue;
942
}
943
#endif
944
assert(nodeEdge->getFromJunction() == *iter);
945
if (edgeSet->find(nodeEdge) == edgeSet->end()) {
946
#ifdef KDTP_KEEP_OUTGOING_BOUNDARY_EDGES
947
myOutgoingBoundaryEdges.insert(nodeEdge); // outgoing boundary edge
948
#endif
949
#ifdef KDTP_KEEP_BOUNDARY_FROM_NODES
950
boundaryFromNodesSet.insert(*iter); // boundary from-node
951
#endif
952
}
953
}
954
#ifdef KDTP_KEEP_BOUNDARY_FROM_NODES
955
std::copy(boundaryFromNodesSet.begin(), boundaryFromNodesSet.end(),
956
std::back_inserter(myBoundaryFromNodes));
957
#endif
958
#endif
959
}
960
delete edgeSet;
961
#if defined(KDTP_KEEP_BOUNDARY_NODES) || defined(KDTP_WRITE_QGIS_FILTERS)
962
size_t numberOfBoundaryNodes = myBoundaryNodes.size();
963
#ifdef KDTP_DEBUG_LEVEL_1
964
std::cout << "Number of boundary nodes: " << numberOfBoundaryNodes << std::endl;
965
#endif
966
#endif
967
#ifdef KDTP_KEEP_BOUNDARY_FROM_NODES
968
#ifdef KDTP_DEBUG_LEVEL_1
969
size_t numberOfBoundaryFromNodes = myBoundaryFromNodes.size();
970
std::cout << "Number of boundary from nodes: " << numberOfBoundaryFromNodes << std::endl;
971
#endif
972
#endif
973
#ifdef KDTP_KEEP_BOUNDARY_TO_NODES
974
size_t numberOfBoundaryToNodes = myBoundaryToNodes.size();
975
#ifdef KDTP_DEBUG_LEVEL_1
976
std::cout << "Number of boundary to nodes: " << numberOfBoundaryToNodes << std::endl;
977
#endif
978
#endif
979
#ifdef KDTP_KEEP_BOUNDARY_EDGES
980
size_t numberOfBoundaryEdges = myBoundaryEdges.size();
981
#ifdef KDTP_DEBUG_LEVEL_1
982
std::cout << "Number of boundary edges: " << numberOfBoundaryEdges << std::endl;
983
#endif
984
#endif
985
#ifdef KDTP_KEEP_INCOMING_BOUNDARY_EDGES
986
#ifdef KDTP_DEBUG_LEVEL_1
987
size_t numberOfIncomingBoundaryEdges = myIncomingBoundaryEdges.size();
988
std::cout << "Number of incoming boundary edges: " << numberOfIncomingBoundaryEdges << std::endl;
989
#endif
990
#endif
991
#ifdef KDTP_KEEP_OUTGOING_BOUNDARY_EDGES
992
#ifdef KDTP_DEBUG_LEVEL_1
993
size_t numberOfOutgoingBoundaryEdges = myOutgoingBoundaryEdges.size();
994
std::cout << "Number of outgoing boundary edges: " << numberOfOutgoingBoundaryEdges << std::endl;
995
#endif
996
#endif
997
#ifdef KDTP_WRITE_QGIS_FILTERS
998
k = 0;
999
qgisFilterString.clear();
1000
qgisFilterString = "id IN (";
1001
// go through the boundary nodes of the cell
1002
for (const N* node : myBoundaryNodes) {
1003
k++;
1004
qgisFilterString += node->getID() + (k < numberOfBoundaryNodes ? ", " : "");
1005
}
1006
#ifndef KDTP_KEEP_BOUNDARY_NODES
1007
myBoundaryNodes.clear();
1008
#endif
1009
qgisFilterString += ")";
1010
pathAndFileName.str("");
1011
pathAndFileName.clear();
1012
pathAndFileName << "./filter_boundary_nodes_of_cell_" << myNumber << ".qqf";
1013
file.clear();
1014
file.open(pathAndFileName.str());
1015
content.str("");
1016
content.clear();
1017
content << "<Query>" << qgisFilterString << "</Query>";
1018
file << content.str();
1019
file.close();
1020
#endif
1021
#ifdef KDTP_DEBUG_LEVEL_1
1022
std::cout << "Done. Now calling the constructor recursively to instantiate the subcells (left or lower one first)..." << std::endl;
1023
#endif
1024
size_t medianIndex = partition();
1025
completeSpatialInfo();
1026
// create subcells
1027
if (myLevel < myNumberOfLevels - 1) {
1028
// determine min/max X/Y-values to pass on to left or lower subcell
1029
double passMinX = -1, passMaxX = -1, passMinY = -1, passMaxY = -1;
1030
if (myAxis == Axis::X) { // left subcell
1031
passMinX = myMinX;
1032
passMaxX = (*mySortedNodes)[medianIndex]->getPosition().x();
1033
passMinY = myMinY;
1034
passMaxY = myMaxY;
1035
} else { // lower subcell
1036
passMinX = myMinX;
1037
passMaxX = myMaxX;
1038
passMinY = myMinY;
1039
passMaxY = (*mySortedNodes)[medianIndex]->getPosition().y();
1040
}
1041
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
1042
// notice that nodes with indexes medianIndex and medianIndex+1 may have the same coordinate in the direction of myAxis
1043
// (in that case, they are ordered / distributed between the two subcells with a tie-breaking rule)
1044
// consequently, the spatial extent of cells alone does not suffice to decide whether a node belongs to a certain cell or not
1045
// therefore, for each of the two subcells, we compute the set of nodes sharing said coordinate (called the set of "spatial conflict nodes")
1046
// the size of this set is usually very small compared to the size of the set of all nodes of the subcell
1047
// with the spatial extent of a cell and its spatial conflict nodes set, a valid test whether a node belongs to the cell becomes available
1048
// this test is quicker and requires significantly less memory than one based on pre-computed sets of all cell nodes
1049
std::pair<std::unordered_set<const N*>*, std::unordered_set<const N*>*> conflictNodes = spatialConflictNodes(medianIndex);
1050
// determine northern/eastern/southern/western conflict nodes to pass on to left or lower subcell
1051
std::unordered_set<const N*>* passNorthernConflictNodes;
1052
std::unordered_set<const N*>* passEasternConflictNodes;
1053
std::unordered_set<const N*>* passSouthernConflictNodes;
1054
std::unordered_set<const N*>* passWesternConflictNodes;
1055
if (myAxis == Axis::X) { // left subcell
1056
passNorthernConflictNodes = myNorthernConflictNodes;
1057
passEasternConflictNodes = conflictNodes.first;
1058
passSouthernConflictNodes = mySouthernConflictNodes;
1059
passWesternConflictNodes = myWesternConflictNodes;
1060
} else { // lower subcell
1061
passNorthernConflictNodes = conflictNodes.first;
1062
passEasternConflictNodes = myEasternConflictNodes;
1063
passSouthernConflictNodes = mySouthernConflictNodes;
1064
passWesternConflictNodes = myWesternConflictNodes;
1065
}
1066
myLeftOrLowerSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), myFromInclusive, medianIndex + 1, this,
1067
passMinX, passMaxX, passMinY, passMaxY, passNorthernConflictNodes, passEasternConflictNodes, passSouthernConflictNodes, passWesternConflictNodes, true,
1068
vehicle, myHavePermissions, myHaveRestrictions);
1069
#else
1070
myLeftOrLowerSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), myFromInclusive, medianIndex + 1, this,
1071
passMinX, passMaxX, passMinY, passMaxY, true, vehicle, myHavePermissions, myHaveRestrictions);
1072
#endif
1073
#ifdef KDTP_DEBUG_LEVEL_1
1074
std::cout << "Left or lower call done. Now calling it for the right or upper subcell..." << std::endl;
1075
#endif
1076
// determine min/max X/Y-values to pass on to right or upper subcell
1077
passMinX = -1, passMaxX = -1, passMinY = -1, passMaxY = -1;
1078
if (myAxis == Axis::X) { // right subcell
1079
passMinX = (*mySortedNodes)[medianIndex + 1]->getPosition().x();
1080
passMaxX = myMaxX;
1081
passMinY = myMinY;
1082
passMaxY = myMaxY;
1083
} else { // upper subcell
1084
passMinX = myMinX;
1085
passMaxX = myMaxX;
1086
passMinY = (*mySortedNodes)[medianIndex + 1]->getPosition().y();
1087
passMaxY = myMaxY;
1088
}
1089
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
1090
// determine northern/eastern/southern/western conflict nodes to pass on to right or upper subcell
1091
if (myAxis == Axis::X) { // right subcell
1092
passNorthernConflictNodes = myNorthernConflictNodes;
1093
passEasternConflictNodes = myEasternConflictNodes;
1094
passSouthernConflictNodes = mySouthernConflictNodes;
1095
passWesternConflictNodes = conflictNodes.second;
1096
} else { // upper subcell
1097
passNorthernConflictNodes = myNorthernConflictNodes;
1098
passEasternConflictNodes = myEasternConflictNodes;
1099
passSouthernConflictNodes = conflictNodes.second;
1100
passWesternConflictNodes = myWesternConflictNodes;
1101
}
1102
myRightOrUpperSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), medianIndex + 1, myToExclusive, this,
1103
passMinX, passMaxX, passMinY, passMaxY, passNorthernConflictNodes, passEasternConflictNodes, passSouthernConflictNodes, passWesternConflictNodes, false,
1104
vehicle, myHavePermissions, myHaveRestrictions);
1105
#else
1106
myRightOrUpperSubcell = new Cell(myCells, myLevelCells, mySortedNodes, myNumberOfLevels, myLevel + 1, KDTreePartition::flip(myAxis), medianIndex + 1, myToExclusive, this,
1107
passMinX, passMaxX, passMinY, passMaxY, false, vehicle, myHavePermissions, myHaveRestrictions);
1108
#endif
1109
#ifdef KDTP_DEBUG_LEVEL_1
1110
std::cout << "Right or upper call done. Returning from constructor..." << std::endl;
1111
#endif
1112
} else {
1113
// leaves of the k-d tree: subcell pointers equal nullptr
1114
myLeftOrLowerSubcell = nullptr;
1115
myRightOrUpperSubcell = nullptr;
1116
}
1117
} // end of cell constructor
1118
1119
template<class E, class N, class V>
1120
double KDTreePartition<E, N, V>::Cell::minAxisValue(Axis axis) const {
1121
#ifdef KDTP_DEBUG_LEVEL_1
1122
double returnValue = -1;
1123
#endif
1124
if (myHasNodesSortedWrtToMyAxis && axis == myAxis) {
1125
#ifndef KDTP_DEBUG_LEVEL_1
1126
return (myAxis == Axis::Y ? (*mySortedNodes)[myFromInclusive]->getPosition().y()
1127
: (*mySortedNodes)[myFromInclusive]->getPosition().x());
1128
#else
1129
returnValue = (myAxis == Axis::Y ? (*mySortedNodes)[myFromInclusive]->getPosition().y()
1130
: (*mySortedNodes)[myFromInclusive]->getPosition().x());
1131
#endif
1132
}
1133
double minAxisValue = std::numeric_limits<double>::max();
1134
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1135
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1136
typename std::vector<const N*>::const_iterator iter;
1137
// go through the nodes of the cell
1138
for (iter = first; iter != last; iter++) {
1139
double nodeAxisValue;
1140
nodeAxisValue = (axis == Axis::Y ? (*iter)->getPosition().y() : (*iter)->getPosition().x());
1141
if (nodeAxisValue < minAxisValue) {
1142
minAxisValue = nodeAxisValue;
1143
}
1144
}
1145
assert(minAxisValue < std::numeric_limits<double>::max());
1146
#ifdef KDTP_DEBUG_LEVEL_1
1147
assert((!myHasNodesSortedWrtToMyAxis || axis != myAxis) || minAxisValue == returnValue);
1148
#endif
1149
return minAxisValue;
1150
}
1151
1152
template<class E, class N, class V>
1153
double KDTreePartition<E, N, V>::Cell::minAxisValue() const {
1154
return minAxisValue(myAxis);
1155
}
1156
1157
template<class E, class N, class V>
1158
double KDTreePartition<E, N, V>::Cell::maxAxisValue(Axis axis) const {
1159
#ifdef KDTP_DEBUG_LEVEL_1
1160
double returnValue = -1;
1161
#endif
1162
if (myHasNodesSortedWrtToMyAxis && axis == myAxis) {
1163
#ifndef KDTP_DEBUG_LEVEL_1
1164
return (myAxis == Axis::Y ? (*mySortedNodes)[myToExclusive - 1]->getPosition().y()
1165
: (*mySortedNodes)[myToExclusive - 1]->getPosition().x());
1166
#else
1167
returnValue = (myAxis == Axis::Y ? (*mySortedNodes)[myToExclusive - 1]->getPosition().y()
1168
: (*mySortedNodes)[myToExclusive - 1]->getPosition().x());
1169
#endif
1170
1171
}
1172
double maxAxisValue = -1;
1173
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1174
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1175
typename std::vector<const N*>::const_iterator iter;
1176
// go through the nodes of the cell
1177
for (iter = first; iter != last; iter++) {
1178
double nodeAxisValue;
1179
nodeAxisValue = (axis == Axis::Y ? (*iter)->getPosition().y() : (*iter)->getPosition().x());
1180
if (nodeAxisValue > maxAxisValue) {
1181
maxAxisValue = nodeAxisValue;
1182
}
1183
}
1184
assert(maxAxisValue > 0);
1185
#ifdef KDTP_DEBUG_LEVEL_1
1186
assert((!myHasNodesSortedWrtToMyAxis || axis != myAxis) || maxAxisValue == returnValue);
1187
#endif
1188
return maxAxisValue;
1189
}
1190
1191
template<class E, class N, class V>
1192
double KDTreePartition<E, N, V>::Cell::maxAxisValue() const {
1193
return maxAxisValue(myAxis);
1194
}
1195
1196
template<class E, class N, class V>
1197
size_t KDTreePartition<E, N, V>::Cell::partition() {
1198
typename std::vector<const N*>::iterator first = mySortedNodes->begin() + myFromInclusive;
1199
typename std::vector<const N*>::iterator last = mySortedNodes->begin() + myToExclusive;
1200
if (myAxis == Axis::Y) {
1201
std::sort(first, last, NodeYComparator());
1202
} else {
1203
std::sort(first, last, NodeXComparator());
1204
}
1205
myHasNodesSortedWrtToMyAxis = true;
1206
if (mySupercell) {
1207
// sorting at one level destroys order at higher levels (but preserves the median split property)
1208
mySupercell->myHasNodesSortedWrtToMyAxis = false;
1209
}
1210
size_t length = myToExclusive - myFromInclusive;
1211
size_t medianIndex = myFromInclusive + (length % 2 == 0 ? length / 2 - 1 : (length + 1) / 2 - 1);
1212
#ifndef KDTP_FOR_SYNTHETIC_NETWORKS
1213
// notice that nodes with indexes medianIndex and medianIndex+1 may have the same coordinate in the direction of myAxis -
1214
// in that case, they would be ordered and distributed between the two subcells with a tie-breaking rule,
1215
// and the spatial extent of cells alone would not suffice to decide whether a node belongs to a certain cell or not
1216
// for real-world road networks, this should occur very rarely
1217
// therefore, a simple but perfectly acceptable remedy is to shift the median index until the nodes with indexes
1218
// medianIndex and medianIndex+1 have different coordinates
1219
// this will distort the 50%/50% distribution of nodes just a little bit (and only under very rare circumstances)
1220
// hence we can assume zero impact on performance
1221
// note that this may happen more frequently for e.g. synthetic networks placing nodes at a regular, constant grid.
1222
// for this case, a different solution is provided, see code within #ifdef KDTP_FOR_SYNTHETIC_NETWORKS ... #endif
1223
const N* medianNode = (*mySortedNodes)[medianIndex];
1224
const N* afterMedianNode = (*mySortedNodes)[medianIndex + 1];
1225
double medianNodeCoordinate = myAxis == Axis::X ? medianNode->getPosition().x()
1226
: medianNode->getPosition().y();
1227
double afterMedianNodeCoordinate = myAxis == Axis::X ? afterMedianNode->getPosition().x()
1228
: afterMedianNode->getPosition().y();
1229
while (medianNodeCoordinate == afterMedianNodeCoordinate && medianIndex < myToExclusive - 3) {
1230
#ifdef KDTP_DEBUG_LEVEL_2
1231
std::cout << "Found spatially conflicting nodes." << std::endl;
1232
#endif
1233
medianIndex++;
1234
medianNode = (*mySortedNodes)[medianIndex];
1235
afterMedianNode = (*mySortedNodes)[medianIndex + 1];
1236
medianNodeCoordinate = myAxis == Axis::X ? medianNode->getPosition().x()
1237
: medianNode->getPosition().y();
1238
afterMedianNodeCoordinate = myAxis == Axis::X ? afterMedianNode->getPosition().x()
1239
: afterMedianNode->getPosition().y();
1240
}
1241
#endif
1242
myMedianCoordinate = medianNodeCoordinate;
1243
return medianIndex;
1244
}
1245
1246
template<class E, class N, class V>
1247
void KDTreePartition<E, N, V>::Cell::completeSpatialInfo() {
1248
// complete missing information about the cell's spatial extent
1249
if (myMinX < 0) {
1250
myMinX = minAxisValue(Axis::X);
1251
}
1252
if (myMaxX < 0) {
1253
myMaxX = maxAxisValue(Axis::X);
1254
}
1255
if (myMinY < 0) {
1256
myMinY = minAxisValue(Axis::Y);
1257
}
1258
if (myMaxY < 0) {
1259
myMaxY = maxAxisValue(Axis::Y);
1260
}
1261
myHasCompleteSpatialInfo = true;
1262
}
1263
1264
template<class E, class N, class V>
1265
std::unordered_set<const E*>* KDTreePartition<E, N, V>::Cell::edgeSet(const V* const vehicle) const {
1266
std::unordered_set<const E*>* edgeSet = new std::unordered_set<const E*>();
1267
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1268
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1269
typename std::vector<const N*>::const_iterator iter;
1270
for (iter = first; iter != last; iter++) {
1271
const N* edgeNode;
1272
const std::vector<const E*>& incomingEdges = (*iter)->getIncoming();
1273
for (const E* incomingEdge : incomingEdges) {
1274
if (isProhibited(incomingEdge, vehicle)) {
1275
continue;
1276
}
1277
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
1278
if (incomingEdge->isInternal()) {
1279
continue;
1280
}
1281
#endif
1282
edgeNode = incomingEdge->getFromJunction();
1283
if (contains(edgeNode)) {
1284
edgeSet->insert(incomingEdge);
1285
}
1286
}
1287
const std::vector<const E*>& outgoingEdges = (*iter)->getOutgoing();
1288
for (const E* outgoingEdge : outgoingEdges) {
1289
if (isProhibited(outgoingEdge, vehicle)) {
1290
continue;
1291
}
1292
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
1293
if (outgoingEdge->isInternal()) {
1294
continue;
1295
}
1296
#endif
1297
edgeNode = outgoingEdge->getToJunction();
1298
if (contains(edgeNode)) {
1299
edgeSet->insert(outgoingEdge);
1300
}
1301
}
1302
}
1303
return edgeSet;
1304
}
1305
1306
template<class E, class N, class V>
1307
size_t KDTreePartition<E, N, V>::Cell::numberOfEdgesEndingInCell(const V* const vehicle) const {
1308
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1309
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1310
typename std::vector<const N*>::const_iterator iter;
1311
size_t edgeCounter = 0;
1312
for (iter = first; iter != last; iter++) {
1313
const std::vector<const E*>& incomingEdges = (*iter)->getIncoming();
1314
for (const E* incomingEdge : incomingEdges) {
1315
if (isProhibited(incomingEdge, vehicle)) {
1316
continue;
1317
}
1318
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
1319
if (incomingEdge->isInternal()) {
1320
continue;
1321
} else {
1322
edgeCounter++;
1323
}
1324
#endif
1325
}
1326
}
1327
return edgeCounter;
1328
}
1329
1330
template<class E, class N, class V>
1331
size_t KDTreePartition<E, N, V>::Cell::numberOfEdgesStartingInCell(const V* const vehicle) const {
1332
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1333
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1334
typename std::vector<const N*>::const_iterator iter;
1335
size_t edgeCounter = 0;
1336
for (iter = first; iter != last; iter++) {
1337
const std::vector<const E*>& outgoingEdges = (*iter)->getOutgoing();
1338
for (const E* outgoingEdge : outgoingEdges) {
1339
if (isProhibited(outgoingEdge, vehicle)) {
1340
continue;
1341
}
1342
#ifdef KDTP_EXCLUDE_INTERNAL_EDGES
1343
if (outgoingEdge->isInternal()) {
1344
continue;
1345
} else {
1346
edgeCounter++;
1347
}
1348
}
1349
#endif
1350
}
1351
return edgeCounter;
1352
}
1353
1354
template<class E, class N, class V>
1355
std::pair<typename std::vector<const N*>::const_iterator,
1356
typename std::vector<const N*>::const_iterator> KDTreePartition<E, N, V>::Cell::nodeIterators() const {
1357
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1358
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1359
std::pair<typename std::vector<const N*>::const_iterator,
1360
typename std::vector<const N*>::const_iterator> iterators = std::make_pair(first, last);
1361
return iterators;
1362
}
1363
1364
template<class E, class N, class V>
1365
std::vector<const N*>* KDTreePartition<E, N, V>::Cell::nodes() const {
1366
typename std::vector<const N*>::const_iterator first = mySortedNodes->begin() + myFromInclusive;
1367
typename std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1368
std::vector<const N*>* nodes = new std::vector<const N*>(first, last);
1369
return nodes;
1370
}
1371
1372
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
1373
template<class E, class N, class V>
1374
std::pair<std::unordered_set<const N*>*,
1375
std::unordered_set<const N*>*> KDTreePartition<E, N, V>::Cell::spatialConflictNodes(size_t medianIndex) const {
1376
std::unordered_set<const N*>* leftOrLowerSpatialConflictNodes = new std::unordered_set<const N*>();
1377
std::unordered_set<const N*>* rightOrUpperSpatialConflictNodes = new std::unordered_set<const N*>();
1378
std::pair<std::unordered_set<const N*>*, std::unordered_set<const N*>*> spatialConflictNodes
1379
= std::make_pair(leftOrLowerSpatialConflictNodes, rightOrUpperSpatialConflictNodes);
1380
std::vector<const N*>::const_iterator iter, prev;
1381
if (myAxis == Axis::X) {
1382
if ((*mySortedNodes)[medianIndex]->getPosition().x() == (*mySortedNodes)[medianIndex + 1]->getPosition().x()) {
1383
double sharedCoordinate = (*mySortedNodes)[medianIndex]->getPosition().x();
1384
std::vector<const N*>::iterator firstLeftOrLower = mySortedNodes->begin() + medianIndex;
1385
// this is last since we go backward
1386
std::vector<const N*>::iterator last = mySortedNodes->begin() + myFromInclusive - 1;
1387
for (iter = firstLeftOrLower; ((*iter)->getPosition().x() == sharedCoordinate) && (iter != last); iter--) {
1388
leftOrLowerSpatialConflictNodes->insert(*iter);
1389
}
1390
}
1391
} else {
1392
if ((*mySortedNodes)[medianIndex]->getPosition().y() == (*mySortedNodes)[medianIndex + 1]->getPosition().y()) {
1393
double sharedCoordinate = (*mySortedNodes)[medianIndex]->getPosition().y();
1394
std::vector<const N*>::iterator firstRightOrUpper = mySortedNodes->begin() + medianIndex + 1;
1395
std::vector<const N*>::const_iterator last = mySortedNodes->begin() + myToExclusive;
1396
for (iter = firstRightOrUpper; ((*iter)->getPosition().y() == sharedCoordinate) && (iter != last); iter++) {
1397
rightOrUpperSpatialConflictNodes->insert(*iter);
1398
}
1399
}
1400
}
1401
return spatialConflictNodes;
1402
}
1403
#endif
1404
1405
template<class E, class N, class V>
1406
bool KDTreePartition<E, N, V>::Cell::isInBounds(const N* node) const {
1407
double nodeX = node->getPosition().x();
1408
double nodeY = node->getPosition().y();
1409
if (nodeX < myMinX || nodeX > myMaxX || nodeY < myMinY || nodeY > myMaxY) {
1410
return false;
1411
}
1412
return true;
1413
}
1414
1415
template<class E, class N, class V>
1416
bool KDTreePartition<E, N, V>::Cell::contains(const N* node) const {
1417
if (myLevel == 0) { // p.d., the root cell contains all nodes
1418
return true;
1419
}
1420
if (!isInBounds(node)) {
1421
#ifdef KDTP_DEBUG_LEVEL_2
1422
std::cout << "Not in bounds, nX: " << node->getPosition().x() << ", nY: " << node->getPosition().y() << std::endl;
1423
#endif
1424
return false;
1425
}
1426
#ifdef KDTP_DEBUG_LEVEL_2
1427
else {
1428
std::cout << "Node is in bounds!" << std::endl;
1429
}
1430
#endif
1431
#ifdef KDTP_FOR_SYNTHETIC_NETWORKS
1432
//
1433
double nodeX = node->getPosition().x();
1434
double nodeY = node->getPosition().y();
1435
#ifdef KDTP_DEBUG_LEVEL_2
1436
std::cout << "Entered contains, nodeX: " << nodeX << ", nodeY: " << nodeY << std::endl;
1437
#endif
1438
double northY = -1;
1439
if (myNorthernConflictNodes && !myNorthernConflictNodes->empty()) {
1440
northY = (*(myNorthernConflictNodes->begin()))->getPosition().y();
1441
}
1442
double eastX = -1;
1443
if (myEasternConflictNodes && !myEasternConflictNodes->empty()) {
1444
eastX = (*(myEasternConflictNodes->begin()))->getPosition().x();
1445
}
1446
double southY = -1;
1447
if (mySouthernConflictNodes && !mySouthernConflictNodes->empty()) {
1448
southY = (*(mySouthernConflictNodes->begin()))->getPosition().y();
1449
}
1450
double westX = -1;
1451
if (myWesternConflictNodes && !myWesternConflictNodes->empty()) {
1452
westX = (*(myWesternConflictNodes->begin()))->getPosition().x();
1453
}
1454
#ifdef KDTP_DEBUG_LEVEL_2
1455
std::cout << "northY: " << northY << ", eastX: " << eastX << ", southY: " << southY << ", westX: " << westX << std::endl;
1456
#endif
1457
if (nodeX == eastX) { // we have to test the eastern conflict nodes
1458
#ifdef KDTP_DEBUG_LEVEL_2
1459
std::cout << "On eastern bound, nX: " << node->getPosition().x() << ", nY: " << node->getPosition().y() << std::endl;
1460
#endif
1461
return myEasternConflictNodes->find(node) != myEasternConflictNodes->end();
1462
}
1463
if (nodeX == westX) { // we have to test the western conflict nodes
1464
#ifdef KDTP_DEBUG_LEVEL_2
1465
std::cout << "On western bound, nX: " << node->getPosition().x() << ", nY: " << node->getPosition().y() << std::endl;
1466
#endif
1467
return myWesternConflictNodes->find(node) != myWesternConflictNodes->end();
1468
}
1469
if (nodeY == northY) { // we have to test the northern conflict nodes
1470
#ifdef KDTP_DEBUG_LEVEL_2
1471
std::cout << "On northern bound, nX: " << node->getPosition().x() << ", nY: " << node->getPosition().y() << std::endl;
1472
#endif
1473
return myNorthernConflictNodes->find(node) != myNorthernConflictNodes->end();
1474
}
1475
if (nodeY == southY) { // we have to test the southern conflict nodes
1476
#ifdef KDTP_DEBUG_LEVEL_2
1477
std::cout << "On southern bound, nX: " << node->getPosition().x() << ", nY: " << node->getPosition().y() << std::endl;
1478
#endif
1479
return mySouthernConflictNodes->find(node) != myEasternConflictNodes->end();
1480
}
1481
#endif
1482
#ifdef KDTP_DEBUG_LEVEL_2
1483
std::cout << "Node does not lie on a border!" << std::endl;
1484
#endif
1485
return true; // if the node does not lie on a spatial border, the passed in-bounds test suffices
1486
}
1487
1488
template<class E, class N, class V>
1489
const typename KDTreePartition<E, N, V>::Cell* KDTreePartition<E, N, V>::searchNode(const N* node) const {
1490
const typename KDTreePartition<E, N, V>::Cell* cell = myRoot;
1491
if (!myRoot->contains(node)) {
1492
return nullptr;
1493
}
1494
while (true) {
1495
assert(cell);
1496
double nodeCoordinate = cell->getAxis() == Axis::X ? node->getPosition().x() : node->getPosition().y();
1497
const typename KDTreePartition<E, N, V>::Cell* nextCell = nodeCoordinate <= cell->getMedianCoordinate() ?
1498
cell->getLeftOrLowerSubcell() : cell->getRightOrUpperSubcell();
1499
if (nextCell == nullptr) {
1500
return cell;
1501
} else {
1502
cell = nextCell;
1503
}
1504
}
1505
}
1506
1507