2
2
#define STATIC_RTREE_HPP
3
3
4
4
#include " storage/tar_fwd.hpp"
5
-
6
5
#include " util/bearing.hpp"
7
6
#include " util/coordinate_calculation.hpp"
8
7
#include " util/deallocating_vector.hpp"
11
10
#include " util/integer_range.hpp"
12
11
#include " util/mmap_file.hpp"
13
12
#include " util/rectangle.hpp"
13
+ #include " util/timing_util.hpp"
14
14
#include " util/typedefs.hpp"
15
15
#include " util/vector_view.hpp"
16
16
#include " util/web_mercator.hpp"
@@ -487,70 +487,9 @@ class StaticRTree
487
487
Rectangle needs to be projected!*/
488
488
std::vector<EdgeDataT> SearchInBox (const Rectangle &search_rectangle) const
489
489
{
490
- const Rectangle projected_rectangle{
491
- search_rectangle.min_lon ,
492
- search_rectangle.max_lon ,
493
- toFixed (FloatLatitude{
494
- web_mercator::latToY (toFloating (FixedLatitude (search_rectangle.min_lat )))}),
495
- toFixed (FloatLatitude{
496
- web_mercator::latToY (toFloating (FixedLatitude (search_rectangle.max_lat )))})};
497
490
std::vector<EdgeDataT> results;
498
-
499
- std::queue<TreeIndex> traversal_queue;
500
- traversal_queue.push (TreeIndex{});
501
-
502
- while (!traversal_queue.empty ())
503
- {
504
- auto const current_tree_index = traversal_queue.front ();
505
- traversal_queue.pop ();
506
-
507
- // If we're at the bottom of the tree, we need to explore the
508
- // element array
509
- if (is_leaf (current_tree_index))
510
- {
511
-
512
- // Note: irange is [start,finish), so we need to +1 to make sure we visit the
513
- // last
514
- for (const auto current_child_index : child_indexes (current_tree_index))
515
- {
516
- const auto ¤t_edge = m_objects[current_child_index];
517
-
518
- // we don't need to project the coordinates here,
519
- // because we use the unprojected rectangle to test against
520
- const Rectangle bbox{std::min (m_coordinate_list[current_edge.u ].lon ,
521
- m_coordinate_list[current_edge.v ].lon ),
522
- std::max (m_coordinate_list[current_edge.u ].lon ,
523
- m_coordinate_list[current_edge.v ].lon ),
524
- std::min (m_coordinate_list[current_edge.u ].lat ,
525
- m_coordinate_list[current_edge.v ].lat ),
526
- std::max (m_coordinate_list[current_edge.u ].lat ,
527
- m_coordinate_list[current_edge.v ].lat )};
528
-
529
- // use the _unprojected_ input rectangle here
530
- if (bbox.Intersects (search_rectangle))
531
- {
532
- results.push_back (current_edge);
533
- }
534
- }
535
- }
536
- else
537
- {
538
- BOOST_ASSERT (current_tree_index.level + 1 < m_tree_level_starts.size ());
539
-
540
- for (const auto child_index : child_indexes (current_tree_index))
541
- {
542
- const auto &child_rectangle =
543
- m_search_tree[child_index].minimum_bounding_rectangle ;
544
-
545
- if (child_rectangle.Intersects (projected_rectangle))
546
- {
547
- traversal_queue.push (TreeIndex (
548
- current_tree_index.level + 1 ,
549
- child_index - m_tree_level_starts[current_tree_index.level + 1 ]));
550
- }
551
- }
552
- }
553
- }
491
+ SearchInBox (search_rectangle,
492
+ [&results](const auto &edge_data) { results.push_back (edge_data); });
554
493
return results;
555
494
}
556
495
@@ -565,15 +504,56 @@ class StaticRTree
565
504
{ return num_results >= max_results; });
566
505
}
567
506
507
+ // NB 1: results are not guaranteed to be sorted by distance
508
+ // NB 2: maxDistanceMeters is not a hard limit, it's just a way to reduce the number of edges
509
+ // returned
510
+ template <typename FilterT>
511
+ std::vector<CandidateSegment> SearchInRange (const Coordinate input_coordinate,
512
+ double maxDistanceMeters,
513
+ const FilterT filter) const
514
+ {
515
+ auto projected_coordinate = web_mercator::fromWGS84 (input_coordinate);
516
+ Coordinate fixed_projected_coordinate{projected_coordinate};
517
+
518
+ auto bbox = Rectangle::ExpandMeters (input_coordinate, maxDistanceMeters);
519
+ std::vector<CandidateSegment> results;
520
+
521
+ SearchInBox (
522
+ bbox,
523
+ [&results, &filter, fixed_projected_coordinate, this ](const EdgeDataT ¤t_edge)
524
+ {
525
+ const auto projected_u = web_mercator::fromWGS84 (m_coordinate_list[current_edge.u ]);
526
+ const auto projected_v = web_mercator::fromWGS84 (m_coordinate_list[current_edge.v ]);
527
+
528
+ auto [_, projected_nearest] = coordinate_calculation::projectPointOnSegment (
529
+ projected_u, projected_v, fixed_projected_coordinate);
530
+
531
+ CandidateSegment current_candidate{projected_nearest, current_edge};
532
+ auto use_segment = filter (current_candidate);
533
+ if (!use_segment.first && !use_segment.second )
534
+ {
535
+ return ;
536
+ }
537
+ current_candidate.data .forward_segment_id .enabled &= use_segment.first ;
538
+ current_candidate.data .reverse_segment_id .enabled &= use_segment.second ;
539
+
540
+ results.push_back (current_candidate);
541
+ });
542
+
543
+ return results;
544
+ }
545
+
568
546
// Return edges in distance order with the coordinate of the closest point on the edge.
569
547
template <typename FilterT, typename TerminationT>
570
548
std::vector<CandidateSegment> Nearest (const Coordinate input_coordinate,
571
549
const FilterT filter,
572
550
const TerminationT terminate) const
573
551
{
574
552
std::vector<CandidateSegment> results;
553
+
575
554
auto projected_coordinate = web_mercator::fromWGS84 (input_coordinate);
576
555
Coordinate fixed_projected_coordinate{projected_coordinate};
556
+
577
557
// initialize queue with root element
578
558
std::priority_queue<QueryCandidate> traversal_queue;
579
559
traversal_queue.push (QueryCandidate{0 , TreeIndex{}});
@@ -631,6 +611,73 @@ class StaticRTree
631
611
}
632
612
633
613
private:
614
+ template <typename Callback>
615
+ void SearchInBox (const Rectangle &search_rectangle, Callback &&callback) const
616
+ {
617
+ const Rectangle projected_rectangle{
618
+ search_rectangle.min_lon ,
619
+ search_rectangle.max_lon ,
620
+ toFixed (FloatLatitude{
621
+ web_mercator::latToY (toFloating (FixedLatitude (search_rectangle.min_lat )))}),
622
+ toFixed (FloatLatitude{
623
+ web_mercator::latToY (toFloating (FixedLatitude (search_rectangle.max_lat )))})};
624
+ std::queue<TreeIndex> traversal_queue;
625
+ traversal_queue.push (TreeIndex{});
626
+
627
+ while (!traversal_queue.empty ())
628
+ {
629
+ auto const current_tree_index = traversal_queue.front ();
630
+ traversal_queue.pop ();
631
+
632
+ // If we're at the bottom of the tree, we need to explore the
633
+ // element array
634
+ if (is_leaf (current_tree_index))
635
+ {
636
+
637
+ // Note: irange is [start,finish), so we need to +1 to make sure we visit the
638
+ // last
639
+ for (const auto current_child_index : child_indexes (current_tree_index))
640
+ {
641
+ const auto ¤t_edge = m_objects[current_child_index];
642
+
643
+ // we don't need to project the coordinates here,
644
+ // because we use the unprojected rectangle to test against
645
+ const Rectangle bbox{std::min (m_coordinate_list[current_edge.u ].lon ,
646
+ m_coordinate_list[current_edge.v ].lon ),
647
+ std::max (m_coordinate_list[current_edge.u ].lon ,
648
+ m_coordinate_list[current_edge.v ].lon ),
649
+ std::min (m_coordinate_list[current_edge.u ].lat ,
650
+ m_coordinate_list[current_edge.v ].lat ),
651
+ std::max (m_coordinate_list[current_edge.u ].lat ,
652
+ m_coordinate_list[current_edge.v ].lat )};
653
+
654
+ // use the _unprojected_ input rectangle here
655
+ if (bbox.Intersects (search_rectangle))
656
+ {
657
+ callback (current_edge);
658
+ }
659
+ }
660
+ }
661
+ else
662
+ {
663
+ BOOST_ASSERT (current_tree_index.level + 1 < m_tree_level_starts.size ());
664
+
665
+ for (const auto child_index : child_indexes (current_tree_index))
666
+ {
667
+ const auto &child_rectangle =
668
+ m_search_tree[child_index].minimum_bounding_rectangle ;
669
+
670
+ if (child_rectangle.Intersects (projected_rectangle))
671
+ {
672
+ traversal_queue.push (TreeIndex (
673
+ current_tree_index.level + 1 ,
674
+ child_index - m_tree_level_starts[current_tree_index.level + 1 ]));
675
+ }
676
+ }
677
+ }
678
+ }
679
+ }
680
+
634
681
/* *
635
682
* Iterates over all the objects in a leaf node and inserts them into our
636
683
* search priority queue. The speed of this function is very much governed
0 commit comments