Add parallelogramm prediction for strips serialization.

This commit is contained in:
vng 2011-02-01 22:48:50 +02:00 committed by Alex Zolotarev
parent 6e09c5a8b8
commit 5b533632a6
6 changed files with 169 additions and 99 deletions

View file

@ -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)

View file

@ -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);

View file

@ -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));
}
}
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);
}
//@}
}