Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
authorSergey Magidovich <mgsergio@mapswithme.com>2016-03-21 14:40:44 +0300
committerSergey Yershov <yershov@corp.mail.ru>2016-03-23 16:59:26 +0300
commitd4aa42b8a4e3bd8272f4615e83e43150f34ba834 (patch)
tree0c2ca9dd925b075363bf728cd3330e76376cd319 /editor
parent36fc19a3d2554bdc931b79bbf20d7d0b3a5b8213 (diff)
Match against relations.
Diffstat (limited to 'editor')
-rw-r--r--editor/changeset_wrapper.cpp53
-rw-r--r--editor/changeset_wrapper.hpp5
-rw-r--r--editor/editor_tests/osm_feature_matcher_test.cpp252
-rw-r--r--editor/osm_feature_matcher.cpp98
-rw-r--r--editor/osm_feature_matcher.hpp4
5 files changed, 358 insertions, 54 deletions
diff --git a/editor/changeset_wrapper.cpp b/editor/changeset_wrapper.cpp
index 3a99160fb5..e844e23218 100644
--- a/editor/changeset_wrapper.cpp
+++ b/editor/changeset_wrapper.cpp
@@ -15,6 +15,20 @@
using editor::XMLFeature;
+namespace
+{
+m2::RectD GetBoundingRect(vector<m2::PointD> const & geometry)
+{
+ m2::RectD rect;
+ for (auto const & p : geometry)
+ {
+ auto const latLon = MercatorBounds::ToLatLon(p);
+ rect.Add({latLon.lon, latLon.lat});
+ }
+ return rect;
+}
+} // namespace
+
namespace pugi
{
string DebugPrint(xml_document const & doc)
@@ -27,7 +41,6 @@ string DebugPrint(xml_document const & doc)
namespace osm
{
-
ChangesetWrapper::ChangesetWrapper(TKeySecret const & keySecret,
ServerApi06::TKeyValueTags const & comments) noexcept
: m_changesetComments(comments), m_api(OsmOAuth::ServerAuth(keySecret))
@@ -59,6 +72,16 @@ void ChangesetWrapper::LoadXmlFromOSM(ms::LatLon const & ll, pugi::xml_document
MYTHROW(OsmXmlParseException, ("Can't parse OSM server response for GetXmlFeaturesAtLatLon request", response.second));
}
+void ChangesetWrapper::LoadXmlFromOSM(m2::RectD const & rect, pugi::xml_document & doc)
+{
+ auto const response = m_api.GetXmlFeaturesInRect(rect);
+ if (response.first != OsmOAuth::HTTP::OK)
+ MYTHROW(HttpErrorException, ("HTTP error", response, "with GetXmlFeaturesInRect", rect));
+
+ if (pugi::status_ok != doc.load(response.second.c_str()).status)
+ MYTHROW(OsmXmlParseException, ("Can't parse OSM server response for GetXmlFeaturesInRect request", response.second));
+}
+
XMLFeature ChangesetWrapper::GetMatchingNodeFeatureFromOSM(m2::PointD const & center)
{
// Match with OSM node.
@@ -80,6 +103,7 @@ XMLFeature ChangesetWrapper::GetMatchingNodeFeatureFromOSM(m2::PointD const & ce
XMLFeature ChangesetWrapper::GetMatchingAreaFeatureFromOSM(vector<m2::PointD> const & geometry)
{
// TODO: Make two/four requests using points on inscribed rectagle.
+ bool hasRelation = false;
for (auto const & pt : geometry)
{
ms::LatLon const ll = MercatorBounds::ToLatLon(pt);
@@ -87,11 +111,32 @@ XMLFeature ChangesetWrapper::GetMatchingAreaFeatureFromOSM(vector<m2::PointD> co
// Throws!
LoadXmlFromOSM(ll, doc);
- pugi::xml_node const bestWay = GetBestOsmWay(doc, geometry);
- if (bestWay.empty())
+ if (doc.select_node("osm/relation"))
+ {
+ auto const rect = GetBoundingRect(geometry);
+ LoadXmlFromOSM(rect, doc);
+ hasRelation = true;
+ }
+
+ pugi::xml_node const bestWayOrRelation = GetBestOsmWayOrRelation(doc, geometry);
+ if (!bestWayOrRelation)
+ {
+ if (hasRelation)
+ break;
continue;
+ }
+
+ if (strcmp(bestWayOrRelation.name(), "relation") == 0)
+ {
+ stringstream sstr;
+ bestWayOrRelation.print(sstr);
+ LOG(LDEBUG, ("Relation is the best match", sstr.str()));
+ MYTHROW(RelationFeatureAreNotSupportedException,
+ ("Got relation as the best matching."));
+ }
- XMLFeature const way(bestWay);
+ // TODO: rename to wayOrRelation when relations are handled.
+ XMLFeature const way(bestWayOrRelation);
ASSERT(way.IsArea(), ("Best way must be an area."));
// AlexZ: TODO: Check that this way is really match our feature.
diff --git a/editor/changeset_wrapper.hpp b/editor/changeset_wrapper.hpp
index d1665276f5..0eefcf4788 100644
--- a/editor/changeset_wrapper.hpp
+++ b/editor/changeset_wrapper.hpp
@@ -6,6 +6,7 @@
#include "editor/xml_feature.hpp"
#include "geometry/point2d.hpp"
+#include "geometry/rect2d.hpp"
#include "std/set.hpp"
#include "std/vector.hpp"
@@ -14,7 +15,6 @@ class FeatureType;
namespace osm
{
-
struct ClientToken;
class ChangesetWrapper
@@ -28,6 +28,8 @@ public:
DECLARE_EXCEPTION(CreateChangeSetFailedException, ChangesetWrapperException);
DECLARE_EXCEPTION(ModifyNodeFailedException, ChangesetWrapperException);
DECLARE_EXCEPTION(LinearFeaturesAreNotSupportedException, ChangesetWrapperException);
+ // TODO: Remove this when relations are handled properly.
+ DECLARE_EXCEPTION(RelationFeatureAreNotSupportedException, ChangesetWrapperException);
ChangesetWrapper(TKeySecret const & keySecret, ServerApi06::TKeyValueTags const & comments) noexcept;
~ChangesetWrapper();
@@ -51,6 +53,7 @@ private:
/// Unfortunately, pugi can't return xml_documents from methods.
/// Throws exceptions from above list.
void LoadXmlFromOSM(ms::LatLon const & ll, pugi::xml_document & doc);
+ void LoadXmlFromOSM(m2::RectD const & rect, pugi::xml_document & doc);
ServerApi06::TKeyValueTags m_changesetComments;
ServerApi06 m_api;
diff --git a/editor/editor_tests/osm_feature_matcher_test.cpp b/editor/editor_tests/osm_feature_matcher_test.cpp
index f6ac0c3e47..d0a8361b6c 100644
--- a/editor/editor_tests/osm_feature_matcher_test.cpp
+++ b/editor/editor_tests/osm_feature_matcher_test.cpp
@@ -5,7 +5,9 @@
#include "3party/pugixml/src/pugixml.hpp"
-static char const * const osmRawResponseWay = R"SEP(
+namespace
+{
+char const * const osmRawResponseWay = R"SEP(
<osm version="0.6" generator="CGImap 0.4.0 (22123 thorn-03.openstreetmap.org)" copyright="OpenStreetMap and contributors">
<bounds minlat="53.8976570" minlon="27.5576615" maxlat="53.8976570" maxlon="27.5576615"/>
<node id="277171984" visible="true" version="2" changeset="20577443" timestamp="2014-02-15T14:37:39Z" user="iglezz" uid="450366" lat="53.8978034" lon="27.5577642"/>
@@ -52,7 +54,7 @@ static char const * const osmRawResponseWay = R"SEP(
</osm>
)SEP";
-static char const * const osmRawResponseNode = R"SEP(
+char const * const osmRawResponseNode = R"SEP(
<osm version="0.6" generator="CGImap 0.4.0 (5501 thorn-02.openstreetmap.org)" copyright="OpenStreetMap and contributors">
<bounds minlat="53.8977000" minlon="27.5578900" maxlat="53.8977700" maxlon="27.5579800"/>
<node id="2673014342" visible="true" version="1" changeset="20577443" timestamp="2014-02-15T14:37:11Z" user="iglezz" uid="450366" lat="53.8976095" lon="27.5579360"/>
@@ -84,6 +86,202 @@ static char const * const osmRawResponseNode = R"SEP(
</osm>
)SEP";
+char const * const osmRawResponseRelation = R"SEP(
+<?xml version="1.0" encoding="UTF-8"?>
+<osm version="0.6" generator="CGImap 0.4.0 (22560 thorn-01.openstreetmap.org)" copyright="OpenStreetMap and contributors">
+ <bounds minlat="55.7509200" minlon="37.6397200" maxlat="55.7515400" maxlon="37.6411300"/>
+ <node id="271892032" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:35Z" user="Scondo" uid="421524" lat="55.7524913" lon="37.6397264"/>
+ <node id="271892033" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:17Z" user="Scondo" uid="421524" lat="55.7522475" lon="37.6391447"/>
+ <node id="583193392" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:07Z" user="Vovanium" uid="87682" lat="55.7507909" lon="37.6404902"/>
+ <node id="583193432" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7510964" lon="37.6397197"/>
+ <node id="583193426" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7510560" lon="37.6394035"/>
+ <node id="583193429" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7512865" lon="37.6396919"/>
+ <node id="583193395" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7509787" lon="37.6401799"/>
+ <node id="583193415" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7510898" lon="37.6403571"/>
+ <node id="583193424" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7508581" lon="37.6399029"/>
+ <node id="583193422" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7509689" lon="37.6400415"/>
+ <node id="583193398" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7514775" lon="37.6401937"/>
+ <node id="583193416" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7513532" lon="37.6405069"/>
+ <node id="583193431" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7512162" lon="37.6398695"/>
+ <node id="583193390" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7507783" lon="37.6410989"/>
+ <node id="583193388" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7509982" lon="37.6416194"/>
+ <node id="583193405" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7514149" lon="37.6406910"/>
+ <node id="583193408" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7509930" lon="37.6412441"/>
+ <node id="583193410" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7509124" lon="37.6406648"/>
+ <node id="583193401" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:09Z" user="Vovanium" uid="87682" lat="55.7516648" lon="37.6407506"/>
+ <node id="666179513" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7510740" lon="37.6401059"/>
+ <node id="666179517" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7511507" lon="37.6403206"/>
+ <node id="666179519" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7512863" lon="37.6403782"/>
+ <node id="666179521" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7512185" lon="37.6403206"/>
+ <node id="666179522" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7512214" lon="37.6400483"/>
+ <node id="666179524" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7513393" lon="37.6401111"/>
+ <node id="666179526" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7514337" lon="37.6402525"/>
+ <node id="666179528" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7507439" lon="37.6406349"/>
+ <node id="666179530" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7507291" lon="37.6407868"/>
+ <node id="666179531" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7507380" lon="37.6409544"/>
+ <node id="666179540" visible="true" version="1" changeset="4128036" timestamp="2010-03-14T18:30:48Z" user="Vovanium" uid="87682" lat="55.7508736" lon="37.6408287"/>
+ <node id="595699492" visible="true" version="2" changeset="4128036" timestamp="2010-03-14T18:31:08Z" user="Vovanium" uid="87682" lat="55.7508900" lon="37.6410015"/>
+ <node id="271892037" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:03Z" user="Scondo" uid="421524" lat="55.7519689" lon="37.6393462"/>
+ <node id="666179544" visible="true" version="2" changeset="8261156" timestamp="2011-05-27T10:18:03Z" user="Scondo" uid="421524" lat="55.7523858" lon="37.6394615"/>
+ <node id="271892040" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:09Z" user="Scondo" uid="421524" lat="55.7518044" lon="37.6401900"/>
+ <node id="271892039" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:11Z" user="Scondo" uid="421524" lat="55.7518997" lon="37.6400631"/>
+ <node id="271892031" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:23Z" user="Scondo" uid="421524" lat="55.7517772" lon="37.6406618"/>
+ <node id="271892036" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:23Z" user="Scondo" uid="421524" lat="55.7521424" lon="37.6397730"/>
+ <node id="271892035" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:25Z" user="Scondo" uid="421524" lat="55.7522520" lon="37.6396264"/>
+ <node id="666179542" visible="true" version="2" changeset="8261156" timestamp="2011-05-27T10:18:26Z" user="Scondo" uid="421524" lat="55.7523415" lon="37.6393631"/>
+ <node id="271892038" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:30Z" user="Scondo" uid="421524" lat="55.7517353" lon="37.6396389"/>
+ <node id="666179545" visible="true" version="2" changeset="8261156" timestamp="2011-05-27T10:18:30Z" user="Scondo" uid="421524" lat="55.7523947" lon="37.6392844"/>
+ <node id="271892041" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:34Z" user="Scondo" uid="421524" lat="55.7516804" lon="37.6398672"/>
+ <node id="666179548" visible="true" version="2" changeset="8261156" timestamp="2011-05-27T10:18:35Z" user="Scondo" uid="421524" lat="55.7524390" lon="37.6393828"/>
+ <node id="271892030" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:38Z" user="Scondo" uid="421524" lat="55.7515240" lon="37.6400640"/>
+ <node id="271892034" visible="true" version="4" changeset="8261156" timestamp="2011-05-27T10:18:40Z" user="Scondo" uid="421524" lat="55.7521203" lon="37.6393028"/>
+ <node id="2849850611" visible="true" version="2" changeset="33550372" timestamp="2015-08-24T15:55:36Z" user="vadp" uid="326091" lat="55.7507261" lon="37.6405934"/>
+ <node id="2849850614" visible="true" version="1" changeset="22264538" timestamp="2014-05-11T07:26:43Z" user="Vadim Zudkin" uid="177747" lat="55.7509233" lon="37.6401297"/>
+ <node id="3712207029" visible="true" version="1" changeset="33550372" timestamp="2015-08-24T15:55:35Z" user="vadp" uid="326091" lat="55.7510865" lon="37.6400013"/>
+ <node id="3712207030" visible="true" version="1" changeset="33550372" timestamp="2015-08-24T15:55:35Z" user="vadp" uid="326091" lat="55.7512462" lon="37.6399456"/>
+ <node id="3712207031" visible="true" version="2" changeset="33550412" timestamp="2015-08-24T15:57:10Z" user="vadp" uid="326091" lat="55.7514944" lon="37.6401534"/>
+ <node id="3712207032" visible="true" version="2" changeset="33550412" timestamp="2015-08-24T15:57:10Z" user="vadp" uid="326091" lat="55.7516969" lon="37.6407362">
+ <tag k="access" v="private"/>
+ <tag k="barrier" v="gate"/>
+ </node>
+ <node id="3712207033" visible="true" version="2" changeset="33550412" timestamp="2015-08-24T15:57:10Z" user="vadp" uid="326091" lat="55.7517316" lon="37.6408217"/>
+ <node id="3712207034" visible="true" version="2" changeset="33550412" timestamp="2015-08-24T15:57:10Z" user="vadp" uid="326091" lat="55.7517602" lon="37.6409066"/>
+ <node id="2849850613" visible="true" version="3" changeset="33551686" timestamp="2015-08-24T16:50:21Z" user="vadp" uid="326091" lat="55.7507965" lon="37.6399611"/>
+ <node id="338464706" visible="true" version="3" changeset="33551686" timestamp="2015-08-24T16:50:21Z" user="vadp" uid="326091" lat="55.7510322" lon="37.6393637"/>
+ <node id="338464708" visible="true" version="7" changeset="33551686" timestamp="2015-08-24T16:50:21Z" user="vadp" uid="326091" lat="55.7515407" lon="37.6383137"/>
+ <node id="3755931947" visible="true" version="1" changeset="34206452" timestamp="2015-09-23T13:58:11Z" user="trolleway" uid="397326" lat="55.7517090" lon="37.6407565"/>
+ <way id="25009838" visible="true" version="14" changeset="28090002" timestamp="2015-01-12T16:15:21Z" user="midrug" uid="2417727">
+ <nd ref="271892030"/>
+ <nd ref="271892031"/>
+ <nd ref="271892032"/>
+ <nd ref="666179544"/>
+ <nd ref="666179548"/>
+ <nd ref="666179545"/>
+ <nd ref="666179542"/>
+ <nd ref="271892033"/>
+ <nd ref="271892034"/>
+ <nd ref="271892035"/>
+ <nd ref="271892036"/>
+ <nd ref="271892037"/>
+ <nd ref="271892038"/>
+ <nd ref="271892039"/>
+ <nd ref="271892040"/>
+ <nd ref="271892041"/>
+ <nd ref="271892030"/>
+ <tag k="addr:housenumber" v="12-14"/>
+ <tag k="addr:street" v="улица Солянка"/>
+ <tag k="building" v="yes"/>
+ <tag k="building:colour" v="lightpink"/>
+ <tag k="building:levels" v="3"/>
+ <tag k="description:en" v="Housed the Board of Trustees, a public institution of the Russian Empire until 1917"/>
+ <tag k="end_date" v="1826"/>
+ <tag k="name" v="Опекунский совет"/>
+ <tag k="name:de" v="Kuratorium"/>
+ <tag k="name:en" v="Board of Trustees Building"/>
+ <tag k="ref" v="7710784000"/>
+ <tag k="roof:material" v="metal"/>
+ <tag k="source:description:en" v="wikipedia:ru"/>
+ <tag k="start_date" v="1823"/>
+ <tag k="tourism" v="attraction"/>
+ <tag k="wikipedia" v="ru:Опекунский совет (Москва)"/>
+ </way>
+ <way id="45814282" visible="true" version="3" changeset="4128036" timestamp="2010-03-14T18:31:24Z" user="Vovanium" uid="87682">
+ <nd ref="583193405"/>
+ <nd ref="583193408"/>
+ <nd ref="595699492"/>
+ <nd ref="666179540"/>
+ <nd ref="583193410"/>
+ <nd ref="583193415"/>
+ <nd ref="666179517"/>
+ <nd ref="666179521"/>
+ <nd ref="666179519"/>
+ <nd ref="583193416"/>
+ <nd ref="583193405"/>
+ </way>
+ <way id="109538181" visible="true" version="7" changeset="34206452" timestamp="2015-09-23T13:58:11Z" user="trolleway" uid="397326">
+ <nd ref="338464708"/>
+ <nd ref="338464706"/>
+ <nd ref="2849850613"/>
+ <nd ref="2849850614"/>
+ <nd ref="3712207029"/>
+ <nd ref="3712207030"/>
+ <nd ref="3712207031"/>
+ <nd ref="3712207032"/>
+ <nd ref="3755931947"/>
+ <nd ref="3712207033"/>
+ <nd ref="3712207034"/>
+ <tag k="highway" v="service"/>
+ </way>
+ <way id="45814281" visible="true" version="6" changeset="9583527" timestamp="2011-10-17T16:38:55Z" user="luch86" uid="266092">
+ <nd ref="583193388"/>
+ <nd ref="583193390"/>
+ <nd ref="666179531"/>
+ <nd ref="666179530"/>
+ <nd ref="666179528"/>
+ <nd ref="583193392"/>
+ <nd ref="583193395"/>
+ <nd ref="666179513"/>
+ <nd ref="666179522"/>
+ <nd ref="666179524"/>
+ <nd ref="666179526"/>
+ <nd ref="583193398"/>
+ <nd ref="583193401"/>
+ <nd ref="583193388"/>
+ </way>
+ <way id="45814283" visible="true" version="3" changeset="28090002" timestamp="2015-01-12T16:15:23Z" user="midrug" uid="2417727">
+ <nd ref="583193422"/>
+ <nd ref="583193424"/>
+ <nd ref="583193426"/>
+ <nd ref="583193429"/>
+ <nd ref="583193431"/>
+ <nd ref="583193432"/>
+ <nd ref="583193422"/>
+ <tag k="addr:street" v="улица Солянка"/>
+ <tag k="building" v="yes"/>
+ <tag k="building:colour" v="goldenrod"/>
+ <tag k="building:levels" v="2"/>
+ <tag k="roof:colour" v="black"/>
+ <tag k="roof:material" v="tar_paper"/>
+ </way>
+ <way id="367274913" visible="true" version="2" changeset="33550484" timestamp="2015-08-24T16:00:25Z" user="vadp" uid="326091">
+ <nd ref="2849850614"/>
+ <nd ref="2849850611"/>
+ <tag k="highway" v="service"/>
+ </way>
+ <relation id="365808" visible="true" version="6" changeset="28090002" timestamp="2015-01-12T16:15:14Z" user="midrug" uid="2417727">
+ <member type="way" ref="45814281" role="outer"/>
+ <member type="way" ref="45814282" role="inner"/>
+ <tag k="addr:housenumber" v="14/2"/>
+ <tag k="addr:street" v="улица Солянка"/>
+ <tag k="building" v="yes"/>
+ <tag k="building:colour" v="gold"/>
+ <tag k="building:levels" v="2"/>
+ <tag k="roof:material" v="metal"/>
+ <tag k="type" v="multipolygon"/>
+ </relation>
+</osm>
+)SEP";
+} // namespace
+
+UNIT_TEST(GetBestOsmNode_Test)
+{
+ {
+ pugi::xml_document osmResponse;
+ TEST(osmResponse.load_buffer(osmRawResponseNode, ::strlen(osmRawResponseNode)), ());
+
+ auto const bestNode = osm::GetBestOsmNode(osmResponse, ms::LatLon(53.8977398, 27.5579251));
+ TEST_EQUAL(editor::XMLFeature(bestNode).GetName(),
+ "Главное управление капитального строительства", ());
+ }
+ {
+ pugi::xml_document osmResponse;
+ TEST(osmResponse.load_buffer(osmRawResponseNode, ::strlen(osmRawResponseNode)), ());
+
+ auto const bestNode = osm::GetBestOsmNode(osmResponse, ms::LatLon(53.8978398, 27.5579251));
+ TEST(bestNode, ());
+ }
+}
+
UNIT_TEST(GetBestOsmWay_Test)
{
{
@@ -99,7 +297,7 @@ UNIT_TEST(GetBestOsmWay_Test)
MercatorBounds::FromLatLon(53.8976041, 27.557518),
};
- auto const bestWay = osm::GetBestOsmWay(osmResponse, geometry);
+ auto const bestWay = osm::GetBestOsmWayOrRelation(osmResponse, geometry);
TEST_EQUAL(editor::XMLFeature(bestWay).GetName(), "Беллесбумпром", ());
}
{
@@ -115,26 +313,42 @@ UNIT_TEST(GetBestOsmWay_Test)
MercatorBounds::FromLatLon(53.8976041, 27.557318), // diff
};
- auto const bestWay = osm::GetBestOsmWay(osmResponse, geometry);
+ auto const bestWay = osm::GetBestOsmWayOrRelation(osmResponse, geometry);
TEST(!bestWay, ());
}
}
-UNIT_TEST(GetBestOsmNode_Test)
+UNIT_TEST(GetBestOsmRealtion_Test)
{
- {
- pugi::xml_document osmResponse;
- TEST(osmResponse.load_buffer(osmRawResponseNode, ::strlen(osmRawResponseNode)), ());
+ pugi::xml_document osmResponse;
+ TEST(osmResponse.load_buffer(osmRawResponseRelation, ::strlen(osmRawResponseRelation)), ());
+ vector<m2::PointD> const geometry = {
+ {37.6400469, 67.4549381},
+ {37.6401059, 67.4546779},
+ {37.6401113, 67.4551473},
+ {37.640181, 67.4545089},
+ {37.6401944, 67.455394},
+ {37.6402534, 67.4553162},
+ {37.6403205, 67.454812},
+ {37.6403205, 67.4549327},
+ {37.640358, 67.4547047},
+ {37.6403768, 67.4550534},
+ {37.6404895, 67.4541736},
+ {37.6405056, 67.4551741},
+ {37.6406343, 67.4540905},
+ {37.6406638, 67.4543909},
+ {37.6406906, 67.4552814},
+ {37.6407496, 67.4557266},
+ {37.6407496, 67.45572},
+ {37.6407872, 67.4540636},
+ {37.6408274, 67.4543211},
+ {37.6409535, 67.4540797},
+ {37.6410018, 67.4543506},
+ {37.6410983, 67.4541522},
+ {37.6412432, 67.454533},
+ {37.6416187, 67.4545411}
+ };
- auto const bestNode = osm::GetBestOsmNode(osmResponse, ms::LatLon(53.8977398, 27.5579251));
- TEST_EQUAL(editor::XMLFeature(bestNode).GetName(),
- "Главное управление капитального строительства", ());
- }
- {
- pugi::xml_document osmResponse;
- TEST(osmResponse.load_buffer(osmRawResponseNode, ::strlen(osmRawResponseNode)), ());
-
- auto const bestNode = osm::GetBestOsmNode(osmResponse, ms::LatLon(53.8978398, 27.5579251));
- TEST(bestNode, ());
- }
+ auto const bestWay = osm::GetBestOsmWayOrRelation(osmResponse, geometry);
+ TEST_EQUAL(bestWay.attribute("id").value(), string("365808"), ());
}
diff --git a/editor/osm_feature_matcher.cpp b/editor/osm_feature_matcher.cpp
index 1605a85729..fac7dc7305 100644
--- a/editor/osm_feature_matcher.cpp
+++ b/editor/osm_feature_matcher.cpp
@@ -1,13 +1,16 @@
#include "editor/osm_feature_matcher.hpp"
#include "base/logging.hpp"
+#include "base/stl_helpers.hpp"
#include "std/algorithm.hpp"
using editor::XMLFeature;
-namespace
+namespace osm
{
+using editor::XMLFeature;
+
constexpr double kPointDiffEps = MercatorBounds::GetCellID2PointAbsEpsilon();
bool PointsEqual(m2::PointD const & a, m2::PointD const & b)
@@ -38,6 +41,22 @@ void ForEachWaysNode(pugi::xml_document const & osmResponse, pugi::xml_node cons
}
}
+template <typename TFunc>
+void ForEachRelationsNode(pugi::xml_document const & osmResponse, pugi::xml_node const & relation,
+ TFunc && func)
+{
+ for (auto const xNodeRef : relation.select_nodes("member[@type='way']/@ref"))
+ {
+ string const wayRef = xNodeRef.attribute().value();
+ auto const xpath = "osm/way[@id='" + wayRef + "']";
+ auto const way = osmResponse.select_node(xpath.data()).node();
+ // Some ways can be missed from relation.
+ if (!way)
+ continue;
+ ForEachWaysNode(osmResponse, way, forward<TFunc>(func));
+ }
+}
+
vector<m2::PointD> GetWaysGeometry(pugi::xml_document const & osmResponse,
pugi::xml_node const & way)
{
@@ -49,54 +68,77 @@ vector<m2::PointD> GetWaysGeometry(pugi::xml_document const & osmResponse,
return result;
}
+vector<m2::PointD> GetRelationsGeometry(pugi::xml_document const & osmResponse,
+ pugi::xml_node const & relation)
+{
+ vector<m2::PointD> result;
+ ForEachRelationsNode(osmResponse, relation, [&result](XMLFeature const & xmlFt)
+ {
+ result.push_back(xmlFt.GetMercatorCenter());
+ });
+ return result;
+}
+
+// TODO(mgsergio): XMLFeature should have GetGeometry method.
+vector<m2::PointD> GetWaysOrRelationsGeometry(pugi::xml_document const & osmResponse,
+ pugi::xml_node const & wayOrRelation)
+{
+ if (strcmp(wayOrRelation.name(), "way") == 0)
+ return GetWaysGeometry(osmResponse, wayOrRelation);
+ return GetRelationsGeometry(osmResponse, wayOrRelation);
+}
+
/// @returns value form [-0.5, 0.5]. Negative values are used as penalty,
/// positive as score.
-double ScoreGeometry(pugi::xml_document const & osmResponse, pugi::xml_node const & way,
- vector<m2::PointD> geometry)
+/// @param osmResponse - nodes, ways and relations from osm
+/// @param wayOrRelation - either way or relation to be compared agains ourGeometry
+/// @param outGeometry - geometry of a FeatureType (ourGeometry must be sort-uniqued)
+double ScoreGeometry(pugi::xml_document const & osmResponse,
+ pugi::xml_node const & wayOrRelation, vector<m2::PointD> ourGeometry)
{
+ ASSERT(!ourGeometry.empty(), ("Our geometry cannot be empty"));
int matched = 0;
- auto wayGeometry = GetWaysGeometry(osmResponse, way);
+ auto theirGeometry = GetWaysOrRelationsGeometry(osmResponse, wayOrRelation);
+
+ if (theirGeometry.empty())
+ return -1;
- sort(begin(wayGeometry), end(wayGeometry));
- sort(begin(geometry), end(geometry));
+ my::SortUnique(theirGeometry);
- auto it1 = begin(geometry);
- auto it2 = begin(wayGeometry);
+ auto ourIt = begin(ourGeometry);
+ auto theirIt = begin(theirGeometry);
- while (it1 != end(geometry) && it2 != end(wayGeometry))
+ while (ourIt != end(ourGeometry) && theirIt != end(theirGeometry))
{
- if (PointsEqual(*it1, *it2))
+ if (PointsEqual(*ourIt, *theirIt))
{
++matched;
- ++it1;
- ++it2;
+ ++ourIt;
+ ++theirIt;
}
- else if (*it1 < *it2)
+ else if (*ourIt < *theirIt)
{
- ++it1;
+ ++ourIt;
}
else
{
- ++it2;
+ ++theirIt;
}
}
- auto const wayScore = static_cast<double>(matched) / wayGeometry.size() - 0.5;
- auto const geomScore = static_cast<double>(matched) / geometry.size() - 0.5;
+ auto const wayScore = static_cast<double>(matched) / theirGeometry.size() - 0.5;
+ auto const geomScore = static_cast<double>(matched) / ourGeometry.size() - 0.5;
auto const result = wayScore <= 0 || geomScore <= 0
? -1
: 2 / (1 / wayScore + 1 / geomScore);
- LOG(LDEBUG, ("Osm score:", wayScore, "our feature score:", geomScore,
- "Total score", result));
+ LOG(LDEBUG, ("Type:", wayOrRelation.name(), "Osm score:",
+ wayScore, "our feature score:", geomScore, "Total score", result));
return result;
}
-} // namespace
-namespace osm
-{
pugi::xml_node GetBestOsmNode(pugi::xml_document const & osmResponse, ms::LatLon const & latLon)
{
double bestScore = -1;
@@ -132,23 +174,23 @@ pugi::xml_node GetBestOsmNode(pugi::xml_document const & osmResponse, ms::LatLon
return bestMatchNode;
}
-pugi::xml_node GetBestOsmWay(pugi::xml_document const & osmResponse,
- vector<m2::PointD> const & geometry)
+pugi::xml_node GetBestOsmWayOrRelation(pugi::xml_document const & osmResponse,
+ vector<m2::PointD> const & geometry)
{
double bestScore = -1;
pugi::xml_node bestMatchWay;
- // TODO(mgsergio): Handle relations as well. Put try_later=version status to edits.xml.
- for (auto const & xWay : osmResponse.select_nodes("osm/way"))
+ auto const xpath = "osm/way|osm/relation[tag[@k='type' and @v='multipolygon']]";
+ for (auto const & xWayOrRelation : osmResponse.select_nodes(xpath))
{
- double const nodeScore = ScoreGeometry(osmResponse, xWay.node(), geometry);
+ double const nodeScore = ScoreGeometry(osmResponse, xWayOrRelation.node(), geometry);
if (nodeScore < 0)
continue;
if (bestScore < nodeScore)
{
bestScore = nodeScore;
- bestMatchWay = xWay.node();
+ bestMatchWay = xWayOrRelation.node();
}
}
diff --git a/editor/osm_feature_matcher.hpp b/editor/osm_feature_matcher.hpp
index 0c1f05e7bb..2d3947317f 100644
--- a/editor/osm_feature_matcher.hpp
+++ b/editor/osm_feature_matcher.hpp
@@ -12,6 +12,6 @@ namespace osm
/// @returns closest to the latLon node from osm or empty node if none is close enough.
pugi::xml_node GetBestOsmNode(pugi::xml_document const & osmResponse, ms::LatLon const & latLon);
/// @returns a way from osm with similar geometry or empy node if can't find such way.
-pugi::xml_node GetBestOsmWay(pugi::xml_document const & osmResponse,
- vector<m2::PointD> const & geometry);
+pugi::xml_node GetBestOsmWayOrRelation(pugi::xml_document const & osmResponse,
+ vector<m2::PointD> const & geometry);
} // namespace osm