diff --git a/indexer/feature.cpp b/indexer/feature.cpp index e9682e6813..6d05895b9e 100644 --- a/indexer/feature.cpp +++ b/indexer/feature.cpp @@ -4,6 +4,7 @@ #include "feature_impl.hpp" #include "feature_visibility.hpp" #include "scales.hpp" +#include "geometry_serialization.hpp" #include "../defines.hpp" // just for file extensions @@ -323,16 +324,6 @@ bool FeatureBuilder2::PreSerialize(buffers_holder_t const & data) namespace { - template - void WriteVarUintArray(vector const & v, TSink & sink) - { - size_t const count = v.size(); - ASSERT_GREATER ( count, 0, () ); - - for (size_t i = 0; i < count; ++i) - WriteVarUint(sink, v[i]); - } - template class BitSink { TSink & m_sink; @@ -447,13 +438,13 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, int64_t base) } } - feature::SavePointsSimple(data.m_innerPts, base, sink); + serial::SaveInnerPath(data.m_innerPts, base, sink); } else { // offsets was pushed from high scale index to low reverse(data.m_ptsOffset.begin(), data.m_ptsOffset.end()); - WriteVarUintArray(data.m_ptsOffset, sink); + serial::WriteVarUintArray(data.m_ptsOffset, sink); } } @@ -469,7 +460,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, int64_t base) { // offsets was pushed from high scale index to low reverse(data.m_trgOffset.begin(), data.m_trgOffset.end()); - WriteVarUintArray(data.m_trgOffset, sink); + serial::WriteVarUintArray(data.m_trgOffset, sink); } } } @@ -608,7 +599,6 @@ void FeatureType::Deserialize(read_source_t & src) m_Points.clear(); m_Triangles.clear(); - m_InnerPoints.clear(); m_bHeader2Parsed = m_bPointsParsed = m_bTrianglesParsed = false; m_ptsSimpMask = 0; @@ -807,9 +797,7 @@ void FeatureType::ParseHeader2() const char const * start = static_cast(src.Ptr()); - m_InnerPoints.reserve(ptsCount); - src = ArrayByteSource(ReadVarInt64Array( - src.Ptr(), ptsCount, MakeBackInsertFunctor(m_InnerPoints))); + src = ArrayByteSource(serial::LoadInnerPath(src.Ptr(), ptsCount, m_base, m_Points)); m_InnerStats.m_Points = static_cast(src.Ptr()) - start; } @@ -855,7 +843,7 @@ uint32_t FeatureType::ParseGeometry(int scale) const uint32_t sz = 0; if (Header() & HEADER_IS_LINE) { - if (m_InnerPoints.empty()) + if (m_Points.empty()) { // outer geometry int const ind = GetScaleIndex(scale, m_ptsOffsets); @@ -864,35 +852,32 @@ uint32_t FeatureType::ParseGeometry(int scale) const ReaderSource src( m_cont->GetReader(feature::GetTagForIndex(GEOMETRY_FILE_TAG, ind))); src.Skip(m_ptsOffsets[ind]); - feature::LoadPoints(m_Points, m_base, src); + serial::LoadOuterPath(src, m_base, m_Points); sz = static_cast(src.Pos() - m_ptsOffsets[ind]); } } else { - // inner geometry - size_t const count = m_InnerPoints.size(); - ASSERT_GREATER ( count, 1, () ); + // filter inner geometry - m_Points.reserve(count); + size_t const count = m_Points.size(); + points_t points; + points.reserve(count); uint32_t const scaleIndex = GetScaleIndex(scale); ASSERT_LESS ( scaleIndex, ARRAY_SIZE(feature::g_arrScales), () ); - int64_t id = m_InnerPoints.front() + m_base; - m_Points.push_back(feature::pts::ToPoint(id)); - + points.push_back(m_Points.front()); for (size_t i = 1; i < count-1; ++i) { - id += m_InnerPoints[i]; // check for point visibility in needed scaleIndex if (((m_ptsSimpMask >> (2*(i-1))) & 0x3) <= scaleIndex) - m_Points.push_back(feature::pts::ToPoint(id)); + points.push_back(m_Points[i]); } + points.push_back(m_Points.back()); - id += m_InnerPoints.back(); - m_Points.push_back(feature::pts::ToPoint(id)); + m_Points.swap(points); } CalcRect(m_Points, m_LimitRect); diff --git a/indexer/feature.hpp b/indexer/feature.hpp index 37877cd63e..c598b73b7e 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -461,8 +461,6 @@ private: // (number of points in inner triangle-strips). static const size_t static_buffer = 32; - mutable buffer_vector m_InnerPoints; - typedef buffer_vector points_t; mutable points_t m_Points, m_Triangles; diff --git a/indexer/feature_impl.hpp b/indexer/feature_impl.hpp index ab0ba3e766..4ad60f86e2 100644 --- a/indexer/feature_impl.hpp +++ b/indexer/feature_impl.hpp @@ -7,6 +7,10 @@ #include "../geometry/point2d.hpp" +#include "../std/algorithm.hpp" +#include "../std/iterator.hpp" + + namespace feature { namespace pts diff --git a/indexer/geometry_coding.cpp b/indexer/geometry_coding.cpp index f5dac67a90..d0a8a7e701 100644 --- a/indexer/geometry_coding.cpp +++ b/indexer/geometry_coding.cpp @@ -1,45 +1,22 @@ #include "geometry_coding.hpp" + #include "../../geometry/distance.hpp" -#include "../coding/byte_stream.hpp" + #include "../base/assert.hpp" #include "../base/stl_add.hpp" + #include "../std/complex.hpp" #include "../std/vector.hpp" + namespace { - -inline void EncodeVarUints(vector const & varints, vector & serialOutput) -{ - PushBackByteSink > sink(serialOutput); - for (vector::const_iterator it = varints.begin(); it != varints.end(); ++it) - WriteVarUint(sink, *it); -} - -template -inline m2::PointU ClampPoint(m2::PointU const & maxPoint, m2::Point point) -{ - return m2::PointU( - point.x < 0 ? 0 : (point.x < maxPoint.x ? static_cast(point.x) : maxPoint.x), - point.y < 0 ? 0 : (point.y < maxPoint.y ? static_cast(point.y) : maxPoint.y)); -} - -bool TestDecoding(vector const & points, - m2::PointU const & basePoint, - m2::PointU const & maxPoint, - vector & serialOutput, - void (* fnDecode)(char const * pBeg, char const * pEnd, - m2::PointU const & basePoint, - m2::PointU const & maxPoint, - vector & points)) -{ - vector decoded; - decoded.reserve(points.size()); - fnDecode(&serialOutput[0], &serialOutput[0] + serialOutput.size(), basePoint, maxPoint, decoded); - ASSERT_EQUAL(points, decoded, (basePoint, maxPoint)); - return true; -} - + template + inline m2::PointU ClampPoint(m2::PointU const & maxPoint, m2::Point const & point) + { + return m2::PointU(my::clamp(static_cast(point.x), 0, maxPoint.x), + my::clamp(static_cast(point.y), 0, maxPoint.y)); + } } m2::PointU PredictPointInPolyline(m2::PointU const & maxPoint, @@ -77,12 +54,29 @@ m2::PointU PredictPointInPolyline(m2::PointU const & maxPoint, return ClampPoint(maxPoint, m2::PointD(c0.real(), c0.imag())); } -void EncodePolylinePrev1(vector const & points, +namespace geo_coding +{ + bool TestDecoding(InPointsT const & points, + m2::PointU const & basePoint, + m2::PointU const & maxPoint, + DeltasT const & deltas, + void (* fnDecode)(DeltasT const & deltas, + m2::PointU const & basePoint, + m2::PointU const & maxPoint, + OutPointsT & points)) + { + vector decoded; + decoded.reserve(points.size()); + fnDecode(deltas, basePoint, maxPoint, decoded); + ASSERT_EQUAL(points, decoded, (basePoint, maxPoint)); + return true; + } + +void EncodePolylinePrev1(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & /*maxPoint*/, - vector & serialOutput) + DeltasT & deltas) { - vector deltas; deltas.reserve(points.size()); if (points.size() > 0) { @@ -91,19 +85,14 @@ void EncodePolylinePrev1(vector const & points, deltas.push_back(EncodeDelta(points[i], points[i-1])); } - EncodeVarUints(deltas, serialOutput); - ASSERT(TestDecoding(points, basePoint, m2::PointU(), serialOutput, &DecodePolylinePrev1), ()); + ASSERT(TestDecoding(points, basePoint, m2::PointU(), deltas, &DecodePolylinePrev1), ()); } -void DecodePolylinePrev1(char const * pBeg, char const * pEnd, +void DecodePolylinePrev1(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & /*maxPoint*/, - vector & points) + OutPointsT & points) { - vector deltas; - ReadVarUint64Array(pBeg, pEnd, MakeBackInsertFunctor(deltas)); - points.reserve(points.size() + deltas.size()); - if (deltas.size() > 0) { points.push_back(DecodeDelta(deltas[0], basePoint)); @@ -112,13 +101,11 @@ void DecodePolylinePrev1(char const * pBeg, char const * pEnd, } } -void EncodePolylinePrev2(vector const & points, +void EncodePolylinePrev2(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput) + DeltasT & deltas) { - vector deltas; - deltas.reserve(points.size()); if (points.size() > 0) { deltas.push_back(EncodeDelta(points[0], basePoint)); @@ -131,19 +118,14 @@ void EncodePolylinePrev2(vector const & points, } } - EncodeVarUints(deltas, serialOutput); - ASSERT(TestDecoding(points, basePoint, maxPoint, serialOutput, &DecodePolylinePrev2), ()); + ASSERT(TestDecoding(points, basePoint, maxPoint, deltas, &DecodePolylinePrev2), ()); } -void DecodePolylinePrev2(char const * pBeg, char const * pEnd, +void DecodePolylinePrev2(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & points) + OutPointsT & points) { - vector deltas; - ReadVarUint64Array(pBeg, pEnd, MakeBackInsertFunctor(deltas)); - points.reserve(points.size() + deltas.size()); - if (deltas.size() > 0) { points.push_back(DecodeDelta(deltas[0], basePoint)); @@ -160,17 +142,14 @@ void DecodePolylinePrev2(char const * pBeg, char const * pEnd, } } - -void EncodePolylinePrev3(vector const & points, +void EncodePolylinePrev3(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput) + DeltasT & deltas) { ASSERT_LESS_OR_EQUAL(basePoint.x, maxPoint.x, (basePoint, maxPoint)); ASSERT_LESS_OR_EQUAL(basePoint.y, maxPoint.y, (basePoint, maxPoint)); - vector deltas; - deltas.reserve(points.size()); if (points.size() > 0) { deltas.push_back(EncodeDelta(points[0], basePoint)); @@ -190,22 +169,18 @@ void EncodePolylinePrev3(vector const & points, } } } - EncodeVarUints(deltas, serialOutput); - ASSERT(TestDecoding(points, basePoint, maxPoint, serialOutput, &DecodePolylinePrev3), ()); + + ASSERT(TestDecoding(points, basePoint, maxPoint, deltas, &DecodePolylinePrev3), ()); } -void DecodePolylinePrev3(char const * pBeg, char const * pEnd, +void DecodePolylinePrev3(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & points) + OutPointsT & points) { ASSERT_LESS_OR_EQUAL(basePoint.x, maxPoint.x, (basePoint, maxPoint)); ASSERT_LESS_OR_EQUAL(basePoint.y, maxPoint.y, (basePoint, maxPoint)); - vector deltas; - ReadVarUint64Array(pBeg, pEnd, MakeBackInsertFunctor(deltas)); - points.reserve(points.size() + deltas.size()); - if (deltas.size() > 0) { points.push_back(DecodeDelta(deltas[0], basePoint)); @@ -228,3 +203,5 @@ void DecodePolylinePrev3(char const * pBeg, char const * pEnd, } } } + +} diff --git a/indexer/geometry_coding.hpp b/indexer/geometry_coding.hpp index db81b460a7..746488388a 100644 --- a/indexer/geometry_coding.hpp +++ b/indexer/geometry_coding.hpp @@ -32,51 +32,56 @@ m2::PointU PredictPointInPolyline(m2::PointU const & maxPoint, m2::PointU const & p2, m2::PointU const & p3); +namespace geo_coding +{ + typedef vector InPointsT; + typedef vector OutPointsT; + typedef vector DeltasT; -void EncodePolylinePrev1(vector const & points, +void EncodePolylinePrev1(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput); + DeltasT & deltas); -void DecodePolylinePrev1(char const * pBeg, char const * pEnd, +void DecodePolylinePrev1(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & points); + OutPointsT & points); -void EncodePolylinePrev2(vector const & points, +void EncodePolylinePrev2(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput); + DeltasT & deltas); -void DecodePolylinePrev2(char const * pBeg, char const * pEnd, +void DecodePolylinePrev2(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & points); + OutPointsT & points); -void EncodePolylinePrev3(vector const & points, +void EncodePolylinePrev3(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput); + DeltasT & deltas); -void DecodePolylinePrev3(char const * pBeg, char const * pEnd, +void DecodePolylinePrev3(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & points); + OutPointsT & points); -inline void EncodePolyline(vector const & points, +inline void EncodePolyline(InPointsT const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput) + DeltasT & deltas) { - EncodePolylinePrev3(points, basePoint, maxPoint, serialOutput); + EncodePolylinePrev2(points, basePoint, maxPoint, deltas); } -inline void DecodePolyline(char const * pBeg, char const * pEnd, +inline void DecodePolyline(DeltasT const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & points) + OutPointsT & points) { - DecodePolylinePrev3(pBeg, pEnd, basePoint, maxPoint, points); + DecodePolylinePrev2(deltas, basePoint, maxPoint, points); } void EncodeTriangles(vector const & points, @@ -100,3 +105,4 @@ void DecodeTriangleStrip(char const * pBeg, char const * pEnd, m2::PointU const & basePoint, m2::PointU const & maxPoint, vector & points); +} diff --git a/indexer/geometry_serialization.cpp b/indexer/geometry_serialization.cpp new file mode 100644 index 0000000000..63086a8776 --- /dev/null +++ b/indexer/geometry_serialization.cpp @@ -0,0 +1,69 @@ +#include "geometry_serialization.hpp" +#include "mercator.hpp" +#include "point_to_int64.hpp" +#include "geometry_coding.hpp" + +#include "../geometry/pointu_to_uint64.hpp" + +#include "../std/algorithm.hpp" +#include "../std/iterator.hpp" + + +namespace serial +{ + namespace pts + { + inline m2::PointU D2U(m2::PointD const & p) + { + return PointD2PointU(p.x, p.y); + } + + inline m2::PointD U2D(m2::PointU const & p) + { + CoordPointT const pt = PointU2PointD(p); + return m2::PointD(pt.first, pt.second); + } + + inline m2::PointU GetMaxPoint() + { + return D2U(m2::PointD(MercatorBounds::maxX, MercatorBounds::maxY)); + } + + inline m2::PointU GetBasePoint(int64_t base) + { + return m2::Uint64ToPointU(base); + } + } + + void EncodePath(vector const & points, int64_t base, vector & deltas) + { + vector upoints; + upoints.reserve(points.size()); + + transform(points.begin(), points.end(), back_inserter(upoints), &pts::D2U); + + geo_coding::EncodePolyline(upoints, pts::GetBasePoint(base), pts::GetMaxPoint(), deltas); + } + + void DecodePath(vector const & deltas, int64_t base, OutPointsT & points) + { + vector upoints; + upoints.reserve(deltas.size()); + + geo_coding::DecodePolyline(deltas, pts::GetBasePoint(base), pts::GetMaxPoint(), upoints); + + points.reserve(upoints.size()); + transform(upoints.begin(), upoints.end(), back_inserter(points), &pts::U2D); + } + + void const * LoadInnerPath(void const * pBeg, size_t count, int64_t base, OutPointsT & points) + { + vector deltas; + deltas.reserve(count); + void const * ret = ReadVarUint64Array(static_cast(pBeg), count, + MakeBackInsertFunctor(deltas)); + + DecodePath(deltas, base, points); + return ret; + } +} diff --git a/indexer/geometry_serialization.hpp b/indexer/geometry_serialization.hpp new file mode 100644 index 0000000000..974a3c1b9a --- /dev/null +++ b/indexer/geometry_serialization.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "../geometry/point2d.hpp" + +#include "../coding/writer.hpp" +#include "../coding/varint.hpp" + +#include "../base/buffer_vector.hpp" +#include "../base/stl_add.hpp" + + +namespace serial +{ + template + inline void WriteVarUintArray(vector const & v, TSink & sink) + { + for (size_t i = 0; i != v.size(); ++i) + WriteVarUint(sink, v[i]); + } + + void EncodePath(vector const & points, int64_t base, vector & deltas); + + typedef buffer_vector OutPointsT; + void DecodePath(vector const & deltas, int64_t base, OutPointsT & points); + + template + void SaveInnerPath(vector const & points, int64_t base, TSink & sink) + { + vector deltas; + EncodePath(points, base, deltas); + WriteVarUintArray(deltas, sink); + } + + template + void SaveOuterPath(vector const & points, int64_t base, TSink & sink) + { + vector deltas; + EncodePath(points, base, deltas); + + vector buffer; + MemWriter > writer(buffer); + WriteVarUintArray(deltas, writer); + + uint32_t const count = buffer.size(); + WriteVarUint(sink, count); + sink.Write(&buffer[0], count); + } + + void const * LoadInnerPath(void const * pBeg, size_t count, int64_t base, OutPointsT & points); + + template + void LoadOuterPath(TSource & src, int64_t base, OutPointsT & points) + { + uint32_t const count = ReadVarUint(src); + vector buffer(count); + char * p = &buffer[0]; + src.Read(p, count); + + vector deltas; + deltas.reserve(count / 2); + ReadVarUint64Array(p, p + count, MakeBackInsertFunctor(deltas)); + + DecodePath(deltas, base, points); + } +} diff --git a/indexer/indexer.pro b/indexer/indexer.pro index 00ffdad6e4..a9a929c265 100644 --- a/indexer/indexer.pro +++ b/indexer/indexer.pro @@ -39,6 +39,7 @@ SOURCES += \ data_header.cpp \ data_header_reader.cpp \ geometry_coding.cpp \ + geometry_serialization.cpp HEADERS += \ feature.hpp \ @@ -70,3 +71,5 @@ HEADERS += \ tree_structure.hpp \ feature_impl.hpp \ geometry_coding.hpp \ + geometry_serialization.hpp \ + point_to_int64.hpp diff --git a/indexer/indexer_tests/geometry_coding_test.cpp b/indexer/indexer_tests/geometry_coding_test.cpp index fd814d5b50..034a4abe55 100644 --- a/indexer/indexer_tests/geometry_coding_test.cpp +++ b/indexer/indexer_tests/geometry_coding_test.cpp @@ -1,12 +1,17 @@ #include "../geometry_coding.hpp" #include "../../testing/testing.hpp" + #include "../../geometry/geometry_tests/large_polygon.hpp" #include "../../geometry/distance.hpp" #include "../../geometry/simplification.hpp" + #include "../../coding/byte_stream.hpp" #include "../../coding/varint.hpp" +#include "../../coding/writer.hpp" + #include "../../base/logging.hpp" + typedef m2::PointU PU; UNIT_TEST(EncodeDelta) @@ -31,13 +36,15 @@ UNIT_TEST(EncodeDelta) UNIT_TEST(PredictPointsInPolyline2) { - TEST_EQUAL(PU(7, 6), PredictPointInPolyline(PU(8, 7), PU(4, 4), PU(1, 2)), ()); + // Ci = Ci-1 + (Ci-1 + Ci-2) / 2 + TEST_EQUAL(PU(5, 5), PredictPointInPolyline(PU(8, 7), PU(4, 4), PU(1, 2)), ()); } UNIT_TEST(PredictPointsInPolyline2_ClampMax) { - TEST_EQUAL(PU(6, 6), PredictPointInPolyline(PU(6, 7), PU(4, 4), PU(1, 2)), ()); - TEST_EQUAL(PU(7, 6), PredictPointInPolyline(PU(8, 7), PU(4, 4), PU(1, 2)), ()); + // Ci = Ci-1 + (Ci-1 + Ci-2) / 2 + TEST_EQUAL(PU(4, 4), PredictPointInPolyline(PU(4, 4), PU(4, 4), PU(1, 2)), ()); + TEST_EQUAL(PU(5, 5), PredictPointInPolyline(PU(8, 7), PU(4, 4), PU(1, 2)), ()); TEST_EQUAL(PU(5, 5), PredictPointInPolyline(PU(5, 5), PU(4, 4), PU(1, 2)), ()); } @@ -46,6 +53,7 @@ UNIT_TEST(PredictPointsInPolyline2_Clamp0) TEST_EQUAL(PU(4, 0), PredictPointInPolyline(PU(5, 5), PU(4, 1), PU(4, 4)), ()); } +/* UNIT_TEST(PredictPointsInPolyline3_Square) { TEST_EQUAL(PU(5, 1), PredictPointInPolyline(PU(6, 6), PU(5, 4), PU(2, 4), PU(2, 1)), ()); @@ -62,6 +70,7 @@ UNIT_TEST(PredictPointsInPolyline3_90deg) { TEST_EQUAL(PU(3, 2), PredictPointInPolyline(PU(8, 8), PU(3, 6), PU(1, 6), PU(1, 5)), ()); } +*/ namespace { @@ -72,22 +81,32 @@ void TestPolylineEncode(string testName, void (* fnEncode)(vector const & points, m2::PointU const & basePoint, m2::PointU const & maxPoint, - vector & serialOutput), - void (* fnDecode)(char const * pBeg, char const * pEnd, + vector & deltas), + void (* fnDecode)(vector const & deltas, m2::PointU const & basePoint, m2::PointU const & maxPoint, vector & points)) { m2::PointU const basePoint = (points.empty() ? m2::PointU(0, 0) : points[points.size() / 2]); - vector data; - fnEncode(points, basePoint, maxPoint, data); + + vector deltas; + fnEncode(points, basePoint, maxPoint, deltas); + vector decodedPoints; - // TODO: push_back - fnDecode(&data[0], &data[0] + data.size(), basePoint, maxPoint, decodedPoints); + fnDecode(deltas, basePoint, maxPoint, decodedPoints); + TEST_EQUAL(points, decodedPoints, ()); if (points.size() > 10) + { + vector data; + MemWriter > writer(data); + + for (size_t i = 0; i != deltas.size(); ++i) + WriteVarUint(writer, deltas[i]); + LOG(LINFO, (testName, points.size(), data.size())); + } } vector SimplifyPoints(vector const & points, double eps) @@ -101,6 +120,8 @@ vector SimplifyPoints(vector const & points, double eps) void TestEncodePolyline(string name, m2::PointU maxPoint, vector const & points) { + using namespace geo_coding; + TestPolylineEncode(name + "1", points, maxPoint, &EncodePolylinePrev1, &DecodePolylinePrev1); TestPolylineEncode(name + "2", points, maxPoint, &EncodePolylinePrev2, &DecodePolylinePrev2); TestPolylineEncode(name + "3", points, maxPoint, &EncodePolylinePrev3, &DecodePolylinePrev3); diff --git a/indexer/indexer_tool/feature_sorter.cpp b/indexer/indexer_tool/feature_sorter.cpp index a0dc6dfd89..09a9ab7d97 100644 --- a/indexer/indexer_tool/feature_sorter.cpp +++ b/indexer/indexer_tool/feature_sorter.cpp @@ -8,6 +8,7 @@ #include "../../indexer/feature_visibility.hpp" #include "../../indexer/feature_impl.hpp" #include "../../indexer/cell_id.hpp" +#include "../../indexer/geometry_serialization.hpp" #include "../../geometry/polygon.hpp" #include "../../geometry/tesselator.hpp" @@ -153,7 +154,7 @@ namespace feature { m_buffer.m_ptsMask |= (1 << i); m_buffer.m_ptsOffset.push_back(m_rMain.GetFileSize(*m_rMain.m_geoFile[i])); - feature::SavePoints(points, m_base, *m_rMain.m_geoFile[i]); + serial::SaveOuterPath(points, m_base, *m_rMain.m_geoFile[i]); } void WriteOuterTriangles(points_t const & triangles, int i)