From 5a0ecb3b2d214b3b040a0191967ec9deae104004 Mon Sep 17 00:00:00 2001 From: Michael Kutzner <174690291+MichaelKutzner@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:58:05 +0100 Subject: [PATCH] WIP: Compress elevation data --- include/osr/elevation_storage.h | 17 ++++-- src/elevation_storage.cc | 105 +++++++++++++++++--------------- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/include/osr/elevation_storage.h b/include/osr/elevation_storage.h index f4daac0..0b0e5d7 100644 --- a/include/osr/elevation_storage.h +++ b/include/osr/elevation_storage.h @@ -6,8 +6,6 @@ #include "cista/mmap.h" -#include "utl/progress_tracker.h" - #include "osr/types.h" #include "osr/ways.h" @@ -24,18 +22,25 @@ struct elevation_storage { elevation_t up_; elevation_t down_; }; + // TODO Rename + struct compressed_elevation { + using coding = std::uint8_t; + static coding encode(elevation_t const); + static elevation_t decode(coding const); + bool is_flat() const; + coding up_ : 4; + coding down_ : 4; + }; elevation_storage(std::filesystem::path const&, cista::mmap::protection const mode); static std::unique_ptr try_open( std::filesystem::path const&); - void set_elevations(ways&, - preprocessing::elevation::provider const&); + void set_elevations(ways&, preprocessing::elevation::provider const&); elevation get_elevations(way_idx_t const way, std::uint16_t const from, std::uint16_t const to) const; - mm_vecvec elevations_up_; - mm_vecvec elevations_down_; + mm_vecvec elevations_; }; elevation_storage::elevation get_elevations(elevation_storage const*, diff --git a/src/elevation_storage.cc b/src/elevation_storage.cc index 6d38498..db304f5 100644 --- a/src/elevation_storage.cc +++ b/src/elevation_storage.cc @@ -1,9 +1,11 @@ #include "osr/elevation_storage.h" +#include #include #include "utl/helpers/algorithm.h" #include "utl/pairwise.h" +#include "utl/progress_tracker.h" #include "osr/point.h" #include "osr/preprocessing/elevation/provider.h" @@ -18,36 +20,28 @@ cista::mmap mm(std::filesystem::path const& p, } namespace elevation_files { -constexpr auto const kUpDataName = "elevation_up_data.bin"; -constexpr auto const kUpIndexName = "elevation_up_idx.bin"; -constexpr auto const kDownDataName = "elevation_down_data.bin"; -constexpr auto const kDownIndexName = "elevation_down_idx.bin"; +constexpr auto const kDataName = "elevation_data.bin"; +constexpr auto const kIndexName = "elevation_idx.bin"; }; // namespace elevation_files elevation_storage::elevation_storage(std::filesystem::path const& p, cista::mmap::protection const mode) - : elevations_up_{mm_vec{ - mm(p, elevation_files::kUpDataName, mode)}, - mm_vec( - mm(p, elevation_files::kUpIndexName, mode))}, - elevations_down_{ - mm_vec{mm(p, elevation_files::kDownDataName, mode)}, - mm_vec(mm(p, elevation_files::kDownIndexName, mode))} {} + : elevations_{ + mm_vec{mm(p, elevation_files::kDataName, mode)}, + mm_vec(mm(p, elevation_files::kIndexName, mode))} {} std::unique_ptr elevation_storage::try_open( std::filesystem::path const& path) { - if (utl::all_of(std::array{elevation_files::kUpDataName, - elevation_files::kUpIndexName, - elevation_files::kDownDataName, - elevation_files::kDownIndexName}, - [&](char const* const filename) { - auto const full_path = path / filename; - auto const exists = std::filesystem::exists(full_path); - if (!exists) { - std::cout << full_path << " does not exist\n"; - } - return exists; - })) { + if (utl::all_of( + std::array{elevation_files::kDataName, elevation_files::kIndexName}, + [&](char const* const filename) { + auto const full_path = path / filename; + auto const exists = std::filesystem::exists(full_path); + if (!exists) { + std::cout << full_path << " does not exist\n"; + } + return exists; + })) { return std::make_unique(path, cista::mmap::protection::READ); } @@ -102,12 +96,10 @@ void elevation_storage::set_elevations( auto pt = utl::get_active_progress_tracker_or_activate("osr"); pt->status("Load elevation data").out_bounds(85, 90).in_high(w.n_ways()); auto const max_step_size = dem.get_step_size(); - auto elevations_up = std::vector{}; - auto elevations_down = std::vector{}; + auto elevations = std::vector{}; auto points = std::vector{}; for (auto nodes : w.r_->way_nodes_) { - elevations_up.clear(); - elevations_down.clear(); + elevations.clear(); points.clear(); for (auto const& node : nodes) { points.emplace_back(w.get_node_pos(node)); @@ -115,39 +107,35 @@ void elevation_storage::set_elevations( auto idx = std::size_t{0U}; for (auto const [from, to] : utl::pairwise(points)) { auto const elevation = get_way_elevation(dem, from, to, max_step_size); - if (elevation.up_ > elevation_t{0}) { - elevations_up.resize(idx); - elevations_up.push_back(elevation.up_); - } - if (elevation.down_ > elevation_t{0}) { - elevations_down.resize(idx); - elevations_down.push_back(elevation.down_); + auto const segment_elevation = compressed_elevation{ + .up_ = compressed_elevation::encode(elevation.up_), + .down_ = compressed_elevation::encode(elevation.down_), + }; + if (!segment_elevation.is_flat()) { + elevations.resize(idx); + elevations.push_back(segment_elevation); } ++idx; } - elevations_up_.emplace_back(elevations_up); - elevations_down_.emplace_back(elevations_down); + elevations_.emplace_back(elevations); pt->increment(); } } -elevation_t elevation_at(mm_vecvec const& elevations, - way_idx_t const way_idx, - std::uint16_t const idx) { - return way_idx < elevations.size() && idx < elevations[way_idx].size() - ? elevations[way_idx].at(idx) - : elevation_t{0}; -} - elevation_storage::elevation elevation_storage::get_elevations( way_idx_t const way, std::uint16_t const from, std::uint16_t const to) const { - return (from < to) ? elevation{elevation_at(elevations_up_, way, from), - elevation_at(elevations_down_, way, from)} - : elevation{elevation_at(elevations_down_, way, to), - elevation_at(elevations_up_, way, to)}; + auto const idx = (from < to) ? from : to; + auto const elev = (way < elevations_.size() && idx < elevations_[way].size()) + ? elevations_[way][idx] + : compressed_elevation{0U, 0U}; + return (from < to) + ? elevation{.up_ = compressed_elevation::decode(elev.up_), + .down_ = compressed_elevation::decode(elev.down_)} + : elevation{.up_ = compressed_elevation::decode(elev.down_), + .down_ = compressed_elevation::decode(elev.up_)}; } elevation_storage::elevation get_elevations(elevation_storage const* elevations, @@ -159,4 +147,25 @@ elevation_storage::elevation get_elevations(elevation_storage const* elevations, : elevations->get_elevations(way, from, to); } +constexpr auto const kCompressedValues = std::array{ + // 0, 1, 2, 4, 6, 8, 11, 14, 17, 21, 25, 29, 34, 38, 43, 48}; + 0, 1, 2, 3, 4, 5, 6, 7, 17, 21, 25, 29, 34, 38, 43, 48}; + +elevation_storage::compressed_elevation::coding +elevation_storage::compressed_elevation::encode(elevation_t const e) { + auto const c = std::ranges::lower_bound(kCompressedValues, e); + return (c == end(kCompressedValues)) + ? kCompressedValues.size() - 1 + : static_cast(c - begin(kCompressedValues)); +} + +elevation_t elevation_storage::compressed_elevation::decode(coding const c) { + assert(c < kCompressedValues.size()); + return kCompressedValues.at(c); +} + +bool elevation_storage::compressed_elevation::is_flat() const { + return up_ == 0U && down_ == 0U; +} + } // namespace osr