diff options
author | Anatoly Serdtcev <serdtcev@maps.me> | 2019-04-15 16:29:54 +0300 |
---|---|---|
committer | Anatoly Serdtcev <serdtcev@maps.me> | 2019-06-05 18:58:29 +0300 |
commit | d9a1dfc4a86e3557e6b7a03a962261ecba45d605 (patch) | |
tree | 120ab2d62384b875d0013432b624eeffce930f46 /generator | |
parent | d07cd2dd15214ba77c6e25783184e7b5c553f31e (diff) |
[generator:geo_objetcs] Add street bbox and center
Diffstat (limited to 'generator')
-rw-r--r-- | generator/CMakeLists.txt | 2 | ||||
-rw-r--r-- | generator/boost_helpers.hpp | 3 | ||||
-rw-r--r-- | generator/generator_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | generator/generator_tests/street_geometry_tests.cpp | 31 | ||||
-rw-r--r-- | generator/streets/street_geometry.cpp | 334 | ||||
-rw-r--r-- | generator/streets/street_geometry.hpp | 125 | ||||
-rw-r--r-- | generator/streets/streets_builder.cpp | 67 | ||||
-rw-r--r-- | generator/streets/streets_builder.hpp | 16 |
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; |