forked from organicmaps/organicmaps-tmp
Add parallelogramm prediction for strips serialization.
This commit is contained in:
parent
6e09c5a8b8
commit
5b533632a6
6 changed files with 169 additions and 99 deletions
|
@ -355,37 +355,6 @@ namespace
|
|||
m_pos += count;
|
||||
}
|
||||
};
|
||||
|
||||
/// @name Rearrange strips for optimal save size.
|
||||
/// Save in this order: 0, 2, 4, ..., 15, 13, ..., 1
|
||||
//@{
|
||||
void RearrangeStripsSave(vector<m2::PointD> const & src, vector<m2::PointD> & dest)
|
||||
{
|
||||
size_t const count = src.size();
|
||||
dest.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (i & 1)
|
||||
dest[count-1 - (i/2)] = src[i];
|
||||
else
|
||||
dest[i/2] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
void RearrangeStripsLoad( buffer_vector<m2::PointD, 32> const & src,
|
||||
buffer_vector<m2::PointD, 32> & dest)
|
||||
{
|
||||
size_t const count = src.size();
|
||||
dest.resize(count);
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
if (i & 1)
|
||||
dest[i] = src[count-1 - (i/2)];
|
||||
else
|
||||
dest[i] = src[i/2];
|
||||
}
|
||||
}
|
||||
//@}
|
||||
}
|
||||
|
||||
void FeatureBuilder2::Serialize(buffers_holder_t & data, int64_t base)
|
||||
|
@ -451,11 +420,7 @@ void FeatureBuilder2::Serialize(buffers_holder_t & data, int64_t base)
|
|||
if (m_bArea)
|
||||
{
|
||||
if (trgCount > 0)
|
||||
{
|
||||
vector<m2::PointD> toSave;
|
||||
RearrangeStripsSave(data.m_innerTrg, toSave);
|
||||
feature::SavePointsSimple(toSave, base, sink);
|
||||
}
|
||||
serial::SaveInnerTriangles(data.m_innerTrg, base, sink);
|
||||
else
|
||||
{
|
||||
// offsets was pushed from high scale index to low
|
||||
|
@ -813,9 +778,8 @@ void FeatureType::ParseHeader2() const
|
|||
|
||||
char const * start = static_cast<char const *>(src.Ptr());
|
||||
|
||||
points_t toLoad, points;
|
||||
ReadInnerPoints(src, toLoad, trgCount);
|
||||
RearrangeStripsLoad(toLoad, points);
|
||||
points_t points;
|
||||
src = ArrayByteSource(serial::LoadInnerTriangles(src.Ptr(), trgCount, m_base, points));
|
||||
|
||||
m_InnerStats.m_Strips = static_cast<char const *>(src.Ptr()) - start;
|
||||
|
||||
|
@ -894,19 +858,23 @@ uint32_t FeatureType::ParseTriangles(int scale) const
|
|||
ParseHeader2();
|
||||
|
||||
uint32_t sz = 0;
|
||||
if (m_Triangles.empty() && Header() & HEADER_IS_AREA)
|
||||
if (Header() & HEADER_IS_AREA)
|
||||
{
|
||||
uint32_t const ind = GetScaleIndex(scale, m_trgOffsets);
|
||||
if (ind != -1)
|
||||
if (m_Triangles.empty())
|
||||
{
|
||||
ReaderSource<FileReader> src(
|
||||
m_cont->GetReader(feature::GetTagForIndex(TRIANGLE_FILE_TAG, ind)));
|
||||
src.Skip(m_trgOffsets[ind]);
|
||||
feature::LoadTriangles(m_Triangles, m_base, src);
|
||||
uint32_t const ind = GetScaleIndex(scale, m_trgOffsets);
|
||||
if (ind != -1)
|
||||
{
|
||||
ReaderSource<FileReader> src(
|
||||
m_cont->GetReader(feature::GetTagForIndex(TRIANGLE_FILE_TAG, ind)));
|
||||
src.Skip(m_trgOffsets[ind]);
|
||||
feature::LoadTriangles(m_Triangles, m_base, src);
|
||||
|
||||
CalcRect(m_Triangles, m_LimitRect);
|
||||
sz = static_cast<uint32_t>(src.Pos() - m_trgOffsets[ind]);
|
||||
sz = static_cast<uint32_t>(src.Pos() - m_trgOffsets[ind]);
|
||||
}
|
||||
}
|
||||
|
||||
CalcRect(m_Triangles, m_LimitRect);
|
||||
}
|
||||
|
||||
m_bTrianglesParsed = true;
|
||||
|
@ -926,12 +894,6 @@ void FeatureType::ReadOffsets(ArrayByteSource & src, uint8_t mask, offsets_t & o
|
|||
}
|
||||
}
|
||||
|
||||
void FeatureType::ReadInnerPoints(ArrayByteSource & src, points_t & points, uint8_t count) const
|
||||
{
|
||||
src = ArrayByteSource(feature::LoadPointsSimple(src.Ptr(), count, m_base, points));
|
||||
CalcRect(points, m_LimitRect);
|
||||
}
|
||||
|
||||
void FeatureType::ParseAll(int scale) const
|
||||
{
|
||||
if (!m_bPointsParsed)
|
||||
|
|
|
@ -475,7 +475,6 @@ private:
|
|||
typedef array<uint32_t, 4> offsets_t; // should be synchronized with ARRAY_SIZE(g_arrScales)
|
||||
|
||||
static void ReadOffsets(ArrayByteSource & src, uint8_t mask, offsets_t & offsets);
|
||||
void ReadInnerPoints(ArrayByteSource & src, points_t & points, uint8_t count) const;
|
||||
|
||||
static int GetScaleIndex(int scale);
|
||||
static int GetScaleIndex(int scale, offsets_t const & offset);
|
||||
|
|
|
@ -77,11 +77,11 @@ void EncodePolylinePrev1(InPointsT const & points,
|
|||
m2::PointU const & /*maxPoint*/,
|
||||
DeltasT & deltas)
|
||||
{
|
||||
deltas.reserve(points.size());
|
||||
if (points.size() > 0)
|
||||
size_t const count = points.size();
|
||||
if (count > 0)
|
||||
{
|
||||
deltas.push_back(EncodeDelta(points[0], basePoint));
|
||||
for (size_t i = 1; i < points.size(); ++i)
|
||||
for (size_t i = 1; i < count; ++i)
|
||||
deltas.push_back(EncodeDelta(points[i], points[i-1]));
|
||||
}
|
||||
|
||||
|
@ -93,10 +93,11 @@ void DecodePolylinePrev1(DeltasT const & deltas,
|
|||
m2::PointU const & /*maxPoint*/,
|
||||
OutPointsT & points)
|
||||
{
|
||||
if (deltas.size() > 0)
|
||||
size_t const count = deltas.size();
|
||||
if (count > 0)
|
||||
{
|
||||
points.push_back(DecodeDelta(deltas[0], basePoint));
|
||||
for (size_t i = 1; i < deltas.size(); ++i)
|
||||
for (size_t i = 1; i < count; ++i)
|
||||
points.push_back(DecodeDelta(deltas[i], points.back()));
|
||||
}
|
||||
}
|
||||
|
@ -106,13 +107,14 @@ void EncodePolylinePrev2(InPointsT const & points,
|
|||
m2::PointU const & maxPoint,
|
||||
DeltasT & deltas)
|
||||
{
|
||||
if (points.size() > 0)
|
||||
size_t const count = points.size();
|
||||
if (count > 0)
|
||||
{
|
||||
deltas.push_back(EncodeDelta(points[0], basePoint));
|
||||
if (points.size() > 1)
|
||||
if (count > 1)
|
||||
{
|
||||
deltas.push_back(EncodeDelta(points[1], points[0]));
|
||||
for (size_t i = 2; i < points.size(); ++i)
|
||||
for (size_t i = 2; i < count; ++i)
|
||||
deltas.push_back(EncodeDelta(points[i],
|
||||
PredictPointInPolyline(maxPoint, points[i-1], points[i-2])));
|
||||
}
|
||||
|
@ -126,13 +128,14 @@ void DecodePolylinePrev2(DeltasT const & deltas,
|
|||
m2::PointU const & maxPoint,
|
||||
OutPointsT & points)
|
||||
{
|
||||
if (deltas.size() > 0)
|
||||
size_t const count = deltas.size();
|
||||
if (count > 0)
|
||||
{
|
||||
points.push_back(DecodeDelta(deltas[0], basePoint));
|
||||
if (deltas.size() > 1)
|
||||
if (count > 1)
|
||||
{
|
||||
points.push_back(DecodeDelta(deltas[1], points.back()));
|
||||
for (size_t i = 2; i < deltas.size(); ++i)
|
||||
for (size_t i = 2; i < count; ++i)
|
||||
{
|
||||
size_t const n = points.size();
|
||||
points.push_back(DecodeDelta(deltas[i],
|
||||
|
@ -150,17 +153,18 @@ void EncodePolylinePrev3(InPointsT const & points,
|
|||
ASSERT_LESS_OR_EQUAL(basePoint.x, maxPoint.x, (basePoint, maxPoint));
|
||||
ASSERT_LESS_OR_EQUAL(basePoint.y, maxPoint.y, (basePoint, maxPoint));
|
||||
|
||||
if (points.size() > 0)
|
||||
size_t const count = points.size();
|
||||
if (count > 0)
|
||||
{
|
||||
deltas.push_back(EncodeDelta(points[0], basePoint));
|
||||
if (points.size() > 1)
|
||||
if (count > 1)
|
||||
{
|
||||
deltas.push_back(EncodeDelta(points[1], points[0]));
|
||||
if (points.size() > 2)
|
||||
if (count > 2)
|
||||
{
|
||||
m2::PointU const prediction = PredictPointInPolyline(maxPoint, points[1], points[0]);
|
||||
deltas.push_back(EncodeDelta(points[2], prediction));
|
||||
for (size_t i = 3; i < points.size(); ++i)
|
||||
for (size_t i = 3; i < count; ++i)
|
||||
{
|
||||
m2::PointU const prediction =
|
||||
PredictPointInPolyline(maxPoint, points[i-1], points[i-2], points[i-3]);
|
||||
|
@ -181,18 +185,19 @@ void DecodePolylinePrev3(DeltasT const & deltas,
|
|||
ASSERT_LESS_OR_EQUAL(basePoint.x, maxPoint.x, (basePoint, maxPoint));
|
||||
ASSERT_LESS_OR_EQUAL(basePoint.y, maxPoint.y, (basePoint, maxPoint));
|
||||
|
||||
if (deltas.size() > 0)
|
||||
size_t const count = deltas.size();
|
||||
if (count> 0)
|
||||
{
|
||||
points.push_back(DecodeDelta(deltas[0], basePoint));
|
||||
if (deltas.size() > 1)
|
||||
if (count > 1)
|
||||
{
|
||||
m2::PointU const pt0 = points.back();
|
||||
points.push_back(DecodeDelta(deltas[1], pt0));
|
||||
if (deltas.size() > 2)
|
||||
if (count > 2)
|
||||
{
|
||||
points.push_back(DecodeDelta(deltas[2],
|
||||
PredictPointInPolyline(maxPoint, points.back(), pt0)));
|
||||
for (size_t i = 3; i < deltas.size(); ++i)
|
||||
for (size_t i = 3; i < count; ++i)
|
||||
{
|
||||
size_t const n = points.size();
|
||||
m2::PointU const prediction =
|
||||
|
@ -204,4 +209,61 @@ void DecodePolylinePrev3(DeltasT const & deltas,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
m2::PointU PredictPointInTriangle(m2::PointU const & maxPoint,
|
||||
m2::PointU const & p1,
|
||||
m2::PointU const & p2,
|
||||
m2::PointU const & p3)
|
||||
{
|
||||
// parallelogramm prediction
|
||||
return ClampPoint(maxPoint, p2 + p3 - p1);
|
||||
}
|
||||
|
||||
void EncodeTriangleStrip(InPointsT const & points,
|
||||
m2::PointU const & basePoint,
|
||||
m2::PointU const & maxPoint,
|
||||
DeltasT & deltas)
|
||||
{
|
||||
size_t const count = points.size();
|
||||
if (count > 0)
|
||||
{
|
||||
ASSERT_GREATER(count, 2, ());
|
||||
|
||||
deltas.push_back(EncodeDelta(points[0], basePoint));
|
||||
deltas.push_back(EncodeDelta(points[1], points[0]));
|
||||
deltas.push_back(EncodeDelta(points[2], points[1]));
|
||||
|
||||
for (size_t i = 3; i < count; ++i)
|
||||
{
|
||||
m2::PointU const prediction =
|
||||
PredictPointInTriangle(maxPoint, points[i-1], points[i-2], points[i-3]);
|
||||
deltas.push_back(EncodeDelta(points[i], prediction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeTriangleStrip(DeltasT const & deltas,
|
||||
m2::PointU const & basePoint,
|
||||
m2::PointU const & maxPoint,
|
||||
OutPointsT & points)
|
||||
{
|
||||
size_t const count = deltas.size();
|
||||
if (count > 0)
|
||||
{
|
||||
ASSERT_GREATER(count, 2, ());
|
||||
|
||||
points.push_back(DecodeDelta(deltas[0], basePoint));
|
||||
points.push_back(DecodeDelta(deltas[1], points.back()));
|
||||
points.push_back(DecodeDelta(deltas[2], points.back()));
|
||||
|
||||
for (size_t i = 3; i < count; ++i)
|
||||
{
|
||||
size_t const n = points.size();
|
||||
m2::PointU const prediction =
|
||||
PredictPointInTriangle(maxPoint, points[n-1], points[n-2], points[n-3]);
|
||||
points.push_back(DecodeDelta(deltas[i], prediction));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -84,25 +84,27 @@ inline void DecodePolyline(DeltasT const & deltas,
|
|||
DecodePolylinePrev2(deltas, basePoint, maxPoint, points);
|
||||
}
|
||||
|
||||
void EncodeTriangles(vector<m2::PointU> const & points,
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t> > const & triangles,
|
||||
typedef vector<tuple<uint32_t, uint32_t, uint32_t> > TrianglesT;
|
||||
|
||||
void EncodeTriangles(InPointsT const & points,
|
||||
TrianglesT const & triangles,
|
||||
m2::PointU const & basePoint,
|
||||
m2::PointU const & maxPoint,
|
||||
vector<char> & serialOutput);
|
||||
DeltasT & deltas);
|
||||
|
||||
void DecodeTriangles(char const * pBeg, char const * pEnd,
|
||||
void DecodeTriangles(DeltasT const & deltas,
|
||||
m2::PointU const & basePoint,
|
||||
m2::PointU const & maxPoint,
|
||||
vector<m2::PointU> & points,
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t> > & triangles);
|
||||
OutPointsT & points,
|
||||
TrianglesT & triangles);
|
||||
|
||||
void EncodeTriangleStrip(vector<m2::PointU> const & points,
|
||||
void EncodeTriangleStrip(InPointsT const & points,
|
||||
m2::PointU const & basePoint,
|
||||
m2::PointU const & maxPoint,
|
||||
vector<char> & serialOutput);
|
||||
DeltasT & deltas);
|
||||
|
||||
void DecodeTriangleStrip(char const * pBeg, char const * pEnd,
|
||||
void DecodeTriangleStrip(DeltasT const & deltas,
|
||||
m2::PointU const & basePoint,
|
||||
m2::PointU const & maxPoint,
|
||||
vector<m2::PointU> & points);
|
||||
OutPointsT & points);
|
||||
}
|
||||
|
|
|
@ -35,35 +35,35 @@ namespace serial
|
|||
}
|
||||
}
|
||||
|
||||
void EncodePath(vector<m2::PointD> const & points, int64_t base, vector<uint64_t> & deltas)
|
||||
void Encode(EncodeFunT fn, vector<m2::PointD> const & points, int64_t base, vector<uint64_t> & deltas)
|
||||
{
|
||||
vector<m2::PointU> 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);
|
||||
(*fn)(upoints, pts::GetBasePoint(base), pts::GetMaxPoint(), deltas);
|
||||
}
|
||||
|
||||
void DecodePath(vector<uint64_t> const & deltas, int64_t base, OutPointsT & points)
|
||||
void Decode(DecodeFunT fn, vector<uint64_t> const & deltas, int64_t base, OutPointsT & points)
|
||||
{
|
||||
vector<m2::PointU> upoints;
|
||||
upoints.reserve(deltas.size());
|
||||
|
||||
geo_coding::DecodePolyline(deltas, pts::GetBasePoint(base), pts::GetMaxPoint(), upoints);
|
||||
(*fn)(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)
|
||||
void const * LoadInner(DecodeFunT fn, void const * pBeg, size_t count, int64_t base, OutPointsT & points)
|
||||
{
|
||||
vector<uint64_t> deltas;
|
||||
deltas.reserve(count);
|
||||
void const * ret = ReadVarUint64Array(static_cast<char const *>(pBeg), count,
|
||||
MakeBackInsertFunctor(deltas));
|
||||
|
||||
DecodePath(deltas, base, points);
|
||||
Decode(fn, deltas, base, points);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "geometry_coding.hpp"
|
||||
|
||||
#include "../geometry/point2d.hpp"
|
||||
|
||||
#include "../coding/writer.hpp"
|
||||
|
@ -18,24 +20,27 @@ namespace serial
|
|||
WriteVarUint(sink, v[i]);
|
||||
}
|
||||
|
||||
void EncodePath(vector<m2::PointD> const & points, int64_t base, vector<uint64_t> & deltas);
|
||||
typedef void (*EncodeFunT)(vector<m2::PointU> const &, m2::PointU const &, m2::PointU const &, vector<uint64_t> &);
|
||||
typedef void (*DecodeFunT)(vector<uint64_t> const &, m2::PointU const &, m2::PointU const &, vector<m2::PointU> &);
|
||||
|
||||
void Encode(EncodeFunT fn, vector<m2::PointD> const & points, int64_t base, vector<uint64_t> & deltas);
|
||||
|
||||
typedef buffer_vector<m2::PointD, 32> OutPointsT;
|
||||
void DecodePath(vector<uint64_t> const & deltas, int64_t base, OutPointsT & points);
|
||||
void Decode(DecodeFunT fn, vector<uint64_t> const & deltas, int64_t base, OutPointsT & points);
|
||||
|
||||
template <class TSink>
|
||||
void SaveInnerPath(vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
void SaveInner(EncodeFunT fn, vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
{
|
||||
vector<uint64_t> deltas;
|
||||
EncodePath(points, base, deltas);
|
||||
Encode(fn, points, base, deltas);
|
||||
WriteVarUintArray(deltas, sink);
|
||||
}
|
||||
|
||||
template <class TSink>
|
||||
void SaveOuterPath(vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
void SaveOuter(EncodeFunT fn, vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
{
|
||||
vector<uint64_t> deltas;
|
||||
EncodePath(points, base, deltas);
|
||||
Encode(fn, points, base, deltas);
|
||||
|
||||
vector<char> buffer;
|
||||
MemWriter<vector<char> > writer(buffer);
|
||||
|
@ -46,10 +51,10 @@ namespace serial
|
|||
sink.Write(&buffer[0], count);
|
||||
}
|
||||
|
||||
void const * LoadInnerPath(void const * pBeg, size_t count, int64_t base, OutPointsT & points);
|
||||
void const * LoadInner(DecodeFunT fn, void const * pBeg, size_t count, int64_t base, OutPointsT & points);
|
||||
|
||||
template <class TSource>
|
||||
void LoadOuterPath(TSource & src, int64_t base, OutPointsT & points)
|
||||
void LoadOuter(DecodeFunT fn, TSource & src, int64_t base, OutPointsT & points)
|
||||
{
|
||||
uint32_t const count = ReadVarUint<uint32_t>(src);
|
||||
vector<char> buffer(count);
|
||||
|
@ -60,6 +65,46 @@ namespace serial
|
|||
deltas.reserve(count / 2);
|
||||
ReadVarUint64Array(p, p + count, MakeBackInsertFunctor(deltas));
|
||||
|
||||
DecodePath(deltas, base, points);
|
||||
Decode(fn, deltas, base, points);
|
||||
}
|
||||
|
||||
|
||||
/// @name Pathes.
|
||||
//@{
|
||||
template <class TSink>
|
||||
void SaveInnerPath(vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
{
|
||||
SaveInner(&geo_coding::EncodePolyline, points, base, sink);
|
||||
}
|
||||
template <class TSink>
|
||||
void SaveOuterPath(vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
{
|
||||
SaveOuter(&geo_coding::EncodePolyline, points, base, sink);
|
||||
}
|
||||
|
||||
inline void const * LoadInnerPath(void const * pBeg, size_t count, int64_t base, OutPointsT & points)
|
||||
{
|
||||
return LoadInner(&geo_coding::DecodePolyline, pBeg, count, base, points);
|
||||
}
|
||||
|
||||
template <class TSource>
|
||||
void LoadOuterPath(TSource & src, int64_t base, OutPointsT & points)
|
||||
{
|
||||
LoadOuter(&geo_coding::DecodePolyline, src, base, points);
|
||||
}
|
||||
//@}
|
||||
|
||||
/// @name Triangles.
|
||||
//@{
|
||||
template <class TSink>
|
||||
void SaveInnerTriangles(vector<m2::PointD> const & points, int64_t base, TSink & sink)
|
||||
{
|
||||
SaveInner(&geo_coding::EncodeTriangleStrip, points, base, sink);
|
||||
}
|
||||
|
||||
inline void const * LoadInnerTriangles(void const * pBeg, size_t count, int64_t base, OutPointsT & points)
|
||||
{
|
||||
return LoadInner(&geo_coding::DecodeTriangleStrip, pBeg, count, base, points);
|
||||
}
|
||||
//@}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue