Skip to content

Commit bcd88d7

Browse files
genadzkevinkreiser
andauthored
Double precision for lon lat (valhalla#2693)
* Introduce Point2d and Vector2d * Use double precision for GeoPoint * Read ll from json as double * Fix unit tests * Fix double precision for height action * Continue fix tests * hopefully reduce pointll hash collisions, fix long standing but benign bugs in decode7/encode7 * allow differnt precision on encode/decode7 * use 7 digits of precision for finding other places precision is lost * make 7digit precision possible with a preprocessor defintion * store 7bits of precision in OSMNode daat tile building time * Fix hash collisions for PointXY * Fix tiles unit test * Don't loose precision while setting lon,lat to OSMNode * Fix test_trimming * Fix thor_worker test * Fix matrix test * 7 digits of precision for nodeinfo ll * refactor TileHierarchy while tracking down a typo :( * update isochrone test * update summary shape * fix map match test * fix astar test * lint * update summary * use double precision for path edges in loki search * use our own hash_combine since older boost doesnt ahve it at same place * more doubles in place of floats * more doubles to shut up clang * working on bss tests * fixed one test in the suite * slight differences to bss testing * roll our own hash_combine for since boost relocates it * forgot to remove header * explicit instantiations * tidy * smarter isochrone test * cleanup comments etc * changelog derp Co-authored-by: Kevin Kreiser <[email protected]>
1 parent bec6b20 commit bcd88d7

File tree

96 files changed

+811
-772
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+811
-772
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@
199199
* ADDED: Added functions for predicted speeds encoding-decoding [#2674](https://github.com/valhalla/valhalla/pull/2674)
200200
* ADDED: Time invariant routing via the bidirectional algorithm. This has the effect that when time dependent routes (arrive_by and depart_at) fall back to bidirectional due to length restrictions they will actually use the correct time of day for one of the search directions [#2660](https://github.com/valhalla/valhalla/pull/2660)
201201
* ADDED: If the length of the edge is greater than kMaxEdgeLength, then consider this a catastrophic error if the should_error bool is true in the set_length function. [2678](https://github.com/valhalla/valhalla/pull/2678)
202+
* ADDED: Moved lat,lon coordinates structures from single to double precision. Improves geometry accuracy noticibly at zooms above 17 as well as coordinate snapping and any other geometric operations. Addes about a 2% performance pentalty for standard routes. Graph nodes now have 7 digits of precision. [#2693](https://github.com/valhalla/valhalla/pull/2693)
202203

203204
## Release Date: 2019-11-21 Valhalla 3.0.9
204205
* **Bug Fix**

proto/tripcommon.proto

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ option optimize_for = LITE_RUNTIME;
33
package valhalla;
44

55
message LatLng {
6-
optional float lat = 1;
7-
optional float lng = 2;
6+
optional double lat = 1;
7+
optional double lng = 2;
88
}
99

1010
message BoundingBox {
@@ -34,10 +34,10 @@ message Location {
3434

3535
message PathEdge {
3636
optional uint64 graph_id = 1;
37-
optional float percent_along = 2;
37+
optional double percent_along = 2;
3838
optional LatLng ll = 3;
3939
optional SideOfStreet side_of_street = 4;
40-
optional float distance = 5;
40+
optional double distance = 5;
4141
optional int32 minimum_reachability = 6; //deprecated
4242
optional bool begin_node = 7;
4343
optional bool end_node = 8;

src/baldr/connectivity_map.cc

+13-13
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ connectivity_map_t::connectivity_map_t(const boost::property_tree::ptree& pt) {
116116
// See what kind of tiles we are dealing with here by getting a graphreader
117117
GraphReader reader(pt);
118118
auto tiles = reader.GetTileSet();
119-
transit_level = TileHierarchy::levels().rbegin()->second.level + 1;
119+
transit_level = TileHierarchy::GetTransitLevel().level;
120120

121121
// Quick hack to remove connectivity between known unconnected regions
122122
// The only land connection from north to south america is through
@@ -142,12 +142,12 @@ connectivity_map_t::connectivity_map_t(const boost::property_tree::ptree& pt) {
142142
// (build the ColorMap). Transit level uses local hierarchy tiles
143143
for (auto& color : colors) {
144144
if (color.first == transit_level) {
145-
TileHierarchy::levels().rbegin()->second.tiles.ColorMap(color.second, not_neighbors);
145+
TileHierarchy::GetTransitLevel().tiles.ColorMap(color.second, not_neighbors);
146146
} else {
147-
TileHierarchy::levels()
148-
.find(color.first)
149-
->second.tiles.ColorMap(color.second,
150-
color.first == 2 ? not_neighbors : decltype(not_neighbors){});
147+
TileHierarchy::levels()[color.first].tiles.ColorMap(color.second,
148+
color.first == 2
149+
? not_neighbors
150+
: decltype(not_neighbors){});
151151
}
152152
}
153153
}
@@ -173,7 +173,7 @@ std::unordered_set<size_t> connectivity_map_t::get_colors(uint32_t hierarchy_lev
173173
if (level == colors.cend()) {
174174
return result;
175175
}
176-
const auto& tiles = TileHierarchy::levels().find(hierarchy_level)->second.tiles;
176+
const auto& tiles = TileHierarchy::levels()[hierarchy_level].tiles;
177177
std::vector<const decltype(location.edges)*> edge_sets{&location.edges, &location.filtered_edges};
178178
for (const auto* edges : edge_sets) {
179179
for (const auto& edge : *edges) {
@@ -199,10 +199,10 @@ std::unordered_set<size_t> connectivity_map_t::get_colors(uint32_t hierarchy_lev
199199
std::string connectivity_map_t::to_geojson(const uint32_t hierarchy_level) const {
200200
// bail if we dont have the level
201201
uint32_t tile_level = (hierarchy_level == transit_level) ? transit_level - 1 : hierarchy_level;
202-
auto bbox = TileHierarchy::levels().find(tile_level);
203-
if (bbox == TileHierarchy::levels().cend()) {
202+
if (tile_level >= TileHierarchy::levels().size()) {
204203
throw std::runtime_error("hierarchy level not found");
205204
}
205+
const auto& tiles = TileHierarchy::levels()[tile_level].tiles;
206206

207207
// make a region map (inverse mapping of color to lists of tiles)
208208
// could cache this but shouldnt need to call it much
@@ -230,7 +230,7 @@ std::string connectivity_map_t::to_geojson(const uint32_t hierarchy_level) const
230230
std::unordered_map<size_t, polygon_t> boundaries;
231231
for (const auto& arity : arities) {
232232
auto& region = *regions.find(arity.second);
233-
boundaries.emplace(arity.second, to_boundary(region.second, bbox->second.tiles));
233+
boundaries.emplace(arity.second, to_boundary(region.second, tiles));
234234
}
235235

236236
// turn it into geojson
@@ -239,12 +239,12 @@ std::string connectivity_map_t::to_geojson(const uint32_t hierarchy_level) const
239239

240240
std::vector<size_t> connectivity_map_t::to_image(const uint32_t hierarchy_level) const {
241241
uint32_t tile_level = (hierarchy_level == transit_level) ? transit_level - 1 : hierarchy_level;
242-
auto bbox = TileHierarchy::levels().find(tile_level);
243-
if (bbox == TileHierarchy::levels().cend()) {
242+
if (tile_level >= TileHierarchy::levels().size()) {
244243
throw std::runtime_error("hierarchy level not found");
245244
}
245+
const auto& level_tiles = TileHierarchy::levels()[tile_level];
246246

247-
std::vector<size_t> tiles(bbox->second.tiles.nrows() * bbox->second.tiles.ncolumns(),
247+
std::vector<size_t> tiles(level_tiles.tiles.nrows() * level_tiles.tiles.ncolumns(),
248248
static_cast<uint32_t>(0));
249249
auto level = colors.find(hierarchy_level);
250250
if (level != colors.cend()) {

src/baldr/graphreader.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ GraphId GraphReader::GetShortcut(const GraphId& id) {
606606
};
607607

608608
// No shortcuts on the local level or transit level.
609-
if (id.level() >= TileHierarchy::levels().rbegin()->second.level) {
609+
if (id.level() >= TileHierarchy::levels().back().level) {
610610
return {};
611611
}
612612

@@ -799,7 +799,7 @@ std::unordered_set<GraphId> GraphReader::GetTileSet() const {
799799
} // or individually on disk
800800
else if (!tile_dir_.empty()) {
801801
// for each level
802-
for (uint8_t level = 0; level <= TileHierarchy::levels().rbegin()->first + 1; ++level) {
802+
for (uint8_t level = 0; level <= TileHierarchy::GetTransitLevel().level; ++level) {
803803
// crack open this level of tiles directory
804804
filesystem::path root_dir(tile_dir_ + filesystem::path::preferred_separator +
805805
std::to_string(level) + filesystem::path::preferred_separator);

src/baldr/graphtile.cc

+7-15
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,7 @@ GraphTile::FileSuffix(const GraphId& graphid, const std::string& fname_suffix, b
410410
*/
411411

412412
// figure the largest id for this level
413-
auto found = TileHierarchy::levels().find(graphid.level());
414-
if (found == TileHierarchy::levels().cend() &&
413+
if (graphid.level() >= TileHierarchy::levels().size() &&
415414
graphid.level() != TileHierarchy::GetTransitLevel().level) {
416415
throw std::runtime_error("Could not compute FileSuffix for non-existent level: " +
417416
std::to_string(graphid.level()));
@@ -420,7 +419,7 @@ GraphTile::FileSuffix(const GraphId& graphid, const std::string& fname_suffix, b
420419
// get the level info
421420
const auto& level = graphid.level() == TileHierarchy::GetTransitLevel().level
422421
? TileHierarchy::GetTransitLevel()
423-
: found->second;
422+
: TileHierarchy::levels()[graphid.level()];
424423

425424
// figure out how many digits
426425
auto max_id = level.tiles.ncolumns() * level.tiles.nrows() - 1;
@@ -513,8 +512,7 @@ GraphId GraphTile::GetTileId(const std::string& fname) {
513512
}
514513

515514
// if the first thing isnt a valid level bail
516-
auto found = TileHierarchy::levels().find(digits.back());
517-
if (found == TileHierarchy::levels().cend() &&
515+
if (digits.back() >= TileHierarchy::levels().size() &&
518516
digits.back() != TileHierarchy::GetTransitLevel().level) {
519517
throw std::runtime_error("Invalid tile path: " + fname);
520518
}
@@ -524,7 +522,7 @@ GraphId GraphTile::GetTileId(const std::string& fname) {
524522
digits.pop_back();
525523
const auto& tile_level = level == TileHierarchy::GetTransitLevel().level
526524
? TileHierarchy::GetTransitLevel()
527-
: found->second;
525+
: TileHierarchy::levels()[level];
528526

529527
// get the number of sub directories that we should have
530528
auto max_id = tile_level.tiles.ncolumns() * tile_level.tiles.nrows() - 1;
@@ -558,15 +556,9 @@ GraphId GraphTile::GetTileId(const std::string& fname) {
558556

559557
// Get the bounding box of this graph tile.
560558
AABB2<PointLL> GraphTile::BoundingBox() const {
561-
562-
// figure the largest id for this level
563-
auto level = TileHierarchy::levels().find(header_->graphid().level());
564-
if (level == TileHierarchy::levels().end() &&
565-
header_->graphid().level() == ((TileHierarchy::levels().rbegin())->second.level + 1)) {
566-
level = TileHierarchy::levels().begin();
567-
}
568-
569-
auto tiles = level->second.tiles;
559+
const auto& tiles = header_->graphid().level() == TileHierarchy::GetTransitLevel().level
560+
? TileHierarchy::GetTransitLevel().tiles
561+
: TileHierarchy::levels()[header_->graphid().level()].tiles;
570562
return tiles.TileBounds(header_->graphid().tileid());
571563
}
572564

src/baldr/merge.cc

-9
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,6 @@ namespace baldr {
1212
namespace merge {
1313

1414
namespace {
15-
16-
uint64_t count_tiles_in_levels(GraphReader& reader) {
17-
uint64_t tile_count = 0;
18-
for (const auto& level : TileHierarchy::levels() | bra::map_values) {
19-
tile_count += level.tiles.ncolumns() * level.tiles.nrows();
20-
}
21-
return tile_count;
22-
}
23-
2415
namespace iter {
2516

2617
// the "edges" struct provides a container wrapper for the edges leaving a node

src/baldr/nodeinfo.cc

+15-8
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ NodeInfo::NodeInfo() {
7272
}
7373

7474
NodeInfo::NodeInfo(const PointLL& tile_corner,
75-
const std::pair<float, float>& ll,
75+
const PointLL& ll,
7676
const uint32_t access,
7777
const NodeType type,
7878
const bool traffic_signal) {
@@ -84,14 +84,21 @@ NodeInfo::NodeInfo(const PointLL& tile_corner,
8484
}
8585

8686
// Sets the latitude and longitude.
87-
void NodeInfo::set_latlng(const PointLL& tile_corner, const std::pair<float, float>& ll) {
87+
void NodeInfo::set_latlng(const PointLL& tile_corner, const PointLL& ll) {
8888
// Protect against a node being slightly outside the tile (due to float roundoff)
89-
lat_offset_ = ll.second < tile_corner.lat()
90-
? 0
91-
: static_cast<uint32_t>((ll.second - tile_corner.lat()) / kDegreesPrecision);
92-
lon_offset_ = ll.first < tile_corner.lng()
93-
? 0
94-
: static_cast<uint32_t>((ll.first - tile_corner.lng()) / kDegreesPrecision);
89+
lat_offset_ = 0;
90+
if (ll.lat() > tile_corner.lat()) {
91+
auto lat = std::round((ll.lat() - tile_corner.lat()) / 1e-7);
92+
lat_offset_ = lat / 10;
93+
lat_offset7_ = lat - lat_offset_ * 10;
94+
}
95+
96+
lon_offset_ = 0;
97+
if (ll.lng() > tile_corner.lng()) {
98+
auto lon = std::round((ll.lng() - tile_corner.lng()) / 1e-7);
99+
lon_offset_ = lon / 10;
100+
lon_offset7_ = lon - lon_offset_ * 10;
101+
}
95102
}
96103

97104
// Set the index in the node's tile of its first outbound edge.

src/baldr/pathlocation.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ namespace valhalla {
55
namespace baldr {
66

77
PathLocation::PathEdge::PathEdge(const GraphId& id,
8-
const float percent_along,
8+
const double percent_along,
99
const midgard::PointLL& projected,
10-
const float score,
10+
const double score,
1111
const SideOfStreet sos,
1212
const unsigned int outbound_reach,
1313
const unsigned int inbound_reach)
@@ -47,8 +47,8 @@ bool PathLocation::shares_edges(const PathLocation& other) const {
4747
bool found = false;
4848
for (const auto& other_edge : other.edges) {
4949
if (edge.id == other_edge.id && edge.sos == other_edge.sos &&
50-
midgard::equal<float>(edge.percent_along, other_edge.percent_along) &&
51-
midgard::equal<float>(edge.distance, other_edge.distance, .1f) &&
50+
midgard::equal<double>(edge.percent_along, other_edge.percent_along) &&
51+
midgard::equal<double>(edge.distance, other_edge.distance, .1) &&
5252
edge.projected.ApproximatelyEqual(other_edge.projected)) {
5353
found = true;
5454
break;

src/baldr/tilehierarchy.cc

+27-26
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@ using namespace valhalla::midgard;
66
namespace valhalla {
77
namespace baldr {
88

9-
const std::map<uint8_t, TileLevel>& TileHierarchy::levels() {
9+
const std::vector<TileLevel>& TileHierarchy::levels() {
1010
// Static tile levels
11-
static const std::map<uint8_t, TileLevel> levels_ =
12-
{{2, TileLevel{2, stringToRoadClass("ServiceOther"), "local",
13-
midgard::Tiles<midgard::PointLL>{{{-180, -90}, {180, 90}},
14-
.25,
15-
static_cast<unsigned short>(kBinsDim)}}},
16-
{1, TileLevel{1, stringToRoadClass("Tertiary"), "arterial",
17-
midgard::Tiles<midgard::PointLL>{{{-180, -90}, {180, 90}},
18-
1,
19-
static_cast<unsigned short>(kBinsDim)}}},
20-
{0, TileLevel{0, stringToRoadClass("Primary"), "highway",
21-
midgard::Tiles<midgard::PointLL>{{{-180, -90}, {180, 90}},
22-
4,
23-
static_cast<unsigned short>(kBinsDim)}}}};
11+
static const std::vector<TileLevel> levels_ = {
12+
13+
TileLevel{0, stringToRoadClass("Primary"), "highway",
14+
midgard::Tiles<midgard::PointLL>{{{-180, -90}, {180, 90}},
15+
4,
16+
static_cast<unsigned short>(kBinsDim)}},
17+
18+
TileLevel{1, stringToRoadClass("Tertiary"), "arterial",
19+
midgard::Tiles<midgard::PointLL>{{{-180, -90}, {180, 90}},
20+
1,
21+
static_cast<unsigned short>(kBinsDim)}},
22+
23+
TileLevel{2, stringToRoadClass("ServiceOther"), "local",
24+
midgard::Tiles<midgard::PointLL>{{{-180, -90}, {180, 90}},
25+
.25,
26+
static_cast<unsigned short>(kBinsDim)}},
27+
};
2428

2529
return levels_;
2630
}
@@ -46,9 +50,8 @@ midgard::AABB2<midgard::PointLL> TileHierarchy::GetGraphIdBoundingBox(const Grap
4650
// If the level is not supported an invalid id will be returned.
4751
GraphId TileHierarchy::GetGraphId(const midgard::PointLL& pointll, const uint8_t level) {
4852
GraphId id;
49-
const auto& tl = levels().find(level);
50-
if (tl != levels().end()) {
51-
auto tile_id = tl->second.tiles.TileId(pointll);
53+
if (level < levels().size()) {
54+
auto tile_id = levels()[level].tiles.TileId(pointll);
5255
if (tile_id >= 0) {
5356
id = {static_cast<uint32_t>(tile_id), level, 0};
5457
}
@@ -58,9 +61,9 @@ GraphId TileHierarchy::GetGraphId(const midgard::PointLL& pointll, const uint8_t
5861

5962
// Gets the hierarchy level given the road class.
6063
uint8_t TileHierarchy::get_level(const RoadClass roadclass) {
61-
if (roadclass <= levels().find(0)->second.importance) {
64+
if (roadclass <= levels()[0].importance) {
6265
return 0;
63-
} else if (roadclass <= levels().find(1)->second.importance) {
66+
} else if (roadclass <= levels()[1].importance) {
6467
return 1;
6568
} else {
6669
return 2;
@@ -77,9 +80,8 @@ uint8_t TileHierarchy::get_max_level() {
7780
std::vector<GraphId> TileHierarchy::GetGraphIds(const midgard::AABB2<midgard::PointLL>& bbox,
7881
const uint8_t level) {
7982
std::vector<GraphId> ids;
80-
auto itr = levels().find(level);
81-
if (itr != levels().end()) {
82-
auto tile_ids = itr->second.tiles.TileList(bbox);
83+
if (level < levels().size()) {
84+
auto tile_ids = levels()[level].tiles.TileList(bbox);
8385
ids.reserve(tile_ids.size());
8486

8587
for (auto tile_id : tile_ids) {
@@ -94,7 +96,7 @@ std::vector<GraphId> TileHierarchy::GetGraphIds(const midgard::AABB2<midgard::Po
9496
std::vector<GraphId> TileHierarchy::GetGraphIds(const midgard::AABB2<midgard::PointLL>& bbox) {
9597
std::vector<GraphId> ids;
9698
for (const auto& entry : levels()) {
97-
auto level_ids = GetGraphIds(bbox, entry.first);
99+
auto level_ids = GetGraphIds(bbox, entry.level);
98100
ids.reserve(ids.size() + level_ids.size());
99101
ids.insert(ids.end(), level_ids.begin(), level_ids.end());
100102
}
@@ -107,9 +109,8 @@ std::vector<GraphId> TileHierarchy::GetGraphIds(const midgard::AABB2<midgard::Po
107109
* @return Returns a const reference to the tiling system for this level.
108110
*/
109111
const midgard::Tiles<midgard::PointLL>& TileHierarchy::get_tiling(const uint8_t level) {
110-
const auto& tl = levels().find(level);
111-
if (tl != levels().end()) {
112-
return tl->second.tiles;
112+
if (level < levels().size()) {
113+
return levels()[level].tiles;
113114
}
114115
throw std::runtime_error("Invalid level Id for TileHierarchy::get_tiling");
115116
}

src/loki/height_action.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ std::string loki_worker_t::height(Api& request) {
8787
}
8888

8989
// get the distances between the postings if desired
90-
std::vector<float> ranges;
90+
std::vector<double> ranges;
9191
if (request.options().range()) {
9292
ranges.reserve(shape.size());
9393
ranges.emplace_back(0);

src/loki/matrix_action.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ void loki_worker_t::matrix(Api& request) {
129129
if (!connectivity_map) {
130130
continue;
131131
}
132-
auto colors =
133-
connectivity_map->get_colors(TileHierarchy::levels().rbegin()->first, projection, 0);
132+
auto colors = connectivity_map->get_colors(TileHierarchy::levels().back().level, projection, 0);
134133
for (auto& color : colors) {
135134
auto itr = color_counts.find(color);
136135
if (itr == color_counts.cend()) {

src/loki/node_search.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,8 @@ std::vector<baldr::GraphId> nodes_in_bbox(const vm::AABB2<vm::PointLL>& bbox,
368368
baldr::GraphReader& reader) {
369369
std::vector<vb::GraphId> nodes;
370370

371-
auto tiles = vb::TileHierarchy::levels().rbegin()->second.tiles;
372-
const uint8_t bin_level = vb::TileHierarchy::levels().rbegin()->second.level;
371+
const auto& tiles = vb::TileHierarchy::levels().back().tiles;
372+
const uint8_t bin_level = vb::TileHierarchy::levels().back().level;
373373

374374
// if the bbox only touches the edge of the tile or bin, then we need to
375375
// include neighbouring bins as well, in case both the edge and its opposite
@@ -425,8 +425,8 @@ std::vector<baldr::GraphId> nodes_in_bbox(const vm::AABB2<vm::PointLL>& bbox,
425425
std::vector<baldr::GraphId> edges_in_bbox(const vm::AABB2<vm::PointLL>& bbox,
426426
baldr::GraphReader& reader) {
427427

428-
auto tiles = vb::TileHierarchy::levels().rbegin()->second.tiles;
429-
const uint8_t bin_level = vb::TileHierarchy::levels().rbegin()->second.level;
428+
auto tiles = vb::TileHierarchy::levels().back().tiles;
429+
const uint8_t bin_level = vb::TileHierarchy::levels().back().level;
430430

431431
// if the bbox only touches the edge of the tile or bin, then we need to
432432
// include neighbouring bins as well, in case both the edge and its opposite

0 commit comments

Comments
 (0)