mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-19 04:53:36 +00:00
Added SrtmTileManager::GetTriangleHeight.
Signed-off-by: Viktor Govako <viktor.govako@gmail.com>
This commit is contained in:
committed by
Konstantin Pastbin
parent
58ea819936
commit
c05b668e38
@@ -9,7 +9,6 @@
|
||||
#include "indexer/feature_processor.hpp"
|
||||
|
||||
#include "coding/files_container.hpp"
|
||||
#include "coding/internal/file_data.hpp"
|
||||
#include "coding/read_write_utils.hpp"
|
||||
#include "coding/reader.hpp"
|
||||
#include "coding/succinct_mapper.hpp"
|
||||
@@ -27,30 +26,26 @@
|
||||
|
||||
#include "defines.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "3party/succinct/elias_fano.hpp"
|
||||
#include "3party/succinct/mapper.hpp"
|
||||
#include "3party/succinct/rs_bit_vector.hpp"
|
||||
|
||||
namespace routing
|
||||
{
|
||||
using namespace feature;
|
||||
using namespace geometry;
|
||||
|
||||
namespace
|
||||
{
|
||||
using namespace routing;
|
||||
|
||||
class SrtmGetter : public AltitudeGetter
|
||||
{
|
||||
public:
|
||||
explicit SrtmGetter(std::string const & srtmDir) : m_srtmManager(srtmDir) {}
|
||||
|
||||
// AltitudeGetter overrides:
|
||||
geometry::Altitude GetAltitude(m2::PointD const & p) override
|
||||
Altitude GetAltitude(m2::PointD const & p) override
|
||||
{
|
||||
return m_srtmManager.GetHeight(mercator::ToLatLon(p));
|
||||
return m_srtmManager.GetTriangleHeight(mercator::ToLatLon(p));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -63,31 +58,20 @@ public:
|
||||
struct FeatureAltitude
|
||||
{
|
||||
FeatureAltitude() : m_featureId(0) {}
|
||||
FeatureAltitude(uint32_t featureId, Altitudes const & altitudes)
|
||||
: m_featureId(featureId), m_altitudes(altitudes)
|
||||
FeatureAltitude(uint32_t featureId, geometry::Altitudes && altitudes)
|
||||
: m_featureId(featureId), m_altitudes(std::move(altitudes))
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t m_featureId;
|
||||
Altitudes m_altitudes;
|
||||
feature::Altitudes m_altitudes;
|
||||
};
|
||||
|
||||
using TFeatureAltitudes = std::vector<FeatureAltitude>;
|
||||
|
||||
explicit Processor(AltitudeGetter & altitudeGetter)
|
||||
: m_altitudeGetter(altitudeGetter), m_minAltitude(geometry::kInvalidAltitude)
|
||||
: m_minAltitude(geometry::kInvalidAltitude), m_altitudeGetter(altitudeGetter)
|
||||
{
|
||||
}
|
||||
|
||||
TFeatureAltitudes const & GetFeatureAltitudes() const { return m_featureAltitudes; }
|
||||
|
||||
succinct::bit_vector_builder & GetAltitudeAvailabilityBuilder()
|
||||
{
|
||||
return m_altitudeAvailabilityBuilder;
|
||||
}
|
||||
|
||||
geometry::Altitude GetMinAltitude() const { return m_minAltitude; }
|
||||
|
||||
void operator()(FeatureType & f, uint32_t const & id)
|
||||
{
|
||||
if (id != m_altitudeAvailabilityBuilder.size())
|
||||
@@ -109,10 +93,10 @@ public:
|
||||
return;
|
||||
|
||||
geometry::Altitudes altitudes;
|
||||
geometry::Altitude minFeatureAltitude = geometry::kInvalidAltitude;
|
||||
Altitude minFeatureAltitude = geometry::kInvalidAltitude;
|
||||
for (size_t i = 0; i < pointsCount; ++i)
|
||||
{
|
||||
geometry::Altitude const a = m_altitudeGetter.GetAltitude(f.GetPoint(i));
|
||||
Altitude const a = m_altitudeGetter.GetAltitude(f.GetPoint(i));
|
||||
if (a == geometry::kInvalidAltitude)
|
||||
{
|
||||
// One invalid point invalidates the whole feature.
|
||||
@@ -128,7 +112,7 @@ public:
|
||||
}
|
||||
|
||||
hasAltitude = true;
|
||||
m_featureAltitudes.emplace_back(id, Altitudes(std::move(altitudes)));
|
||||
m_featureAltitudes.emplace_back(id, std::move(altitudes));
|
||||
|
||||
if (m_minAltitude == geometry::kInvalidAltitude)
|
||||
m_minAltitude = minFeatureAltitude;
|
||||
@@ -140,20 +124,20 @@ public:
|
||||
|
||||
bool IsFeatureAltitudesSorted()
|
||||
{
|
||||
return std::is_sorted(m_featureAltitudes.begin(), m_featureAltitudes.end(),
|
||||
return base::IsSortedAndUnique(m_featureAltitudes.begin(), m_featureAltitudes.end(),
|
||||
base::LessBy(&Processor::FeatureAltitude::m_featureId));
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<FeatureAltitude> m_featureAltitudes;
|
||||
succinct::bit_vector_builder m_altitudeAvailabilityBuilder;
|
||||
Altitude m_minAltitude;
|
||||
|
||||
private:
|
||||
AltitudeGetter & m_altitudeGetter;
|
||||
TFeatureAltitudes m_featureAltitudes;
|
||||
succinct::bit_vector_builder m_altitudeAvailabilityBuilder;
|
||||
geometry::Altitude m_minAltitude;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
{
|
||||
void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGetter)
|
||||
{
|
||||
try
|
||||
@@ -174,15 +158,14 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
|
||||
auto w = cont.GetWriter(ALTITUDES_FILE_TAG);
|
||||
|
||||
AltitudeHeader header;
|
||||
header.m_minAltitude = processor.GetMinAltitude();
|
||||
header.m_minAltitude = processor.m_minAltitude;
|
||||
|
||||
auto const startOffset = w->Pos();
|
||||
header.Serialize(*w);
|
||||
{
|
||||
// Altitude availability serialization.
|
||||
coding::FreezeVisitor<Writer> visitor(*w);
|
||||
succinct::bit_vector_builder & builder = processor.GetAltitudeAvailabilityBuilder();
|
||||
succinct::rs_bit_vector(&builder).map(visitor);
|
||||
succinct::rs_bit_vector(&processor.m_altitudeAvailabilityBuilder).map(visitor);
|
||||
}
|
||||
header.m_featureTableOffset = base::checked_cast<uint32_t>(w->Pos() - startOffset);
|
||||
|
||||
@@ -191,8 +174,7 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
|
||||
{
|
||||
// Altitude info serialization to memory.
|
||||
MemWriter<std::vector<uint8_t>> writer(deltas);
|
||||
Processor::TFeatureAltitudes const & featureAltitudes = processor.GetFeatureAltitudes();
|
||||
for (auto const & a : featureAltitudes)
|
||||
for (auto const & a : processor.m_featureAltitudes)
|
||||
{
|
||||
offsets.push_back(base::checked_cast<uint32_t>(writer.Pos()));
|
||||
a.m_altitudes.Serialize(header.m_minAltitude, writer);
|
||||
@@ -200,8 +182,7 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
|
||||
}
|
||||
{
|
||||
// Altitude offsets serialization.
|
||||
CHECK(std::is_sorted(offsets.begin(), offsets.end()), ());
|
||||
CHECK(adjacent_find(offsets.begin(), offsets.end()) == offsets.end(), ());
|
||||
CHECK(base::IsSortedAndUnique(offsets.begin(), offsets.end()), ());
|
||||
|
||||
succinct::elias_fano::elias_fano_builder builder(offsets.back(), offsets.size());
|
||||
for (uint32_t offset : offsets)
|
||||
@@ -221,9 +202,10 @@ void BuildRoadAltitudes(std::string const & mwmPath, AltitudeGetter & altitudeGe
|
||||
w->Seek(startOffset);
|
||||
header.Serialize(w);
|
||||
w->Seek(endOffset);
|
||||
|
||||
LOG(LINFO, (ALTITUDES_FILE_TAG, "section is ready. The size is", header.m_endOffset));
|
||||
if (processor.HasAltitudeInfo())
|
||||
LOG(LINFO, ("Min altitude is", processor.GetMinAltitude()));
|
||||
LOG(LINFO, ("Min altitude is", processor.m_minAltitude));
|
||||
else
|
||||
LOG(LINFO, ("Min altitude isn't defined."));
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ public:
|
||||
for (uint32_t i = 0; i < numPoints; ++i)
|
||||
{
|
||||
// Feature segment altitude.
|
||||
geometry::Altitude altitude = m_srtmManager.GetHeight(mercator::ToLatLon(f.GetPoint(i)));
|
||||
geometry::Altitude altitude = m_srtmManager.GetTriangleHeight(mercator::ToLatLon(f.GetPoint(i)));
|
||||
pointAltitudes[i] = altitude == geometry::kInvalidAltitude ? 0 : altitude;
|
||||
if (i == 0)
|
||||
{
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
|
||||
#include "generator/srtm_parser.hpp"
|
||||
|
||||
using namespace generator;
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
namespace srtm_parser_test
|
||||
{
|
||||
inline std::string GetBase(ms::LatLon const & coord) { return SrtmTile::GetBase(coord); }
|
||||
using namespace generator;
|
||||
using namespace geometry;
|
||||
|
||||
UNIT_TEST(FilenameTests)
|
||||
inline std::string GetBase(ms::LatLon const & coord)
|
||||
{
|
||||
return SrtmTile::GetBase(coord);
|
||||
}
|
||||
|
||||
UNIT_TEST(SRTM_FilenameTest)
|
||||
{
|
||||
auto name = GetBase({56.4566, 37.3467});
|
||||
TEST_EQUAL(name, "N56E037", ());
|
||||
@@ -19,10 +25,89 @@ UNIT_TEST(FilenameTests)
|
||||
name = GetBase({0.1, 0.1});
|
||||
TEST_EQUAL(name, "N00E000", ());
|
||||
|
||||
name = GetBase({-0.9, -0.9});
|
||||
TEST_EQUAL(name, "S01W001", ());
|
||||
|
||||
name = GetBase({-1.0, -1.0});
|
||||
TEST_EQUAL(name, "S01W001", ());
|
||||
|
||||
name = GetBase({-1.9, -1.1});
|
||||
TEST_EQUAL(name, "S02W002", ());
|
||||
|
||||
name = GetBase({-35.35, -12.1});
|
||||
TEST_EQUAL(name, "S36W013", ());
|
||||
|
||||
name = GetBase({-34.622358, -58.383654});
|
||||
TEST_EQUAL(name, "S35W059", ());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
UNIT_TEST(SRTM_TileTest)
|
||||
{
|
||||
SrtmTile tile;
|
||||
size_t sz;
|
||||
Altitude * data = tile.DataForTests(sz);
|
||||
|
||||
// Fill 5 last rows:
|
||||
// -4 -4 -4
|
||||
// -2 -2 -2
|
||||
// 0 0 0
|
||||
// 2 2 2
|
||||
// 4 4 4
|
||||
size_t row = sz - 1;
|
||||
for (Altitude a = 4; a >= -4; a -= 2)
|
||||
{
|
||||
for (size_t i = row * sz; i < (row + 1) * sz; ++i)
|
||||
data[i] = ReverseByteOrder(a);
|
||||
--row;
|
||||
}
|
||||
|
||||
double const len = 1.0 / (sz - 1);
|
||||
|
||||
TEST_EQUAL(tile.GetHeight({0, 0}), 4, ());
|
||||
TEST_EQUAL(tile.GetTriangleHeight({0, 0}), 4, ());
|
||||
TEST_EQUAL(tile.GetHeight({len, len}), 2, ());
|
||||
TEST_EQUAL(tile.GetTriangleHeight({len, len}), 2, ());
|
||||
|
||||
// Key difference here: GetHeight snaps on the nearest node, while GetTriangleHeight calculates
|
||||
// from the nearest nodes' triangle.
|
||||
double l = len / 2;
|
||||
Altitude h = tile.GetHeight({l, l});
|
||||
TEST(h == 4 || h == 2, (h));
|
||||
TEST_EQUAL(tile.GetTriangleHeight({l, l}), 3, ());
|
||||
|
||||
l = 3 * len + len / 2;
|
||||
h = tile.GetHeight({l, l});
|
||||
TEST(h == -4 || h == -2, (h));
|
||||
TEST_EQUAL(tile.GetTriangleHeight({l, l}), -3, ());
|
||||
}
|
||||
|
||||
/*
|
||||
UNIT_TEST(SRTM_SamplesTest)
|
||||
{
|
||||
SrtmTileManager manager("/Users/vng/SRTM");
|
||||
|
||||
std::initializer_list<ms::LatLon> arr[] = {
|
||||
{{ 41.899802800880578957, 12.498703841110341273}, { 41.899748897914214751, 12.498642150302543996}, { 41.899315676124750496, 12.498172763721441925}, { 41.899207869324136766, 12.498057428732948893 }},
|
||||
{{ 41.900315874986389986, 12.499267105007675127}, { 41.900234022973513959, 12.499175909900486658}, { 41.899802800880578957, 12.498703841110341273 }},
|
||||
{{ 41.899317672545265623, 12.499556783583443575}, { 41.899704976945002954, 12.498910371206022774}, { 41.899716955394147533, 12.49888623132471821}, { 41.899730930248637151, 12.498862091443413647}, { 41.899744905100071435, 12.49882990493497914}, { 41.899760876355117034, 12.498797718426573056}, { 41.899772854793766896, 12.498768214127181864}, { 41.899788826041820755, 12.498736027618775779}, { 41.899802800880578957, 12.498703841110341273 }},
|
||||
{{ 41.900297907480371862, 12.497869674100513748}, { 41.900259976062137923, 12.497931364908311025}, { 41.899866685818835776, 12.498593870539906447}, { 41.899834743357700972, 12.498647514720602203}, { 41.899818772121129484, 12.498674336810950081}, { 41.899802800880578957, 12.498703841110341273 }},
|
||||
{{ 41.899728933841061007, 12.497309092412223208}, { 41.900224041013551357, 12.497850898637267392}, { 41.90023202658165502, 12.49786430968242712}, { 41.900224041013551357, 12.497888449563731683}, { 41.899826757739916161, 12.498548272986312213}, { 41.899808790096251698, 12.498556319613442156}, { 41.899802800880578957, 12.498550955195355527}, { 41.89979281885320006, 12.498545590777297321}, { 41.899307690442057606, 12.498009148970311344}, { 41.899301701179375357, 12.497995737925151616}, { 41.899309686862821422, 12.497976962461905259}, { 41.899716955394147533, 12.497311774621238101}, { 41.899728933841061007, 12.497309092412223208 }},
|
||||
{{ 41.899802800880578957, 12.498550955195355527}, { 41.899748897914214751, 12.498642150302543996}, { 41.899681020039992063, 12.498754803082022136 }},
|
||||
{{ 41.899912603078725226, 12.498650196929645517}, { 41.899866685818835776, 12.498593870539906447}, { 41.899826757739916161, 12.498548272986312213 }},
|
||||
{{ 41.899994455503602353, 12.498516086477906128}, { 41.899912603078725226, 12.498650196929645517}, { 41.899912603078725226, 12.498685065647094916}, { 41.900285929140210328, 12.499090079211356397}, { 41.90030589303923847, 12.499111536883646068}, { 41.90070516970908443, 12.498435620206862495}, { 41.900711158840110215, 12.49842489137071766}, { 41.900715151593857399, 12.498408798116514618}, { 41.900713155217019334, 12.498398069280369782}, { 41.90056342677709722, 12.498237136738282516}, { 41.900327853320931126, 12.497979644670920152}, { 41.900317871375655443, 12.497976962461905259}, { 41.900307889428788144, 12.497982326879963466}, { 41.899994455503602353, 12.498516086477906128 }},
|
||||
|
||||
{{ 44.759886801735603967, 34.316046940654871378 }, { 44.759500178870737841, 34.315553414192436321 }, { 44.759132599068138347, 34.315443443622029918 }, { 44.758765016927078761, 34.315430032576841768 }, { 44.758071746835689453, 34.315253006780551459 }, { 44.758037464032938146, 34.315255688989566352 }, { 44.757483222565575431, 34.315306650961247215 }, { 44.756708037437867631, 34.315676795808059296 }, { 44.756323297960172169, 34.315652655926726311 }, { 44.755963316624225001, 34.315430032576841768 }, { 44.755833798981250027, 34.315153765046261469 }, { 44.755789991477485046, 34.314949917159594861 }},
|
||||
{{ 44.759886801735603967, 34.316046940654871378 }, { 44.760006787615907342, 34.315175222718522718 }, { 44.760048687388419353, 34.315011607967392138 }, { 44.760260090322724125, 34.314772891363304552 }, { 44.760437211104594724, 34.314665603001913041 }, { 44.760572431981174191, 34.314383971053246114 }, { 44.760701939002856875, 34.314300822573159166 }, { 44.761223773178279828, 34.314088928059419459 }, { 44.761292334982400121, 34.314091610268434351 }, { 44.761376132632506142, 34.314011143997390718 }, { 44.761667518969709079, 34.313895809008897686 }, { 44.761739889204726239, 34.31379924948365101 }, { 44.761739889204726239, 34.313705372167419227 }, { 44.76183130410882427, 34.313568579506636524 }, { 44.761930336758403826, 34.313549804043390168 }, { 44.761981757490261202, 34.313442515681998657 }, { 44.762050318394869919, 34.313396918128404423 }, { 44.762176013175370315, 34.313391553710346216 }, { 44.762316943361625476, 34.313359367201911709 }, { 44.762610229403847484, 34.313332545111563832 }, { 44.762627369451166714, 34.313343273947708667 }, { 44.762663553978839559, 34.313313769648317475 }, { 44.762673076219179791, 34.313278900930868076 }, { 44.762678789562635018, 34.313233303377273842 }, { 44.762692120695184883, 34.31320379907788265 }, { 44.762720687397411723, 34.313182341405621401 }, { 44.762734018520298207, 34.313107239552635974 }, { 44.762747349640086725, 34.313091146298432932 }, { 44.7628063874193316, 34.313101875134577767 }, { 44.76292065391750441, 34.313123332806839016 }, { 44.762977787081830172, 34.313056277580983533 }, { 44.763063486722373341, 34.313107239552635974 }, { 44.763282496337311045, 34.313088464089389618 }},
|
||||
{{ 44.756521381971580809, 34.332137512655094724 }, { 44.756469956380023234, 34.331619846311355104 }, { 44.756412816780184016, 34.331308710063325407 }, { 44.756359486436011252, 34.331040489159818208 }, { 44.75633282124546497, 34.330965387306861203 }, { 44.756294728094793811, 34.330860781154484584 }, { 44.756264253556160781, 34.330694484194339111 }, { 44.756294728094793811, 34.330608653505208849 }, { 44.756323297960172169, 34.330533551652223423 }, { 44.756433767973362592, 34.330359208064976428 }, { 44.756555665673857902, 34.330109762624715586 }, { 44.756641374840555159, 34.329940783455526798 }, { 44.756755653531747896, 34.329755711032106547 }, { 44.757010875126020721, 34.329463350247323206 }, { 44.757180387352946127, 34.329117345281815687 }, { 44.757266095593031707, 34.32893495506743875 }, { 44.757448939413642108, 34.328564810220626669 }, { 44.757591785745901802, 34.328301953735206098 }, { 44.757746059388104243, 34.327797698436654628 }, { 44.757807006886359602, 34.327470468934393466 }, { 44.75787366813893442, 34.327239798957407402 }, { 44.757986039790637278, 34.327089595251464971 }, { 44.758026036427494887, 34.326995717935233188 }, { 44.758113648011466523, 34.326907205037088033 }, { 44.75817078592944398, 34.326783823421465058 }, { 44.758237446762365153, 34.326400267529493249 }, { 44.758264111073970071, 34.3263519877668557 }, { 44.758357436067782942, 34.326177644179608706 }, { 44.758412669156371066, 34.325909423276101506 }, { 44.758505993910240761, 34.325775312824362118 }, { 44.758526944344453113, 34.325598287028071809 }, { 44.758479329710219474, 34.325461494367289106 }, { 44.758391718680712756, 34.325370299260100637 }, { 44.758429810449001707, 34.32524423543546277 }, { 44.75854789477109108, 34.325085985102390396 }, { 44.758637410144764601, 34.324914323724158294 }, { 44.758685024648755757, 34.324734615718824671 }, { 44.758707879596705936, 34.324613916312273432 }, { 44.758766921503791991, 34.324568318758679197 }, { 44.758749780311177346, 34.32444225493404133 }, { 44.758799299298182461, 34.324206220538968637 }, { 44.75882786792522694, 34.323988961607142301 }, { 44.758825963350531651, 34.323667096522939346 }, { 44.758843104520543932, 34.323423015500765132 }, { 44.758862150259034252, 34.323181616687634232 }, { 44.758915478293424428, 34.322983133219054253 }, { 44.758944046863021526, 34.322875844857662742 }, { 44.759084984933011242, 34.322862433812474592 }, { 44.758966901708539865, 34.32266126813487972 }, { 44.758865959405987667, 34.32256202640058973 }, { 44.758753589465527511, 34.322331356423575244 }, { 44.75867359717138072, 34.322089957610444344 }, { 44.758690738386590624, 34.321875380887661322 }, { 44.758690738386590624, 34.321754681481081661 }, { 44.758698356702829813, 34.321642028701631943 }, { 44.758643123887310367, 34.321379172216211373 }, { 44.758641219306547043, 34.321231650719283834 }, { 44.758665978851873035, 34.321027802832645648 }, { 44.758732639113461005, 34.320837365991167189 }, { 44.75867359717138072, 34.320502089861804507 }, { 44.75867931091034535, 34.320392119291369681 }, { 44.758808822175438991, 34.320268737675775128 }, { 44.758793585571083895, 34.320099758506557919 }, { 44.758978329127899087, 34.319783257840441593 }, { 44.759109744288181787, 34.319584774371861613 }, { 44.75926782299799811, 34.31950430810081798 }, { 44.759357337256332698, 34.319305824632238 }, { 44.759387810163708821, 34.319016146056469552 }, { 44.759481133342561066, 34.318686234345193498 }, { 44.75951351073673834, 34.318530666221164438 }, { 44.759524938047988485, 34.318332182752584458 }, { 44.759637306488322395, 34.317903029306989993 }, { 44.759671588341880977, 34.317436324934931235 }, { 44.759871565415501493, 34.317044722415829483 }, { 44.759902038051663453, 34.316647755478669524 }, { 44.759915369824923914, 34.316167640061422617 }, { 44.759886801735603967, 34.316046940654871378 }},
|
||||
};
|
||||
|
||||
using namespace std;
|
||||
for (auto const & points : arr)
|
||||
{
|
||||
for (auto const & p : points)
|
||||
cout << manager.GetTriangleHeight(p) << ", ";
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
} // namespace srtm_parser_test
|
||||
|
||||
@@ -2,72 +2,116 @@
|
||||
|
||||
#include "routing/routing_helpers.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/classificator_loader.hpp"
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_altitude.hpp"
|
||||
#include "indexer/feature_data.hpp"
|
||||
#include "indexer/feature_processor.hpp"
|
||||
|
||||
#include "geometry/distance_on_sphere.hpp"
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "geometry/point_with_altitude.hpp"
|
||||
|
||||
#include "platform/country_file.hpp"
|
||||
#include "platform/local_country_file.hpp"
|
||||
#include "platform/local_country_file_utils.hpp"
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
DEFINE_string(srtm_path, "", "Path to directory with SRTM files");
|
||||
DEFINE_string(mwm_path, "", "Path to mwm files (writable dir)");
|
||||
DEFINE_bool(check_dist, false, "Check feature sections distance");
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
class SafeTileManager
|
||||
{
|
||||
gflags::SetUsageMessage("SRTM coverage checker.");
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
generator::SrtmTileManager m_manager;
|
||||
std::mutex m_mutex;
|
||||
|
||||
Platform & platform = GetPlatform();
|
||||
if (!FLAGS_mwm_path.empty())
|
||||
platform.SetWritableDirForTests(FLAGS_mwm_path);
|
||||
uint32_t m_ferry;
|
||||
|
||||
if (FLAGS_srtm_path.empty())
|
||||
public:
|
||||
explicit SafeTileManager(std::string const & dir) : m_manager(dir)
|
||||
{
|
||||
LOG(LERROR, ("SRTM files directory is not specified."));
|
||||
return -1;
|
||||
m_ferry = classif().GetTypeByPath({"route", "ferry"});
|
||||
CHECK(m_ferry != Classificator::INVALID_TYPE, ());
|
||||
}
|
||||
|
||||
LOG(LINFO, ("writable dir =", platform.WritableDir()));
|
||||
LOG(LINFO, ("srtm dir =", FLAGS_srtm_path));
|
||||
bool IsAltitudeRoad(FeatureType & ft) const
|
||||
{
|
||||
feature::TypesHolder types(ft);
|
||||
return (routing::IsRoad(types) && !types.Has(m_ferry));
|
||||
}
|
||||
|
||||
geometry::Altitude GetHeight(ms::LatLon const & coord)
|
||||
{
|
||||
std::lock_guard guard(m_mutex);
|
||||
return m_manager.GetTriangleHeight(coord);
|
||||
}
|
||||
|
||||
void Purge()
|
||||
{
|
||||
std::lock_guard guard(m_mutex);
|
||||
m_manager.Purge();
|
||||
}
|
||||
};
|
||||
|
||||
template <class FnT> void ForEachMWM(SafeTileManager & manager, FnT && fn)
|
||||
{
|
||||
std::vector<platform::LocalCountryFile> localFiles;
|
||||
FindAllLocalMapsAndCleanup(std::numeric_limits<int64_t>::max() /* latestVersion */, localFiles);
|
||||
|
||||
generator::SrtmTileManager manager(FLAGS_srtm_path);
|
||||
classificator::Load();
|
||||
// Better use ComputationalThreadPool, but we want to call SafeTileManager::Purge after each batch.
|
||||
size_t constexpr kThreadsCount = 24;
|
||||
std::vector<std::thread> pool;
|
||||
|
||||
size_t workers = 0;
|
||||
for (auto & file : localFiles)
|
||||
{
|
||||
// Skip worlds.
|
||||
if (file.GetDirectory().empty() || file.GetCountryName().starts_with("World"))
|
||||
continue;
|
||||
|
||||
file.SyncWithDisk();
|
||||
if (!file.OnDisk(MapFileType::Map))
|
||||
{
|
||||
LOG(LINFO, ("Warning! Routing file not found for:", file.GetCountryName()));
|
||||
LOG_SHORT(LWARNING, ("Map file not found for:", file.GetCountryName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const path = file.GetPath(MapFileType::Map);
|
||||
LOG(LINFO, ("Mwm", path, "is being processed."));
|
||||
LOG_SHORT(LINFO, ("Processing", file.GetCountryName()));
|
||||
|
||||
pool.emplace_back([&fn, &file]() { fn(file); });
|
||||
|
||||
if (++workers == kThreadsCount)
|
||||
{
|
||||
for (auto & t : pool)
|
||||
t.join();
|
||||
pool.clear();
|
||||
|
||||
manager.Purge();
|
||||
workers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & t : pool)
|
||||
t.join();
|
||||
}
|
||||
|
||||
void CheckCoverage(SafeTileManager & manager)
|
||||
{
|
||||
ForEachMWM(manager, [&](platform::LocalCountryFile const & file)
|
||||
{
|
||||
size_t all = 0;
|
||||
size_t good = 0;
|
||||
feature::ForEachFeature(path, [&](FeatureType & ft, uint32_t fid) {
|
||||
if (!routing::IsRoad(feature::TypesHolder(ft)))
|
||||
feature::ForEachFeature(file.GetPath(MapFileType::Map), [&](FeatureType & ft, uint32_t)
|
||||
{
|
||||
if (!manager.IsAltitudeRoad(ft))
|
||||
return;
|
||||
|
||||
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
|
||||
@@ -82,9 +126,126 @@ int main(int argc, char * argv[])
|
||||
});
|
||||
|
||||
auto const bad = all - good;
|
||||
auto const percent = all == 0 ? 0.0 : bad * 100.0 / all;
|
||||
LOG(LINFO, (percent > 10.0 ? "Huge" : "Low", "error rate in:", file.GetCountryName(),
|
||||
auto const percent = (all == 0) ? 0.0 : bad * 100.0 / all;
|
||||
LOG_SHORT(LINFO, (percent > 10.0 ? "Huge" : "Low", "error rate in:", file.GetCountryName(),
|
||||
"good:", good, "bad:", bad, "all:", all, "%:", percent));
|
||||
});
|
||||
}
|
||||
|
||||
void CheckDistance(SafeTileManager & manager)
|
||||
{
|
||||
ForEachMWM(manager, [&](platform::LocalCountryFile const & file)
|
||||
{
|
||||
size_t all = 0;
|
||||
size_t added = 0;
|
||||
size_t invalid = 0;
|
||||
feature::ForEachFeature(file.GetPath(MapFileType::Map), [&](FeatureType & ft, uint32_t)
|
||||
{
|
||||
if (!manager.IsAltitudeRoad(ft))
|
||||
return;
|
||||
|
||||
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
|
||||
all += ft.GetPointsCount();
|
||||
|
||||
for (size_t i = 1; i < ft.GetPointsCount(); ++i)
|
||||
{
|
||||
auto const ll1 = mercator::ToLatLon(ft.GetPoint(i-1));
|
||||
auto const alt1 = manager.GetHeight(ll1);
|
||||
auto const ll2 = mercator::ToLatLon(ft.GetPoint(i));
|
||||
auto const alt2 = manager.GetHeight(ll2);
|
||||
|
||||
if (alt1 == geometry::kInvalidAltitude || alt2 == geometry::kInvalidAltitude)
|
||||
{
|
||||
++invalid;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Divide by 1 second sections.
|
||||
size_t const sections = std::round(ms::DistanceOnSphere(ll1.m_lat, ll1.m_lon, ll2.m_lat, ll2.m_lon) * 3600);
|
||||
if (sections < 2)
|
||||
continue;
|
||||
|
||||
for (size_t j = 1; j < sections; ++j)
|
||||
{
|
||||
double const a = j / double(sections);
|
||||
ms::LatLon const ll(ll2.m_lat * a + ll1.m_lat * (1 - a), ll2.m_lon * a + ll1.m_lon * (1 - a));
|
||||
|
||||
// Get diff between approx altitude and real one.
|
||||
auto const alt = manager.GetHeight(ll);
|
||||
if (alt == geometry::kInvalidAltitude)
|
||||
{
|
||||
LOG_SHORT(LWARNING, ("Invalid altitude for the middle point:", ll));
|
||||
++added;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const approxAlt = static_cast<geometry::Altitude>(std::round(alt2 * a + alt1 * (1 - a)));
|
||||
if (abs(alt - approxAlt) >= std::max(1, abs(alt)/10)) // 10%
|
||||
++added;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
auto const percent = added * 100.0 / all;
|
||||
std::string prefix = "Low";
|
||||
if (percent >= 1)
|
||||
prefix = "Huge";
|
||||
else if (added >= 1000)
|
||||
prefix = "Medium";
|
||||
|
||||
LOG_SHORT(LINFO, (prefix, file.GetCountryName(), "all:", all, "invalid:", invalid, "added:", added, "%:", percent));
|
||||
});
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
gflags::SetUsageMessage("SRTM coverage checker.");
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
|
||||
if (FLAGS_srtm_path.empty())
|
||||
{
|
||||
LOG_SHORT(LERROR, ("SRTM files directory is not specified."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
classificator::Load();
|
||||
|
||||
if (!FLAGS_mwm_path.empty())
|
||||
{
|
||||
SafeTileManager manager(FLAGS_srtm_path);
|
||||
|
||||
Platform & platform = GetPlatform();
|
||||
platform.SetWritableDirForTests(FLAGS_mwm_path);
|
||||
|
||||
if (FLAGS_check_dist)
|
||||
CheckDistance(manager);
|
||||
else
|
||||
CheckCoverage(manager);
|
||||
}
|
||||
else
|
||||
{
|
||||
generator::SrtmTileManager manager(FLAGS_srtm_path);
|
||||
|
||||
using namespace std;
|
||||
cout << "Enter lat lon. Or Ctrl + C to exit." << endl;
|
||||
|
||||
while (true)
|
||||
{
|
||||
double lat, lon;
|
||||
cin >> lat >> lon;
|
||||
if (!cin)
|
||||
{
|
||||
cout << "Invalid lat lon." << endl;
|
||||
cin.clear();
|
||||
cin.ignore(10000, '\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "H = " << manager.GetHeight({lat, lon}) << "; TrgH = " << manager.GetTriangleHeight({lat, lon});
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -21,10 +21,16 @@ size_t constexpr kSrtmTileSize = (kArcSecondsInDegree + 1) * (kArcSecondsInDegre
|
||||
|
||||
struct UnzipMemDelegate : public ZipFileReader::Delegate
|
||||
{
|
||||
explicit UnzipMemDelegate(std::string & buffer) : m_buffer(buffer), m_completed(false) {}
|
||||
explicit UnzipMemDelegate(std::vector<uint8_t> & buffer) : m_buffer(buffer), m_completed(false)
|
||||
{
|
||||
m_buffer.reserve(kSrtmTileSize);
|
||||
}
|
||||
|
||||
// ZipFileReader::Delegate overrides:
|
||||
void OnBlockUnzipped(size_t size, char const * data) override { m_buffer.append(data, size); }
|
||||
void OnBlockUnzipped(size_t size, char const * data) override
|
||||
{
|
||||
m_buffer.insert(m_buffer.end(), data, data + size);
|
||||
}
|
||||
|
||||
void OnStarted() override
|
||||
{
|
||||
@@ -34,7 +40,7 @@ struct UnzipMemDelegate : public ZipFileReader::Delegate
|
||||
|
||||
void OnCompleted() override { m_completed = true; }
|
||||
|
||||
std::string & m_buffer;
|
||||
std::vector<uint8_t> & m_buffer;
|
||||
bool m_completed;
|
||||
};
|
||||
|
||||
@@ -45,11 +51,6 @@ std::string GetSrtmContFileName(std::string const & dir, std::string const & bas
|
||||
} // namespace
|
||||
|
||||
// SrtmTile ----------------------------------------------------------------------------------------
|
||||
SrtmTile::SrtmTile()
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
SrtmTile::SrtmTile(SrtmTile && rhs) : m_data(std::move(rhs.m_data)), m_valid(rhs.m_valid)
|
||||
{
|
||||
rhs.Invalidate();
|
||||
@@ -90,7 +91,7 @@ void SrtmTile::Init(std::string const & dir, ms::LatLon const & coord)
|
||||
}
|
||||
else
|
||||
{
|
||||
FileReader(base::JoinPath(dir, file)).ReadAsString(m_data);
|
||||
m_data = base::ReadFile(base::JoinPath(dir, file));
|
||||
}
|
||||
|
||||
if (m_data.size() != kSrtmTileSize)
|
||||
@@ -103,11 +104,9 @@ void SrtmTile::Init(std::string const & dir, ms::LatLon const & coord)
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
geometry::Altitude SrtmTile::GetHeight(ms::LatLon const & coord) const
|
||||
// static
|
||||
ms::LatLon SrtmTile::GetCoordInSeconds(ms::LatLon const & coord)
|
||||
{
|
||||
if (!IsValid())
|
||||
return geometry::kInvalidAltitude;
|
||||
|
||||
double ln = coord.m_lon - static_cast<int>(coord.m_lon);
|
||||
if (ln < 0)
|
||||
ln += 1;
|
||||
@@ -116,15 +115,75 @@ geometry::Altitude SrtmTile::GetHeight(ms::LatLon const & coord) const
|
||||
lt += 1;
|
||||
lt = 1 - lt; // from North to South
|
||||
|
||||
auto const row = static_cast<size_t>(std::round(kArcSecondsInDegree * lt));
|
||||
auto const col = static_cast<size_t>(std::round(kArcSecondsInDegree * ln));
|
||||
return { kArcSecondsInDegree * lt, kArcSecondsInDegree * ln };
|
||||
}
|
||||
|
||||
geometry::Altitude SrtmTile::GetHeight(ms::LatLon const & coord) const
|
||||
{
|
||||
if (!IsValid())
|
||||
return geometry::kInvalidAltitude;
|
||||
|
||||
auto const ll = GetCoordInSeconds(coord);
|
||||
|
||||
return GetHeightRC(static_cast<size_t>(std::round(ll.m_lat)), static_cast<size_t>(std::round(ll.m_lon)));
|
||||
}
|
||||
|
||||
geometry::Altitude SrtmTile::GetHeightRC(size_t row, size_t col) const
|
||||
{
|
||||
size_t const ix = row * (kArcSecondsInDegree + 1) + col;
|
||||
|
||||
CHECK_LESS(ix, Size(), (coord));
|
||||
CHECK_LESS(ix, Size(), (row, col));
|
||||
return ReverseByteOrder(Data()[ix]);
|
||||
}
|
||||
|
||||
geometry::Altitude SrtmTile::GetTriangleHeight(ms::LatLon const & coord) const
|
||||
{
|
||||
if (!IsValid())
|
||||
return geometry::kInvalidAltitude;
|
||||
|
||||
auto const ll = GetCoordInSeconds(coord);
|
||||
|
||||
m2::Point<int> const p1(static_cast<int>(std::round(ll.m_lon)), static_cast<int>(std::round(ll.m_lat)));
|
||||
|
||||
auto p2 = p1;
|
||||
if (p2.x > ll.m_lon)
|
||||
{
|
||||
if (p2.x > 0)
|
||||
--p2.x;
|
||||
}
|
||||
else if (p2.x < ll.m_lon)
|
||||
{
|
||||
if (p2.x < kArcSecondsInDegree)
|
||||
++p2.x;
|
||||
}
|
||||
|
||||
auto p3 = p1;
|
||||
if (p3.y > ll.m_lat)
|
||||
{
|
||||
if (p3.y > 0)
|
||||
--p3.y;
|
||||
}
|
||||
else if (p3.y < ll.m_lat)
|
||||
{
|
||||
if (p3.y < kArcSecondsInDegree)
|
||||
++p3.y;
|
||||
}
|
||||
|
||||
// Approximate height from triangle p1, p2, p3.
|
||||
// p1.y == p2.y; p1.x == p3.x
|
||||
// https://stackoverflow.com/questions/36090269/finding-height-of-point-on-height-map-triangles
|
||||
int const det = (p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y);
|
||||
if (det == 0)
|
||||
return GetHeightRC(p1.y, p1.x);
|
||||
|
||||
double const a1 = ((p2.y - p3.y) * (ll.m_lon - p3.x) + (p3.x - p2.x) * (ll.m_lat - p3.y)) / det;
|
||||
double const a2 = ((p3.y - p1.y) * (ll.m_lon - p3.x) + (p1.x - p3.x) * (ll.m_lat - p3.y)) / det;
|
||||
double const a3 = 1 - a1 - a2;
|
||||
|
||||
return static_cast<geometry::Altitude>(std::round(a1 * GetHeightRC(p1.y, p1.x) +
|
||||
a2 * GetHeightRC(p2.y, p2.x) +
|
||||
a3 * GetHeightRC(p3.y, p3.x)));
|
||||
}
|
||||
|
||||
// static
|
||||
std::string SrtmTile::GetPath(std::string const & dir, std::string const & base)
|
||||
{
|
||||
@@ -168,6 +227,14 @@ std::string SrtmTile::GetBase(ms::LatLon const & coord)
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
geometry::Altitude * SrtmTile::DataForTests(size_t & sz)
|
||||
{
|
||||
m_valid = true;
|
||||
sz = kArcSecondsInDegree + 1;
|
||||
m_data.resize(kSrtmTileSize, 0);
|
||||
return reinterpret_cast<geometry::Altitude *>(m_data.data());
|
||||
}
|
||||
|
||||
void SrtmTile::Invalidate()
|
||||
{
|
||||
m_data.clear();
|
||||
@@ -176,31 +243,22 @@ void SrtmTile::Invalidate()
|
||||
}
|
||||
|
||||
// SrtmTileManager ---------------------------------------------------------------------------------
|
||||
SrtmTileManager::SrtmTileManager(std::string const & dir) : m_dir(dir) {}
|
||||
geometry::Altitude SrtmTileManager::GetHeight(ms::LatLon const & coord)
|
||||
SrtmTile const & SrtmTileManager::GetTile(ms::LatLon const & coord)
|
||||
{
|
||||
auto const key = GetKey(coord);
|
||||
|
||||
auto it = m_tiles.find(key);
|
||||
if (it == m_tiles.end())
|
||||
auto res = m_tiles.emplace(GetKey(coord), SrtmTile());
|
||||
if (res.second)
|
||||
{
|
||||
SrtmTile tile;
|
||||
try
|
||||
{
|
||||
tile.Init(m_dir, coord);
|
||||
res.first->second.Init(m_dir, coord);
|
||||
}
|
||||
catch (RootException const & e)
|
||||
{
|
||||
std::string const base = SrtmTile::GetBase(coord);
|
||||
LOG(LINFO, ("Can't init SRTM tile:", base, "reason:", e.Msg()));
|
||||
}
|
||||
|
||||
// It's OK to store even invalid tiles and return invalid height
|
||||
// for them later.
|
||||
it = m_tiles.emplace(key, std::move(tile)).first;
|
||||
}
|
||||
|
||||
return it->second.GetHeight(coord);
|
||||
return res.first->second;
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -210,13 +268,9 @@ SrtmTileManager::LatLonKey SrtmTileManager::GetKey(ms::LatLon const & coord)
|
||||
return {static_cast<int32_t>(tileCenter.m_lat), static_cast<int32_t>(tileCenter.m_lon)};
|
||||
}
|
||||
|
||||
SrtmTile const & SrtmTileManager::GetTile(ms::LatLon const & coord)
|
||||
void SrtmTileManager::Purge()
|
||||
{
|
||||
// Touch the tile to force its loading.
|
||||
GetHeight(coord);
|
||||
auto const key = GetKey(coord);
|
||||
auto const it = m_tiles.find(key);
|
||||
CHECK(it != m_tiles.end(), (coord));
|
||||
return it->second;
|
||||
MapT().swap(m_tiles);
|
||||
}
|
||||
|
||||
} // namespace generator
|
||||
|
||||
@@ -17,29 +17,40 @@ namespace generator
|
||||
class SrtmTile
|
||||
{
|
||||
public:
|
||||
SrtmTile();
|
||||
SrtmTile() : m_valid(false) {}
|
||||
SrtmTile(SrtmTile && rhs);
|
||||
|
||||
void Init(std::string const & dir, ms::LatLon const & coord);
|
||||
|
||||
inline bool IsValid() const { return m_valid; }
|
||||
// Returns height in meters at |coord| or kInvalidAltitude.
|
||||
/// @return Height in meters at |coord| or kInvalidAltitude.
|
||||
/// @{
|
||||
/// Nearest serialized height.
|
||||
geometry::Altitude GetHeight(ms::LatLon const & coord) const;
|
||||
/// Height from underlying triangle (better than GetHeight).
|
||||
geometry::Altitude GetTriangleHeight(ms::LatLon const & coord) const;
|
||||
/// @}
|
||||
|
||||
static std::string GetBase(ms::LatLon const & coord);
|
||||
static ms::LatLon GetCenter(ms::LatLon const & coord);
|
||||
static std::string GetPath(std::string const & dir, std::string const & base);
|
||||
|
||||
/// Used in unit tests only to prepare mock tile.
|
||||
geometry::Altitude * DataForTests(size_t & sz);
|
||||
|
||||
private:
|
||||
static ms::LatLon GetCoordInSeconds(ms::LatLon const & coord);
|
||||
geometry::Altitude GetHeightRC(size_t row, size_t col) const;
|
||||
|
||||
inline geometry::Altitude const * Data() const
|
||||
{
|
||||
return reinterpret_cast<geometry::Altitude const *>(m_data.data());
|
||||
};
|
||||
}
|
||||
|
||||
inline size_t Size() const { return m_data.size() / sizeof(geometry::Altitude); }
|
||||
void Invalidate();
|
||||
|
||||
std::string m_data;
|
||||
std::vector<uint8_t> m_data;
|
||||
bool m_valid;
|
||||
|
||||
DISALLOW_COPY(SrtmTile);
|
||||
@@ -48,12 +59,22 @@ private:
|
||||
class SrtmTileManager
|
||||
{
|
||||
public:
|
||||
explicit SrtmTileManager(std::string const & dir);
|
||||
|
||||
geometry::Altitude GetHeight(ms::LatLon const & coord);
|
||||
explicit SrtmTileManager(std::string const & dir) : m_dir(dir) {}
|
||||
|
||||
SrtmTile const & GetTile(ms::LatLon const & coord);
|
||||
|
||||
geometry::Altitude GetHeight(ms::LatLon const & coord)
|
||||
{
|
||||
return GetTile(coord).GetHeight(coord);
|
||||
}
|
||||
|
||||
geometry::Altitude GetTriangleHeight(ms::LatLon const & coord)
|
||||
{
|
||||
return GetTile(coord).GetTriangleHeight(coord);
|
||||
}
|
||||
|
||||
void Purge();
|
||||
|
||||
private:
|
||||
using LatLonKey = std::pair<int32_t, int32_t>;
|
||||
static LatLonKey GetKey(ms::LatLon const & coord);
|
||||
@@ -68,7 +89,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<LatLonKey, SrtmTile, Hash> m_tiles;
|
||||
using MapT = std::unordered_map<LatLonKey, SrtmTile, Hash>;
|
||||
MapT m_tiles;
|
||||
|
||||
DISALLOW_COPY(SrtmTileManager);
|
||||
};
|
||||
|
||||
@@ -77,7 +77,7 @@ class Altitudes
|
||||
public:
|
||||
Altitudes() = default;
|
||||
|
||||
explicit Altitudes(geometry::Altitudes const & altitudes) : m_altitudes(altitudes) {}
|
||||
explicit Altitudes(geometry::Altitudes && altitudes) : m_altitudes(std::move(altitudes)) {}
|
||||
|
||||
template <class TSink>
|
||||
void Serialize(geometry::Altitude minAltitude, TSink & sink) const
|
||||
|
||||
@@ -7,20 +7,25 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace feature
|
||||
{
|
||||
template <class ToDo>
|
||||
void ForEachFeature(ModelReaderPtr const & reader, ToDo && toDo)
|
||||
void ForEachFeature(FilesContainerR const & cont, ToDo && toDo)
|
||||
{
|
||||
FeaturesVectorTest features((FilesContainerR(reader)));
|
||||
features.GetVector().ForEach(std::forward<ToDo>(toDo));
|
||||
FeaturesVectorTest features(cont);
|
||||
features.GetVector().ForEach(toDo);
|
||||
}
|
||||
|
||||
template <class ToDo>
|
||||
void ForEachFeature(ModelReaderPtr reader, ToDo && toDo)
|
||||
{
|
||||
ForEachFeature(FilesContainerR(reader), toDo);
|
||||
}
|
||||
|
||||
template <class ToDo>
|
||||
void ForEachFeature(std::string const & fPath, ToDo && toDo)
|
||||
{
|
||||
ForEachFeature(std::make_unique<FileReader>(fPath), std::forward<ToDo>(toDo));
|
||||
ForEachFeature(std::make_unique<FileReader>(fPath), toDo);
|
||||
}
|
||||
} // namespace feature
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/classificator_loader.hpp"
|
||||
#include "indexer/data_source.hpp"
|
||||
#include "indexer/feature_algo.hpp"
|
||||
#include "indexer/feature_altitude.hpp"
|
||||
#include "indexer/feature_data.hpp"
|
||||
#include "indexer/feature_processor.hpp"
|
||||
@@ -27,27 +28,42 @@
|
||||
namespace get_altitude_tests
|
||||
{
|
||||
using namespace feature;
|
||||
using namespace geometry;
|
||||
using namespace platform;
|
||||
using namespace std;
|
||||
|
||||
void TestAltitudeOfAllMwmFeatures(string const & countryId,
|
||||
geometry::Altitude const altitudeLowerBoundMeters,
|
||||
geometry::Altitude const altitudeUpperBoundMeters)
|
||||
class FeaturesGuard
|
||||
{
|
||||
FrozenDataSource dataSource;
|
||||
public:
|
||||
FrozenDataSource m_dataSource;
|
||||
MwmSet::MwmHandle m_handle;
|
||||
unique_ptr<AltitudeLoaderCached> m_altitudes;
|
||||
|
||||
explicit FeaturesGuard(string const & countryId)
|
||||
{
|
||||
LocalCountryFile const country = integration::GetLocalCountryFileByCountryId(CountryFile(countryId));
|
||||
TEST_NOT_EQUAL(country, LocalCountryFile(), ());
|
||||
TEST(country.HasFiles(), (country));
|
||||
|
||||
pair<MwmSet::MwmId, MwmSet::RegResult> const res = dataSource.RegisterMap(country);
|
||||
pair<MwmSet::MwmId, MwmSet::RegResult> const res = m_dataSource.RegisterMap(country);
|
||||
TEST_EQUAL(res.second, MwmSet::RegResult::Success, ());
|
||||
auto const handle = dataSource.GetMwmHandleById(res.first);
|
||||
TEST(handle.IsAlive(), ());
|
||||
m_handle = m_dataSource.GetMwmHandleById(res.first);
|
||||
TEST(m_handle.IsAlive(), ());
|
||||
TEST(GetValue(), ());
|
||||
|
||||
auto altitudeLoader = make_unique<AltitudeLoaderCached>(*handle.GetValue());
|
||||
m_altitudes = make_unique<AltitudeLoaderCached>(*GetValue());
|
||||
}
|
||||
|
||||
ForEachFeature(country.GetPath(MapFileType::Map), [&](FeatureType & f, uint32_t const & id)
|
||||
MwmValue const * GetValue() { return m_handle.GetValue(); }
|
||||
};
|
||||
|
||||
void TestAltitudeOfAllMwmFeatures(string const & countryId,
|
||||
Altitude const altitudeLowerBoundMeters,
|
||||
Altitude const altitudeUpperBoundMeters)
|
||||
{
|
||||
FeaturesGuard features(countryId);
|
||||
|
||||
ForEachFeature(features.GetValue()->m_cont, [&](FeatureType & f, uint32_t const & id)
|
||||
{
|
||||
if (!routing::IsRoad(TypesHolder(f)))
|
||||
return;
|
||||
@@ -57,7 +73,7 @@ void TestAltitudeOfAllMwmFeatures(string const & countryId,
|
||||
if (pointsCount == 0)
|
||||
return;
|
||||
|
||||
geometry::Altitudes const & altitudes = altitudeLoader->GetAltitudes(id, pointsCount);
|
||||
auto const & altitudes = features.m_altitudes->GetAltitudes(id, pointsCount);
|
||||
TEST(!altitudes.empty(),
|
||||
("Empty altitude vector. MWM:", countryId, ", feature id:", id, ", altitudes:", altitudes));
|
||||
|
||||
@@ -69,7 +85,7 @@ void TestAltitudeOfAllMwmFeatures(string const & countryId,
|
||||
});
|
||||
}
|
||||
|
||||
UNIT_TEST(AllMwmFeaturesGetAltitudeTest)
|
||||
UNIT_TEST(GetAltitude_AllMwmFeaturesTest)
|
||||
{
|
||||
classificator::Load();
|
||||
|
||||
@@ -80,4 +96,49 @@ UNIT_TEST(AllMwmFeaturesGetAltitudeTest)
|
||||
TestAltitudeOfAllMwmFeatures("Netherlands_North Holland_Amsterdam", -25 /* altitudeLowerBoundMeters */,
|
||||
50 /* altitudeUpperBoundMeters */);
|
||||
}
|
||||
|
||||
/*
|
||||
void PrintGeometryAndAltitude(std::string const & countryID, ms::LatLon const & ll, double distM)
|
||||
{
|
||||
FeaturesGuard features(countryID);
|
||||
auto const point = mercator::FromLatLon(ll);
|
||||
m2::RectD const rect = mercator::RectByCenterXYAndSizeInMeters(point, distM);
|
||||
|
||||
features.m_dataSource.ForEachInRect([&](FeatureType & ft)
|
||||
{
|
||||
if (!routing::IsRoad(TypesHolder(ft)))
|
||||
return;
|
||||
|
||||
ft.ParseGeometry(FeatureType::BEST_GEOMETRY);
|
||||
size_t const pointsCount = ft.GetPointsCount();
|
||||
if (pointsCount == 0)
|
||||
return;
|
||||
|
||||
if (GetMinDistanceMeters(ft, point) > distM)
|
||||
return;
|
||||
|
||||
stringstream geomSS;
|
||||
geomSS.precision(20);
|
||||
for (size_t i = 0; i < pointsCount; ++i)
|
||||
{
|
||||
auto const ll = mercator::ToLatLon(ft.GetPoint(i));
|
||||
geomSS << "{ " << ll.m_lat << ", " << ll.m_lon << " }, ";
|
||||
}
|
||||
LOG(LINFO, (geomSS.str()));
|
||||
|
||||
auto const & altitudes = features.m_altitudes->GetAltitudes(ft.GetID().m_index, pointsCount);
|
||||
LOG(LINFO, (ft.GetName(StringUtf8Multilang::kDefaultCode), altitudes));
|
||||
|
||||
}, rect, scales::GetUpperScale());
|
||||
}
|
||||
|
||||
UNIT_TEST(GetAltitude_SamplesTest)
|
||||
{
|
||||
classificator::Load();
|
||||
|
||||
PrintGeometryAndAltitude("Italy_Lazio", {41.8998667, 12.4985937}, 15.0);
|
||||
PrintGeometryAndAltitude("Crimea", { 44.7598876, 34.3160482 }, 5.0);
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace get_altitude_tests
|
||||
|
||||
@@ -102,30 +102,35 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
Altitude GetValueImpl(ms::LatLon const & pos)
|
||||
Altitude GetValueImpl(ms::LatLon pos)
|
||||
{
|
||||
if (m_preferredTile != nullptr)
|
||||
{
|
||||
using mercator::kPointEqualityEps;
|
||||
|
||||
// Each SRTM tile overlaps the top row in the bottom tile and the right row in the left tile.
|
||||
// Try to prevent loading a new tile if the position can be found in the loaded one.
|
||||
auto const latDist = pos.m_lat - m_leftBottomOfPreferredTile.m_lat;
|
||||
auto const lonDist = pos.m_lon - m_leftBottomOfPreferredTile.m_lon;
|
||||
if (latDist > -mercator::kPointEqualityEps && latDist < 1.0 + mercator::kPointEqualityEps && lonDist > -mercator::kPointEqualityEps && lonDist < 1.0 + mercator::kPointEqualityEps)
|
||||
if (latDist > -kPointEqualityEps && latDist < 1.0 + kPointEqualityEps &&
|
||||
lonDist > -kPointEqualityEps && lonDist < 1.0 + kPointEqualityEps)
|
||||
{
|
||||
ms::LatLon innerPos = pos;
|
||||
if (latDist < 0.0)
|
||||
innerPos.m_lat += mercator::kPointEqualityEps;
|
||||
pos.m_lat += kPointEqualityEps;
|
||||
else if (latDist >= 1.0)
|
||||
innerPos.m_lat -= mercator::kPointEqualityEps;
|
||||
pos.m_lat -= kPointEqualityEps;
|
||||
if (lonDist < 0.0)
|
||||
innerPos.m_lon += mercator::kPointEqualityEps;
|
||||
pos.m_lon += kPointEqualityEps;
|
||||
else if (lonDist >= 1.0)
|
||||
innerPos.m_lon -= mercator::kPointEqualityEps;
|
||||
return m_preferredTile->GetHeight(innerPos);
|
||||
pos.m_lon -= kPointEqualityEps;
|
||||
|
||||
/// @todo Can't call GetTriangleHeight here and below because it breaks
|
||||
/// ContoursBuilder::AddSegment level constraint. Should investigate deeper.
|
||||
return m_preferredTile->GetHeight(pos);
|
||||
}
|
||||
}
|
||||
|
||||
return m_srtmManager.GetHeight(pos);
|
||||
return m_srtmManager.GetTile(pos).GetHeight(pos);
|
||||
}
|
||||
|
||||
Altitude GetMedianValue(ms::LatLon const & pos)
|
||||
@@ -179,6 +184,8 @@ public:
|
||||
, m_bottomLat(bottomLat)
|
||||
{}
|
||||
|
||||
/// @todo Should we use the same approach as in SrtmTile::GetTriangleHeight?
|
||||
/// This function is used in ASTER fiter only.
|
||||
Altitude GetValue(ms::LatLon const & pos) override
|
||||
{
|
||||
double ln = pos.m_lon - m_leftLon;
|
||||
@@ -374,11 +381,10 @@ private:
|
||||
ValuesProvider<Altitude> & altProvider,
|
||||
Contours<Altitude> & contours)
|
||||
{
|
||||
auto const avoidSeam = lat == kAsterTilesLatTop || (lat == kAsterTilesLatBottom - 1);
|
||||
if (avoidSeam)
|
||||
// Avoid seam between SRTM and ASTER.
|
||||
if ((lat == kAsterTilesLatTop) || (lat == kAsterTilesLatBottom - 1))
|
||||
{
|
||||
m_srtmProvider.SetPrefferedTile(ms::LatLon(lat == kAsterTilesLatTop ? lat - 0.5 : lat + 0.5,
|
||||
lon));
|
||||
m_srtmProvider.SetPrefferedTile(ms::LatLon(lat == kAsterTilesLatTop ? lat - 0.5 : lat + 0.5, lon));
|
||||
SeamlessAltitudeProvider seamlessAltProvider(m_srtmProvider, altProvider,
|
||||
[](ms::LatLon const & pos)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user