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
diff options
context:
space:
mode:
authorAnatoly Serdtcev <serdtcev@maps.me>2019-04-15 16:29:54 +0300
committerAnatoly Serdtcev <serdtcev@maps.me>2019-06-05 18:58:29 +0300
commitd9a1dfc4a86e3557e6b7a03a962261ecba45d605 (patch)
tree120ab2d62384b875d0013432b624eeffce930f46 /generator
parentd07cd2dd15214ba77c6e25783184e7b5c553f31e (diff)
[generator:geo_objetcs] Add street bbox and center
Diffstat (limited to 'generator')
-rw-r--r--generator/CMakeLists.txt2
-rw-r--r--generator/boost_helpers.hpp3
-rw-r--r--generator/generator_tests/CMakeLists.txt1
-rw-r--r--generator/generator_tests/street_geometry_tests.cpp31
-rw-r--r--generator/streets/street_geometry.cpp334
-rw-r--r--generator/streets/street_geometry.hpp125
-rw-r--r--generator/streets/streets_builder.cpp67
-rw-r--r--generator/streets/streets_builder.hpp16
8 files changed, 551 insertions, 28 deletions
diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt
index 006ba41c65..ef398f1541 100644
--- a/generator/CMakeLists.txt
+++ b/generator/CMakeLists.txt
@@ -191,6 +191,8 @@ set(SRC
srtm_parser.hpp
statistics.cpp
statistics.hpp
+ streets/street_geometry.cpp
+ streets/street_geometry.hpp
streets/streets.cpp
streets/streets.hpp
streets/streets_builder.cpp
diff --git a/generator/boost_helpers.hpp b/generator/boost_helpers.hpp
index c8c7ad2777..373e449d52 100644
--- a/generator/boost_helpers.hpp
+++ b/generator/boost_helpers.hpp
@@ -10,6 +10,9 @@ namespace generator
{
namespace boost_helpers
{
+using BoostPoint = boost::geometry::model::point<double, 2, boost::geometry::cs::cartesian>;
+using BoostPolygon = boost::geometry::model::polygon<BoostPoint>;
+
template <typename BoostPoint, typename BoostGeometry, typename FbGeometry>
void FillBoostGeometry(BoostGeometry & geometry, FbGeometry const & fbGeometry)
{
diff --git a/generator/generator_tests/CMakeLists.txt b/generator/generator_tests/CMakeLists.txt
index 95d5a939b5..ac72beef87 100644
--- a/generator/generator_tests/CMakeLists.txt
+++ b/generator/generator_tests/CMakeLists.txt
@@ -34,6 +34,7 @@ set(
speed_cameras_test.cpp
sponsored_storage_tests.cpp
srtm_parser_test.cpp
+ street_geometry_tests.cpp
tag_admixer_test.cpp
tesselator_test.cpp
triangles_tree_coding_test.cpp
diff --git a/generator/generator_tests/street_geometry_tests.cpp b/generator/generator_tests/street_geometry_tests.cpp
new file mode 100644
index 0000000000..b5155ecb1e
--- /dev/null
+++ b/generator/generator_tests/street_geometry_tests.cpp
@@ -0,0 +1,31 @@
+#include "testing/testing.hpp"
+
+#include "generator/streets/street_geometry.hpp"
+
+#include "geometry/point2d.hpp"
+
+using namespace generator::streets;
+
+UNIT_TEST(HighwayGeometryTest_PinAtSingleLineCenter)
+{
+ HighwayGeometry highway{};
+ highway.AddLine(base::MakeOsmWay(1), {{0.0, 0.0}, {1.0, 1.0}});
+
+ auto pin = highway.ChoosePin();
+ TEST_EQUAL(pin.m_osmId, base::MakeOsmWay(1), ());
+ TEST(m2::AlmostEqualAbs(pin.m_position, {0.5, 0.5}, 0.001), ());
+}
+
+UNIT_TEST(HighwayGeometryTest_PinAtHalfWaySegmentCenter)
+{
+ HighwayGeometry highway{};
+ highway.AddLine(base::MakeOsmWay(1), {{0.0, 0.0}, {1.0, 0.0}});
+ highway.AddLine(base::MakeOsmWay(3), {{1.5, 0.5}, {2.0, 0.5}});
+ highway.AddLine(base::MakeOsmWay(5), {{2.5, 0.0}, {3.8, 0.0}});
+ highway.AddLine(base::MakeOsmWay(2), {{1.0, 0.0}, {1.5, 0.5}});
+ highway.AddLine(base::MakeOsmWay(4), {{2.0, 0.5}, {2.5, 0.0}});
+
+ auto pin = highway.ChoosePin();
+ TEST_EQUAL(pin.m_osmId, base::MakeOsmWay(3), ());
+ TEST(m2::AlmostEqualAbs(pin.m_position, {1.75, 0.5}, 0.001), ());
+}
diff --git a/generator/streets/street_geometry.cpp b/generator/streets/street_geometry.cpp
new file mode 100644
index 0000000000..35ee8cc055
--- /dev/null
+++ b/generator/streets/street_geometry.cpp
@@ -0,0 +1,334 @@
+#include "generator/streets/street_geometry.hpp"
+
+#include "generator/boost_helpers.hpp"
+
+#include "indexer/feature_algo.hpp"
+
+#include "geometry/mercator.hpp"
+
+#include "base/exception.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <utility>
+
+#include <boost/geometry.hpp>
+
+namespace generator
+{
+namespace streets
+{
+Pin StreetGeometry::GetOrChoosePin() const
+{
+ if (m_pin)
+ return *m_pin;
+
+ if (m_highwayGeometry)
+ return m_highwayGeometry->ChoosePin();
+
+ if (m_bindingsGeometry)
+ return m_bindingsGeometry->GetCentralBinding();
+
+ UNREACHABLE();
+}
+
+m2::RectD StreetGeometry::GetBbox() const
+{
+ if (m_highwayGeometry)
+ return m_highwayGeometry->GetBbox();
+
+ if (m_bindingsGeometry)
+ return m_bindingsGeometry->GetBbox();
+
+ if (m_pin)
+ return {m_pin->m_position, m_pin->m_position};
+
+ UNREACHABLE();
+}
+
+void StreetGeometry::SetPin(Pin && pin)
+{
+ m_pin = std::move(pin);
+}
+
+void StreetGeometry::AddHighwayLine(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & line)
+{
+ if (!m_highwayGeometry)
+ m_highwayGeometry = std::make_unique<HighwayGeometry>();
+
+ m_highwayGeometry->AddLine(osmId, line);
+}
+
+void StreetGeometry::AddHighwayArea(base::GeoObjectId const osmId, std::vector<m2::PointD> const & border)
+{
+ if (!m_highwayGeometry)
+ m_highwayGeometry = std::make_unique<HighwayGeometry>();
+
+ m_highwayGeometry->AddArea(osmId, border);
+}
+
+void StreetGeometry::AddBinding(base::GeoObjectId const & osmId, m2::PointD const & point)
+{
+ if (!m_bindingsGeometry)
+ m_bindingsGeometry = std::make_unique<BindingsGeometry>();
+
+ m_bindingsGeometry->Add(osmId, point);
+}
+
+// HighwayGeometry -------------------------------------------------------------------------------------------
+
+Pin HighwayGeometry::ChoosePin() const
+{
+ if (!m_areaParts.empty())
+ return ChooseAreaPin();
+
+ return ChooseMultilinePin();
+}
+
+Pin HighwayGeometry::ChooseMultilinePin() const
+{
+ auto const & lines = m_multiLine.m_lines;
+ CHECK(!lines.empty(), ());
+ auto longestLine = lines.cbegin();
+ auto longestLineLength = longestLine->CalculateLength();
+ for (auto l = std::next(longestLine), end = lines.cend(); l != end; ++l)
+ {
+ auto const length = l->CalculateLength();
+ if (longestLineLength < length)
+ {
+ longestLine = l;
+ longestLineLength = length;
+ }
+ }
+
+ return ChooseLinePin(*longestLine, longestLineLength / 2);
+}
+
+Pin HighwayGeometry::ChooseLinePin(Line const & line, double disposeDistance) const
+{
+ double length = 0.0;
+
+ for (auto const & segment : line.m_segments)
+ {
+ auto const & points = segment.m_points;
+ CHECK_GREATER_OR_EQUAL(points.size(), 2, ());
+ for (auto p = points.cbegin(), end = std::prev(points.cend()); p != end; ++p)
+ {
+ auto const & p1 = *p;
+ auto const & p2 = *std::next(p);
+ length += MercatorBounds::DistanceOnEarth(p1, p2);
+ if (disposeDistance < length)
+ return {p1.Mid(p2), segment.m_osmId};
+ }
+ }
+
+ UNREACHABLE();
+}
+
+Pin HighwayGeometry::ChooseAreaPin() const
+{
+ CHECK(!m_areaParts.empty(), ());
+ auto const largestPart = std::max_element(m_areaParts.cbegin(), m_areaParts.cend(),
+ base::LessBy(&AreaPart::m_area));
+ return {largestPart->m_center, largestPart->m_osmId};
+}
+
+void HighwayGeometry::AddLine(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & line)
+{
+ m_multiLine.Add({osmId, line});
+ ExtendLimitRect(line);
+}
+
+void HighwayGeometry::AddArea(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & border)
+{
+ m_areaParts.emplace_back(osmId, border);
+ ExtendLimitRect(border);
+}
+
+m2::RectD const & HighwayGeometry::GetBbox() const
+{
+ return m_limitRect;
+}
+
+void HighwayGeometry::ExtendLimitRect(std::vector<m2::PointD> const & points)
+{
+ feature::CalcRect(points, m_limitRect);
+}
+
+// HighwayGeometry::MultiLine --------------------------------------------------------------------------------
+
+void HighwayGeometry::MultiLine::Add(LineSegment && segment)
+{
+ for (auto line = m_lines.begin(), end = m_lines.end(); line != end; ++line)
+ {
+ if (line->Add(std::move(segment)))
+ {
+ if (Recombine(std::move(*line)))
+ m_lines.erase(line);
+ return;
+ }
+ }
+
+ m_lines.emplace_back(Line{{std::move(segment)}});
+}
+
+bool HighwayGeometry::MultiLine::Recombine(Line && line)
+{
+ for (auto & l : m_lines)
+ {
+ if (l.Concatenate(std::move(line)))
+ return true;
+ }
+
+ return false;
+}
+
+// HighwayGeometry::Line -------------------------------------------------------------------------------------
+
+bool HighwayGeometry::Line::Concatenate(Line && line)
+{
+ auto const initialSize = line.m_segments.size();
+
+ while (!line.m_segments.empty() && Add(std::move(line.m_segments.front())))
+ line.m_segments.pop_front();
+ CHECK(line.m_segments.empty() || line.m_segments.size() == initialSize, ());
+
+ while (!line.m_segments.empty() && Add(std::move(line.m_segments.back())))
+ line.m_segments.pop_back();
+ CHECK(line.m_segments.empty() || line.m_segments.size() == initialSize, ());
+
+ return line.m_segments.empty();
+}
+
+bool HighwayGeometry::Line::Add(LineSegment && segment)
+{
+ CHECK(!m_segments.empty(), ());
+ auto const & startSegment = m_segments.front();
+ auto const & endSegment = m_segments.back();
+ CHECK(!startSegment.m_points.empty(), ());
+ auto const & lineStart = startSegment.m_points.front();
+ CHECK(!endSegment.m_points.empty(), ());
+ auto const & lineEnd = endSegment.m_points.back();
+
+ // Ignore self-addition.
+ if (startSegment.m_osmId == segment.m_osmId || endSegment.m_osmId == segment.m_osmId)
+ return false;
+
+ CHECK(!segment.m_points.empty(), ());
+ auto const & segmentStart = segment.m_points.front();
+ auto const & segmentEnd = segment.m_points.back();
+
+ if (lineEnd == segmentStart)
+ {
+ m_segments.push_back(std::move(segment));
+ return true;
+ }
+
+ if (lineEnd == segmentEnd)
+ {
+ std::reverse(segment.m_points.begin(), segment.m_points.end());
+ m_segments.push_back(std::move(segment));
+ return true;
+ }
+
+ if (lineStart == segmentEnd)
+ {
+ m_segments.push_front(std::move(segment));
+ return true;
+ }
+
+ if (lineStart == segmentStart)
+ {
+ std::reverse(segment.m_points.begin(), segment.m_points.end());
+ m_segments.push_front(std::move(segment));
+ return true;
+ }
+
+ return false;
+}
+
+double HighwayGeometry::Line::CalculateLength() const noexcept
+{
+ double length = 0.0;
+ for (auto const & segment : m_segments)
+ length += segment.CalculateLength();
+ return length;
+}
+
+// HighwayGeometry::LineSegment ------------------------------------------------------------------------------
+
+HighwayGeometry::LineSegment::LineSegment(base::GeoObjectId const & osmId,
+ std::vector<m2::PointD> const & points)
+ : m_osmId{osmId}, m_points{points}
+{
+ CHECK_GREATER_OR_EQUAL(m_points.size(), 2, ());
+}
+
+double HighwayGeometry::LineSegment::CalculateLength() const noexcept
+{
+ if (m_points.size() < 2)
+ return 0.0;
+
+ double length = 0.0;
+ for (auto p1 = m_points.cbegin(), p2 = std::next(p1); p2 != m_points.cend(); p1 = p2, ++p2)
+ length += MercatorBounds::DistanceOnEarth(*p1, *p2);
+
+ return length;
+}
+
+// HighwayGeometry::AreaPart ---------------------------------------------------------------------------------
+
+HighwayGeometry::AreaPart::AreaPart(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & polygon)
+ : m_osmId{osmId}
+{
+ CHECK_GREATER_OR_EQUAL(polygon.size(), 3, ());
+
+ auto boostPolygon = boost_helpers::BoostPolygon{};
+ for (auto const & p : polygon)
+ boost::geometry::append(boostPolygon, boost_helpers::BoostPoint{p.x, p.y});
+ boost::geometry::correct(boostPolygon);
+
+ boost_helpers::BoostPoint center;
+ boost::geometry::centroid(boostPolygon, center);
+ m_center = {center.get<0>(), center.get<1>()};
+
+ m_area = boost::geometry::area(boostPolygon);
+}
+
+// BindingsGeometry ------------------------------------------------------------------------------------------
+
+Pin BindingsGeometry::GetCentralBinding() const
+{
+ CHECK(m_centralBinding, ("no bindings"));
+ return *m_centralBinding;
+}
+
+m2::RectD const & BindingsGeometry::GetBbox() const
+{
+ CHECK(m_centralBinding, ("no bindings"));
+ return m_limitRect;
+}
+
+void BindingsGeometry::ExtendLimitRect(m2::PointD const & point)
+{
+ m_limitRect.Add(point);
+}
+
+void BindingsGeometry::Add(base::GeoObjectId const & osmId, m2::PointD const & point)
+{
+ ExtendLimitRect(point);
+
+ if (!m_centralBinding)
+ {
+ m_centralBinding = Pin{point, osmId};
+ return;
+ }
+
+ auto const bboxCenter = GetBbox().Center();
+ auto const centralBindingDistance = MercatorBounds::DistanceOnEarth(m_centralBinding->m_position, bboxCenter);
+ auto const pointDistance = MercatorBounds::DistanceOnEarth(point, bboxCenter);
+ if (pointDistance < centralBindingDistance)
+ m_centralBinding = Pin{point, osmId};
+}
+} // namespace streets
+} // namespace generator
diff --git a/generator/streets/street_geometry.hpp b/generator/streets/street_geometry.hpp
new file mode 100644
index 0000000000..c3749f63a1
--- /dev/null
+++ b/generator/streets/street_geometry.hpp
@@ -0,0 +1,125 @@
+#pragma once
+
+#include "geometry/point2d.hpp"
+#include "geometry/rect2d.hpp"
+
+#include "base/geo_object_id.hpp"
+
+#include <list>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <boost/optional.hpp>
+
+namespace generator
+{
+namespace streets
+{
+// Pin is central position of street on the map.
+struct Pin
+{
+ m2::PointD m_position;
+ base::GeoObjectId m_osmId;
+};
+
+class HighwayGeometry;
+class BindingsGeometry;
+
+class StreetGeometry
+{
+public:
+ Pin GetOrChoosePin() const;
+ // Bbox may be the minimum bounding box with feature type margin.
+ m2::RectD GetBbox() const;
+
+ void SetPin(Pin && pin);
+ void AddHighwayLine(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & line);
+ void AddHighwayArea(base::GeoObjectId const osmId, std::vector<m2::PointD> const & border);
+ // Bindings are buildings or POIs on this street (that is the objects that have this street
+ // in their address).
+ void AddBinding(base::GeoObjectId const & osmId, m2::PointD const & point);
+
+private:
+ boost::optional<Pin> m_pin;
+ std::unique_ptr<HighwayGeometry> m_highwayGeometry;
+ std::unique_ptr<BindingsGeometry> m_bindingsGeometry;
+};
+
+class HighwayGeometry
+{
+public:
+ Pin ChoosePin() const;
+ m2::RectD const & GetBbox() const;
+
+ void AddLine(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & line);
+ void AddArea(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & border);
+
+private:
+ struct LineSegment
+ {
+ LineSegment(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & points);
+
+ double CalculateLength() const noexcept;
+
+ base::GeoObjectId m_osmId;
+ std::vector<m2::PointD> m_points;
+ };
+
+ struct Line
+ {
+ // Try to append |line| to front or to back of |this| line.
+ bool Concatenate(Line && line);
+ // The function does not check addition of line segment to ring line.
+ // Line configuration depends on addition sequences.
+ // |segment| will not modify if the function returns false.
+ bool Add(LineSegment && segment);
+ double CalculateLength() const noexcept;
+
+ std::list<LineSegment> m_segments;
+ };
+
+ struct MultiLine
+ {
+ void Add(LineSegment && lineSegment);
+ // This function tries to concatenate whole |line| to another line in this multiline.
+ bool Recombine(Line && line);
+
+ std::list<Line> m_lines;
+ };
+
+ struct AreaPart
+ {
+ AreaPart(base::GeoObjectId const & osmId, std::vector<m2::PointD> const & polygon);
+
+ base::GeoObjectId m_osmId;
+ m2::PointD m_center;
+ double m_area;
+ };
+
+ Pin ChooseMultilinePin() const;
+ Pin ChooseLinePin(Line const & line, double disposeDistance) const;
+ Pin ChooseAreaPin() const;
+ void ExtendLimitRect(std::vector<m2::PointD> const & points);
+
+ MultiLine m_multiLine; // TODO: cyclic graph
+ std::vector<AreaPart> m_areaParts;
+ m2::RectD m_limitRect;
+};
+
+class BindingsGeometry
+{
+public:
+ Pin GetCentralBinding() const;
+ m2::RectD const & GetBbox() const;
+
+ void Add(base::GeoObjectId const & osmId, m2::PointD const & point);
+
+private:
+ void ExtendLimitRect(m2::PointD const & point);
+
+ boost::optional<Pin> m_centralBinding;
+ m2::RectD m_limitRect;
+};
+} // namespace streets
+} // namespace generator
diff --git a/generator/streets/streets_builder.cpp b/generator/streets/streets_builder.cpp
index 7f5418cad2..a32381d3c2 100644
--- a/generator/streets/streets_builder.cpp
+++ b/generator/streets/streets_builder.cpp
@@ -3,6 +3,8 @@
#include "indexer/classificator.hpp"
#include "indexer/ftypes_matcher.hpp"
+#include "geometry/mercator.hpp"
+
#include "base/logging.hpp"
#include <utility>
@@ -52,12 +54,11 @@ void StreetsBuilder::SaveRegionStreetsKv(std::ostream & streamStreetsKv, uint64_
for (auto const & street : streets)
{
- auto streetId = street.second;
- if (base::GeoObjectId::Type::Invalid == streetId.GetType())
- streetId = NextOsmSurrogateId();
+ auto const & bbox = street.second.GetBbox();
+ auto const & pin = street.second.GetOrChoosePin();
- auto const id = static_cast<int64_t>(streetId.GetEncodedId());
- auto const value = MakeStreetValue(regionId, *regionObject, street.first);
+ auto const id = static_cast<int64_t>(pin.m_osmId.GetEncodedId());
+ auto const value = MakeStreetValue(regionId, *regionObject, street.first, bbox, pin.m_position);
streamStreetsKv << id << " " << value.get() << "\n";
}
}
@@ -68,7 +69,7 @@ void StreetsBuilder::AddStreet(FeatureBuilder & fb)
if (!region)
return;
- InsertStreet(*region, fb.GetName(), fb.GetMostGenericOsmId());
+ InsertStreet(*region, fb);
}
void StreetsBuilder::AddStreetBinding(std::string && streetName, FeatureBuilder & fb)
@@ -77,13 +78,15 @@ void StreetsBuilder::AddStreetBinding(std::string && streetName, FeatureBuilder
if (!region)
return;
- InsertSurrogateStreet(*region, std::move(streetName));
+ InsertStreetBinding(*region, std::move(streetName), fb);
}
boost::optional<KeyValue> StreetsBuilder::FindStreetRegionOwner(FeatureBuilder & fb)
{
if (fb.IsPoint())
- return FindStreetRegionOwner(fb.GetKeyPoint());
+ return FindStreetRegionOwner(fb.GetKeyPoint(), true /* needLocality */);
+ if (fb.IsArea())
+ return FindStreetRegionOwner(fb.GetGeometryCenter(), true /* needLocality */);
auto const & line = fb.GetOuterGeometry();
CHECK_GREATER_OR_EQUAL(line.size(), 2, ());
@@ -103,9 +106,9 @@ boost::optional<KeyValue> StreetsBuilder::FindStreetRegionOwner(FeatureBuilder &
return owner;
}
-boost::optional<KeyValue> StreetsBuilder::FindStreetRegionOwner(m2::PointD const & point)
+boost::optional<KeyValue> StreetsBuilder::FindStreetRegionOwner(m2::PointD const & point, bool needLocality)
{
- auto const isStreetAdministrator = [] (KeyValue const & region) {
+ auto const isStreetAdministrator = [needLocality] (KeyValue const & region) {
auto const && properties = base::GetJSONObligatoryField(*region.second, "properties");
auto const && address = base::GetJSONObligatoryField(properties, "address");
@@ -114,33 +117,43 @@ boost::optional<KeyValue> StreetsBuilder::FindStreetRegionOwner(m2::PointD const
if (base::GetJSONOptionalField(address, "sublocality"))
return false;
+ if (needLocality && !base::GetJSONOptionalField(address, "locality"))
+ return false;
+
return true;
};
return m_regionInfoGetter.FindDeepest(point, isStreetAdministrator);
}
-bool StreetsBuilder::InsertStreet(KeyValue const & region, std::string && streetName, base::GeoObjectId id)
+void StreetsBuilder::InsertStreet(KeyValue const & region, FeatureBuilder & fb)
{
auto & regionStreets = m_regions[region.first];
- auto emplace = regionStreets.emplace(std::move(streetName), id);
-
- if (!emplace.second && base::GeoObjectId::Type::Invalid == emplace.first->second.GetType())
- emplace.first->second = id;
-
- return emplace.second;
+ auto & street = regionStreets[fb.GetName()];
+ auto const osmId = fb.GetMostGenericOsmId();
+
+ if (fb.IsArea())
+ street.AddHighwayArea(osmId, fb.GetOuterGeometry());
+ else if (fb.IsLine())
+ street.AddHighwayLine(osmId, fb.GetOuterGeometry());
+ else
+ street.SetPin({fb.GetKeyPoint(), osmId});
}
-bool StreetsBuilder::InsertSurrogateStreet(KeyValue const & region, std::string && streetName)
+void StreetsBuilder::InsertStreetBinding(KeyValue const & region, std::string && streetName,
+ FeatureBuilder & fb)
{
auto & regionStreets = m_regions[region.first];
- auto emplace = regionStreets.emplace(std::move(streetName), base::GeoObjectId{});
- return emplace.second;
+ auto & street = regionStreets[std::move(streetName)];
+ street.AddBinding(NextOsmSurrogateId(), fb.GetKeyPoint());
}
std::unique_ptr<char, JSONFreeDeleter> StreetsBuilder::MakeStreetValue(
- uint64_t regionId, JsonValue const & regionObject, std::string const & streetName)
+ uint64_t regionId, JsonValue const & regionObject, std::string const & streetName,
+ m2::RectD const & bbox, m2::PointD const & pinPoint)
{
+ auto streetObject = base::NewJSONObject();
+
auto const && regionProperties = base::GetJSONObligatoryField(regionObject, "properties");
auto const && regionAddress = base::GetJSONObligatoryField(regionProperties, "address");
auto address = base::JSONPtr{json_deep_copy(const_cast<json_t *>(regionAddress))};
@@ -150,10 +163,18 @@ std::unique_ptr<char, JSONFreeDeleter> StreetsBuilder::MakeStreetValue(
ToJSONObject(*properties, "address", std::move(address));
ToJSONObject(*properties, "name", streetName);
ToJSONObject(*properties, "pid", regionId);
-
- auto streetObject = base::NewJSONObject();
ToJSONObject(*streetObject, "properties", std::move(properties));
+ auto const & leftBottom = MercatorBounds::ToLatLon(bbox.LeftBottom());
+ auto const & rightTop = MercatorBounds::ToLatLon(bbox.RightTop());
+ auto const & bboxArray = std::vector<double>{
+ leftBottom.m_lat, leftBottom.m_lon, rightTop.m_lat, rightTop.m_lon};
+ ToJSONObject(*streetObject, "bbox", std::move(bboxArray));
+
+ auto const & pinLatLon = MercatorBounds::ToLatLon(pinPoint);
+ auto const & pinArray = std::vector<double>{pinLatLon.m_lat, pinLatLon.m_lon};
+ ToJSONObject(*streetObject, "pin", std::move(pinArray));
+
auto const value = json_dumps(streetObject.get(), JSON_COMPACT);
return std::unique_ptr<char, JSONFreeDeleter>{value};
}
diff --git a/generator/streets/streets_builder.hpp b/generator/streets/streets_builder.hpp
index 66646fe129..065b13f796 100644
--- a/generator/streets/streets_builder.hpp
+++ b/generator/streets/streets_builder.hpp
@@ -4,6 +4,7 @@
#include "generator/key_value_storage.hpp"
#include "generator/osm_element.hpp"
#include "generator/regions/region_info_getter.hpp"
+#include "generator/streets/street_geometry.hpp"
#include "coding/reader.hpp"
@@ -30,13 +31,16 @@ public:
void AssembleStreets(std::string const & pathInStreetsTmpMwm);
void AssembleBindings(std::string const & pathInGeoObjectsTmpMwm);
+ // Save built streets in the jsonl format with the members: "properties", "bbox" (array: left bottom
+ // latitude, left bottom longitude, right top latitude, right top longitude), "pin" (array: latitude,
+ // longitude).
void SaveStreetsKv(std::ostream & streamStreetsKv);
static bool IsStreet(OsmElement const & element);
static bool IsStreet(feature::FeatureBuilder const & fb);
private:
- using RegionStreets = std::unordered_map<std::string, base::GeoObjectId>;
+ using RegionStreets = std::unordered_map<std::string, StreetGeometry>;
void SaveRegionStreetsKv(std::ostream & streamStreetsKv, uint64_t regionId,
RegionStreets const & streets);
@@ -44,11 +48,13 @@ private:
void AddStreet(feature::FeatureBuilder & fb);
void AddStreetBinding(std::string && streetName, feature::FeatureBuilder & fb);
boost::optional<KeyValue> FindStreetRegionOwner(feature::FeatureBuilder & fb);
- boost::optional<KeyValue> FindStreetRegionOwner(m2::PointD const & point);
- bool InsertStreet(KeyValue const & region, std::string && streetName, base::GeoObjectId id);
- bool InsertSurrogateStreet(KeyValue const & region, std::string && streetName);
+ boost::optional<KeyValue> FindStreetRegionOwner(m2::PointD const & point, bool needLocality = false);
+ void InsertStreet(KeyValue const & region, feature::FeatureBuilder & fb);
+ void InsertStreetBinding(KeyValue const & region, std::string && streetName,
+ feature::FeatureBuilder & fb);
std::unique_ptr<char, JSONFreeDeleter> MakeStreetValue(
- uint64_t regionId, JsonValue const & regionObject, std::string const & streetName);
+ uint64_t regionId, JsonValue const & regionObject, std::string const & streetName,
+ m2::RectD const & bbox, m2::PointD const & pinPoint);
base::GeoObjectId NextOsmSurrogateId();
std::unordered_map<uint64_t, RegionStreets> m_regions;