diff --git a/generator/feature_segments_checker/feature_segments_checker.cpp b/generator/feature_segments_checker/feature_segments_checker.cpp index 49b4fc70be..ad66dcfc7c 100644 --- a/generator/feature_segments_checker/feature_segments_checker.cpp +++ b/generator/feature_segments_checker/feature_segments_checker.cpp @@ -17,8 +17,10 @@ #include "base/logging.hpp" #include "3party/gflags/src/gflags/gflags.h" +#include "3party/kdtree++/kdtree.hpp" #include "std/iostream.hpp" +#include "std/fstream.hpp" #include "std/map.hpp" #include "std/string.hpp" @@ -33,12 +35,26 @@ routing::BicycleModel const & GetBicycleModel() return instance; } -template -void IncrementStats(K const & k, map & m) +int32_t Coord2RoughCoord(double d) { - if (m.find(k) == m.cend()) - m[k] = 0; - m[k] += 1; + int32_t constexpr kFactor = 100000; + return static_cast(round(d * kFactor)); +} + +struct RoughPoint +{ + RoughPoint(m2::PointD const & point) + : x(Coord2RoughCoord(point.x)), y(Coord2RoughCoord(point.y)) {} + + int32_t x; + int32_t y; +}; + +bool operator< (RoughPoint const & l, RoughPoint const & r) +{ + if (l.x != r.x) + return l.x < r.x; + return l.y < r.y; } template @@ -46,66 +62,67 @@ void PrintCont(Cont const & cont, string const & title, string const & msgText1, string const & msgText2) { cout << endl << title << endl; - for (auto const a : cont) + for (auto const & a : cont) cout << a.second << msgText1 << a.first << msgText2 << endl; } -/// \brief Adds |point| to |uniqueRoadPoints| if there's no a point in |uniqueRoadPoints| -/// in |kErrorMeters| environment of |point|. -/// \note This method does get an exact result. The problem is points are sorted in -/// |uniqueRoadPoints| -/// according to operator<(m2::PointD const &, m2::PointD const &). It's not the same criteria with -/// MercatorBounds::DistanceOnEarth(lowerPnt, point). But according to tests the error is less then 1%, -/// and function implemented below works much faster. -bool IsNewFeatureEnd(m2::PointD const & point, set & uniqueRoadPoints) +template +void WriteCSV(Cont const & cont, string const & fileName) { - double constexpr kErrorMeters = 3.; - auto const lower = uniqueRoadPoints.lower_bound(point); - auto const upper = uniqueRoadPoints.upper_bound(point); + ofstream fout(fileName); + for (auto const & a : cont) + fout << a.first << ";" << a.second << endl; +} - if (lower == uniqueRoadPoints.cend() || upper == uniqueRoadPoints.cend()) - uniqueRoadPoints.insert(point); - - m2::PointD const lowerPnt = *lower; - m2::PointD const upperPnt = *upper; - - if (MercatorBounds::DistanceOnEarth(lowerPnt, point) <= kErrorMeters || - MercatorBounds::DistanceOnEarth(upperPnt, point) <= kErrorMeters) - { - return false; - } - - uniqueRoadPoints.insert(point); - return true; +/// \returns expected point altitude in meters according to linear model. +double ExpectedPointAltitude(int16_t startAltitudeMeters, int16_t endAltitudeMeters, + double distFromStartMeters, double featureLengthMeters) +{ + if (featureLengthMeters == 0.0) + return 0; + double const k = (endAltitudeMeters - startAltitudeMeters) / featureLengthMeters; + return startAltitudeMeters + k * distFromStartMeters; } class Processor { public: generator::SrtmTileManager & m_srtmManager; - set m_uniqueRoadPoints; + set m_uniqueRoadPoints; /// Key is altitude difference for feature in meters. If a feature goes up the key is more then 0. /// Value is a feature counter. - map m_altitudeDiffs; + map m_altitudeDiffs; /// Key is length of feature in meters. Value is a feature counter. - map m_featureLength; + map m_featureLength; /// Key is length of feature segment in meters. Value is a segment counter. - map m_segLength; + map m_segLength; /// Key is difference between two values: /// 1. how many meters it's necessary to go up following the feature. If feature wavy /// calculates only raise meters. /// 2. the difference in altitude between end and start of features. /// Value is a segment counter. - map m_featureWave; + map m_featureWave; + /// Key is number of meters which is necessary to go up following the feature. + /// Value is a feature counter. + map m_featureUp; + /// Key is number of meters which is necessary to go down following the feature. + /// Value is a feature counter. + map m_featureDown; + /// Key is number of meters. It shows altitude deviation of intermediate feature points + /// from linear model. + /// Value is a feature counter. + map m_diffFromLinear; /// Feature counter for GetBicycleModel().IsRoad(feature) == true. uint32_t m_roadCount; + /// Feature counter for empty features with GetBicycleModel().IsRoad(feature). + uint32_t m_emptyRoadCount; /// Point counter for feature where GetBicycleModel().IsRoad(feature) == true. uint32_t m_roadPointCount; /// Feature counter for GetBicycleModel().IsRoad(feature) != true. uint32_t m_notRoadCount; Processor(generator::SrtmTileManager & manager) - : m_srtmManager(manager), m_roadCount(0), m_roadPointCount(0), m_notRoadCount(0) + : m_srtmManager(manager), m_roadCount(0), m_emptyRoadCount(0), m_roadPointCount(0), m_notRoadCount(0) { } @@ -119,73 +136,94 @@ public: } f.ParseGeometry(FeatureType::BEST_GEOMETRY); + uint32_t const pointCount = f.GetPointsCount(); + if (pointCount == 0) + { + ++m_emptyRoadCount; + return; + } + ++m_roadCount; - size_t const pointCount = f.GetPointsCount(); m_roadPointCount += pointCount; for (int i = 0; i < pointCount; ++i) - { - IsNewFeatureEnd(f.GetPoint(i), m_uniqueRoadPoints); - } + m_uniqueRoadPoints.insert(RoughPoint(f.GetPoint(i))); - // Feature length. - size_t featureLengthMeters = 0; - if (pointCount != 0) - featureLengthMeters = - MercatorBounds::DistanceOnEarth(f.GetPoint(0), f.GetPoint(pointCount - 1)); - IncrementStats(featureLengthMeters, m_featureLength); - - // Feature segment length. - if (pointCount != 0) + // Feature length and feature segment length. + double realFeatureLengthMeters = 0.0; + for (int i = 0; i < pointCount - 1; ++i) { - for (int i = 0; i < pointCount - 1; ++i) - { - size_t const segmentLengthMeters = - MercatorBounds::DistanceOnEarth(f.GetPoint(i), f.GetPoint(i + 1)); - IncrementStats(segmentLengthMeters, m_segLength); - } + // Feature segment length. + double const realSegmentLengthMeters = MercatorBounds::DistanceOnEarth(f.GetPoint(i), f.GetPoint(i + 1)); + m_segLength[static_cast(floor(realSegmentLengthMeters))]++; + + // Feature length. + realFeatureLengthMeters += realSegmentLengthMeters; } + m_featureLength[static_cast(floor(realFeatureLengthMeters))]++; // Feature altitude difference. - generator::SrtmTile::THeight startAltitude = 0, endAltitude = 0; - if (pointCount != 0) - { - startAltitude = m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(0))); - endAltitude = m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(pointCount - 1))); - } - + generator::SrtmTile::THeight const startAltitude = + m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(0))); + generator::SrtmTile::THeight const endAltitude = + m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(pointCount - 1))); int16_t const altitudeDiff = endAltitude - startAltitude; - IncrementStats(altitudeDiff, m_altitudeDiffs); + m_altitudeDiffs[altitudeDiff]++; // Wave feature factor. Climb minus altitude difference. int32_t climb = 0; - if (pointCount != 0) + int32_t up = 0; + int32_t down = 0; + for (int i = 0; i < pointCount - 1; ++i) { - for (int i = 0; i < pointCount - 1; ++i) + auto const segAltDiff = + (m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(i + 1))) - + m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(i)))); + if (altitudeDiff >= 0) { - auto const segAltDiff = - (m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(i + 1))) - - m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(i)))); - if (altitudeDiff >= 0) - { - // If the feature goes up generaly calculates how many meters it's necessary - // to go up following the feature. - if (segAltDiff > 0) - climb += segAltDiff; - } - else - { - // If the feature goes down generaly calculates how many meters it's necessary - // to go down following the feature. - if (segAltDiff < 0) - climb += segAltDiff; - } + // If the feature goes up generaly calculates how many meters it's necessary + // to go up following the feature. + if (segAltDiff > 0) + climb += segAltDiff; } - // Estimates monotony of the feature. If climb == altitudeDiff it's monotonous. - // If not it's wavy. The more abs(climb - altitudeDiff) the more wavy the feature. - int32_t const waveFactor = climb - altitudeDiff; - IncrementStats(waveFactor, m_featureWave); + else + { + // If the feature goes down generaly calculates how many meters it's necessary + // to go down following the feature. + if (segAltDiff < 0) + climb += segAltDiff; + } + + if (segAltDiff >= 0) + up += segAltDiff; + else + down += segAltDiff; + } + // Estimates monotony of the feature. If climb == altitudeDiff it's monotonous. + // If not it's wavy. The more abs(climb - altitudeDiff) the more wavy the feature. + int32_t const waveFactor = climb - altitudeDiff; + m_featureWave[waveFactor]++; + m_featureUp[up]++; + m_featureDown[down]++; + + // Altitude deviation of internal feature points from linear model. + if (realFeatureLengthMeters == 0.0) + return; + + double distFromStartMeters = 0; + for (int i = 1; i < pointCount - 1; ++i) + { + // Feature segment length. + double const segmentLengthMeters = + MercatorBounds::DistanceOnEarth(f.GetPoint(i - 1), f.GetPoint(i)); + distFromStartMeters += segmentLengthMeters; + + generator::SrtmTile::THeight const pointAltitude = + m_srtmManager.GetHeight(MercatorBounds::ToLatLon(f.GetPoint(i))); + int32_t const deviation = static_cast(ExpectedPointAltitude(startAltitude, endAltitude, distFromStartMeters, + realFeatureLengthMeters)) - pointAltitude; + m_diffFromLinear[deviation]++; } } }; @@ -193,7 +231,7 @@ public: int main(int argc, char ** argv) { - google::SetUsageMessage("This tool extracts some staticstics about features and its altetude."); + google::SetUsageMessage("This tool extracts some staticstics about features and its altitudes."); google::ParseCommandLineFlags(&argc, &argv, true); LOG(LINFO, ("srtm_path =", FLAGS_srtm_path)); @@ -202,19 +240,35 @@ int main(int argc, char ** argv) classificator::Load(); generator::SrtmTileManager manager(FLAGS_srtm_path); - Processor doProcess(manager); - feature::ForEachFromDat(FLAGS_mwm_path, doProcess); + Processor processor(manager); + feature::ForEachFromDat(FLAGS_mwm_path, processor); - cout << endl << "doProcess.m_roadCount = " << doProcess.m_roadCount << endl; - cout << "doProcess.m_uniqueRoadPoints.size = " << doProcess.m_uniqueRoadPoints.size() << endl; - cout << "doProcess.m_roadPointCount = " << doProcess.m_roadPointCount << endl; - cout << "doProcess.m_notRoadCount = " << doProcess.m_notRoadCount << endl; + cout << endl << "Road feature count = " << processor.m_roadCount << endl; + cout << "Empty road feature count = " << processor.m_emptyRoadCount << endl; + cout << "Unique road points count = " << processor.m_uniqueRoadPoints.size() << endl; + cout << "All road point count = " << processor.m_roadPointCount << endl; + cout << "Not road feature count = " << processor.m_notRoadCount << endl; - PrintCont(doProcess.m_altitudeDiffs, "Altitude difference between start and end of features.", + PrintCont(processor.m_altitudeDiffs, "Altitude difference between start and end of features.", " feature(s) with altitude difference ", " meter(s)"); - PrintCont(doProcess.m_featureLength, "Feature length.", " feature(s) with length ", " meter(s)"); - PrintCont(doProcess.m_segLength, "Feature segment length.", " segment(s) with length ", + WriteCSV(processor.m_altitudeDiffs, "altitude_difference.csv"); + + PrintCont(processor.m_featureLength, "Feature length.", " feature(s) with length ", " meter(s)"); + WriteCSV(processor.m_featureLength, "feature_length.csv"); + + PrintCont(processor.m_segLength, "Feature segment length.", " segment(s) with length ", " meter(s)"); - PrintCont(doProcess.m_featureWave, "Wave factor", " features(s) with wave factor ", ""); + + PrintCont(processor.m_featureWave, "Wave factor", " feature(s) with wave factor ", ""); + WriteCSV(processor.m_featureWave, "feature_wave.csv"); + + PrintCont(processor.m_featureUp, "Feature go up in meters", " feature(s) go up ", " meter(s)"); + WriteCSV(processor.m_featureUp, "feature_up.csv"); + + PrintCont(processor.m_featureDown, "Feature go down in meters", " feature(s) go down ", " meter(s)"); + WriteCSV(processor.m_featureDown, "feature_down.csv"); + + PrintCont(processor.m_diffFromLinear, "Altitude deviation of internal feature points from linear model.", + " internal feature point(s) deviate from linear model with ", " meter(s)"); return 0; }