@@ -94,6 +94,39 @@ void IterateAllSuffixes(const absl::flat_hash_set<string>& words,
94
94
}
95
95
}
96
96
97
+ double ConvertToRadiusInMeters (size_t radius, std::string_view arg) {
98
+ const std::string unit = absl::AsciiStrToUpper (arg);
99
+ if (unit == " M" ) {
100
+ return radius * 1 ;
101
+ } else if (unit == " KM" ) {
102
+ return radius * 1000 ;
103
+ } else if (unit == " FT" ) {
104
+ return radius * 0.3048 ;
105
+ } else if (unit == " MI" ) {
106
+ return radius * 1609.34 ;
107
+ } else {
108
+ return -1 ;
109
+ }
110
+ }
111
+
112
+ std::optional<GeoIndex::point> GetGeoPoint (const DocumentAccessor& doc, string_view field) {
113
+ auto element = doc.GetStrings (field);
114
+
115
+ if (!element)
116
+ return std::nullopt ;
117
+
118
+ absl::InlinedVector<string_view, 2 > coordinates = absl::StrSplit (element.value ()[0 ], " ," );
119
+
120
+ if (coordinates.size () != 2 )
121
+ return std::nullopt ;
122
+
123
+ double lat, lon;
124
+ if (!absl::SimpleAtod (coordinates[0 ], &lat) || !absl::SimpleAtod (coordinates[1 ], &lon))
125
+ return nullopt ;
126
+
127
+ return GeoIndex::point{lat, lon};
128
+ }
129
+
97
130
}; // namespace
98
131
99
132
class RangeTreeAdapter : public NumericIndex ::RangeTreeBase {
@@ -638,15 +671,18 @@ void GeoIndex::Remove(DocId id, const DocumentAccessor& doc, string_view field)
638
671
rtree_->remove ({doc_point.value (), id});
639
672
}
640
673
641
- std::vector<DocId> GeoIndex::RadiusSearch (double lat, double lon, double radius) const {
674
+ std::vector<DocId> GeoIndex::RadiusSearch (double lat, double lon, double radius,
675
+ std::string_view unit) {
642
676
std::vector<DocId> results;
643
677
644
- // Declare the geographic_point_circle strategy (with 36 points)
645
- // Default template arguments (taking Andoyer strategy)
646
- boost::geometry::strategy::buffer::geographic_point_circle<> point_strategy (36 );
678
+ // Get radius in meters
679
+ double converted_radius = ConvertToRadiusInMeters (radius, unit);
680
+
681
+ // Declare the geographic_point_circle strategy with 4 points
682
+ boost::geometry::strategy::buffer::geographic_point_circle<> point_strategy (4 );
647
683
648
684
// Declare the distance strategy in meters around the point
649
- boost::geometry::strategy::buffer::distance_symmetric<double > distance_strategy (radius );
685
+ boost::geometry::strategy::buffer::distance_symmetric<double > distance_strategy (converted_radius );
650
686
651
687
// Declare other necessary strategies, unused for point
652
688
boost::geometry::strategy::buffer::join_round join_strategy;
@@ -655,59 +691,32 @@ std::vector<DocId> GeoIndex::RadiusSearch(double lat, double lon, double radius)
655
691
656
692
point p{lat, lon};
657
693
658
- // Create the buffer of a point on the Earth
659
- boost::geometry::model::multi_polygon<boost::geometry::model::polygon<point>> result ;
694
+ // Create polygon with 4 point around point
695
+ boost::geometry::model::multi_polygon<boost::geometry::model::polygon<point>> buffer_polygon ;
660
696
661
- boost::geometry::buffer (p, result , distance_strategy, side_strategy, join_strategy, end_strategy ,
662
- point_strategy);
697
+ boost::geometry::buffer (p, buffer_polygon , distance_strategy, side_strategy, join_strategy,
698
+ end_strategy, point_strategy);
663
699
664
- rtree_-> query ( boost::geometry::index::within (result),
665
- boost::make_function_output_iterator (
666
- [&results]( auto const & val) { results. push_back (val. second ); }) );
700
+ // Create bouding box around polygon to include all possible points
701
+ boost::geometry::model::box<point> box;
702
+ boost::geometry::envelope (buffer_polygon, box );
667
703
668
- return results;
669
- }
704
+ rtree_->query (
705
+ boost::geometry::index::within (box),
706
+ boost::make_function_output_iterator ([&results, &p, &converted_radius](auto const & val) {
707
+ if (boost::geometry::distance (val.first , p) <= converted_radius) {
708
+ results.push_back (val.second );
709
+ }
710
+ }));
670
711
671
- double GeoIndex::ConvertToRadiusInMeters (size_t radius, std::string_view arg) {
672
- const std::string unit = absl::AsciiStrToUpper (arg);
673
- if (unit == " M" ) {
674
- return radius * 1 ;
675
- } else if (unit == " KM" ) {
676
- return radius * 1000 ;
677
- } else if (unit == " FT" ) {
678
- return radius * 0.3048 ;
679
- } else if (unit == " MI" ) {
680
- return radius * 1609.34 ;
681
- } else {
682
- return -1 ;
683
- }
712
+ return results;
684
713
}
685
714
686
- std::optional<GeoIndex::point> GeoIndex::GetGeoPoint (const DocumentAccessor& doc,
687
- string_view field) {
688
- auto element = doc.GetStrings (field);
689
-
690
- if (!element) {
691
- return std::nullopt ;
692
- }
693
-
694
- absl::InlinedVector<string_view, 2 > coordinates = absl::StrSplit (element.value ()[0 ], " ," );
695
-
696
- if (coordinates.size () != 2 ) {
697
- return std::nullopt ;
698
- }
699
-
700
- double lat;
701
- if (!absl::SimpleAtod (coordinates[0 ], &lat)) {
702
- return std::nullopt ;
703
- }
704
-
705
- double lon;
706
- if (!absl::SimpleAtod (coordinates[1 ], &lon)) {
707
- return std::nullopt ;
708
- }
709
-
710
- return point{lat, lon};
715
+ std::vector<DocId> GeoIndex::GetAllDocsWithNonNullValues () const {
716
+ std::vector<DocId> results;
717
+ std::for_each (boost::geometry::index::begin (*rtree_), boost::geometry::index::end (*rtree_),
718
+ [&results](auto const & val) { results.push_back (val.second ); });
719
+ return results;
711
720
}
712
721
713
722
} // namespace dfly::search
0 commit comments