From 1a467a1b97b913f6f0fe680c29d5943f486990d8 Mon Sep 17 00:00:00 2001 From: Sergey Magidovich Date: Thu, 5 May 2016 11:02:28 +0300 Subject: [PATCH] Fix buildings from xml loading. --- indexer/edits_migration.cpp | 18 +++--------------- map/framework.cpp | 24 +++++++++++++++++++----- map/framework.hpp | 3 ++- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/indexer/edits_migration.cpp b/indexer/edits_migration.cpp index c1577b786f..fc58779527 100644 --- a/indexer/edits_migration.cpp +++ b/indexer/edits_migration.cpp @@ -10,19 +10,6 @@ #include "std/algorithm.hpp" #include "std/unique_ptr.hpp" -namespace -{ -m2::PointD CalculateCenter(vector const & geometry) -{ - ASSERT(!geometry.empty() && geometry.size() % 3 == 0, - ("Invalid geometry should be handled in caller. geometry.size() =", geometry.size())); - - auto const boundingBox = ApplyCalculator(begin(geometry), end(geometry), - m2::CalculateBoundingBox()); - return ApplyCalculator(begin(geometry), end(geometry), m2::CalculatePointOnSurface(boundingBox)); -} -} // namespace - namespace editor { FeatureID MigrateNodeFeatureIndex(osm::Editor::TForEachFeaturesNearByFn & forEach, @@ -57,10 +44,11 @@ FeatureID MigrateWayFeatureIndex(osm::Editor::TForEachFeaturesNearByFn & forEach auto bestScore = 0.6; // initial score is used as a threshold. auto geometry = xml.GetGeometry(); - if (geometry.empty() || geometry.size() % 3 != 0) + if (geometry.empty()) MYTHROW(MigrationError, ("Feature has invalid geometry", xml)); - auto const someFeaturePoint = CalculateCenter(geometry); + // This can be any point on a feature. + auto const someFeaturePoint = geometry[0]; sort(begin(geometry), end(geometry)); // Sort to use in set_intersection. auto count = 0; diff --git a/map/framework.cpp b/map/framework.cpp index 74370a8075..3a2fedecd1 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -389,8 +389,14 @@ Framework::Framework() return streets.first[streets.second].m_name; return {}; }); - editor.SetForEachFeatureAtPointFn(bind(&Framework::ForEachFeatureAtPoint, this, _1, _2)); + // Due to floating points accuracy issues (geometry is saved in editor up to 7 digits + // after dicimal poin) some feature vertexes are threated as external to a given feature. + auto const pointToFeatureDistanceToleranceInMeters = 1e-3; + editor.SetForEachFeatureAtPointFn(bind(&Framework::ForEachFeatureAtPoint, this, _1, _2, + pointToFeatureDistanceToleranceInMeters)); editor.LoadMapEdits(); + + m_model.GetIndex().AddObserver(editor); } Framework::~Framework() @@ -1741,7 +1747,8 @@ bool Framework::ShowMapForURL(string const & url) return false; } -void Framework::ForEachFeatureAtPoint(TFeatureTypeFn && fn, m2::PointD const & mercator) const +void Framework::ForEachFeatureAtPoint(TFeatureTypeFn && fn, m2::PointD const & mercator, + double featureDistanceToleranceInMeters) const { constexpr double kSelectRectWidthInMeters = 1.1; constexpr double kMetersToLinearFeature = 3; @@ -1760,10 +1767,17 @@ void Framework::ForEachFeatureAtPoint(TFeatureTypeFn && fn, m2::PointD const & m fn(ft); break; case feature::GEOM_AREA: - if (ft.GetLimitRect(kScale).IsPointInside(mercator) && - feature::GetMinDistanceMeters(ft, mercator) == 0.0) { - fn(ft); + auto limitRect = ft.GetLimitRect(kScale); + // Be a little more tolerant. When used by editor mercator is given + // with some error, so we must extend limit rect a bit. + limitRect.Inflate(MercatorBounds::GetCellID2PointAbsEpsilon(), + MercatorBounds::GetCellID2PointAbsEpsilon()); + if (limitRect.IsPointInside(mercator) && + feature::GetMinDistanceMeters(ft, mercator) <= featureDistanceToleranceInMeters) + { + fn(ft); + } } break; case feature::GEOM_UNDEFINED: diff --git a/map/framework.hpp b/map/framework.hpp index 52b51e423b..8869518c1f 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -523,7 +523,8 @@ public: /// @returns nullptr if no feature was found at the given mercator point. unique_ptr GetFeatureAtPoint(m2::PointD const & mercator) const; using TFeatureTypeFn = function; - void ForEachFeatureAtPoint(TFeatureTypeFn && fn, m2::PointD const & mercator) const; + void ForEachFeatureAtPoint(TFeatureTypeFn && fn, m2::PointD const & mercator, + double featureDistanceToleranceInMeters = 0.0) const; /// Set parse to false if you don't need all feature fields ready. /// TODO(AlexZ): Refactor code which uses this method to get rid of it. /// FeatureType instances shoud not be used outside ForEach* core methods.