diff --git a/indexer/geometry_serialization.hpp b/indexer/geometry_serialization.hpp index 92067bab7c..d29f0bf058 100644 --- a/indexer/geometry_serialization.hpp +++ b/indexer/geometry_serialization.hpp @@ -141,6 +141,14 @@ namespace serial void operator() (PointT arr[3], vector edges); + size_t GetBufferSize() const + { + size_t sz = 0; + for (list::const_iterator i = m_buffers.begin(); i != m_buffers.end(); ++i) + sz += i->size(); + return sz; + } + template void Save(TSink & sink) { size_t const count = m_buffers.size(); diff --git a/indexer/indexer_tests/triangles_tree_coding_test.cpp b/indexer/indexer_tests/triangles_tree_coding_test.cpp index 7f173259b8..5e41d3b62d 100644 --- a/indexer/indexer_tests/triangles_tree_coding_test.cpp +++ b/indexer/indexer_tests/triangles_tree_coding_test.cpp @@ -56,7 +56,11 @@ namespace info.Add(arrT[i]); serial::TrianglesChainSaver saver(0); - info.ProcessPortions(saver.GetBasePoint(), saver.GetMaxPoint(), &serial::pts::D2U, saver); + + tesselator::PointsInfo points; + info.GetPointsInfo(saver.GetBasePoint(), saver.GetMaxPoint(), &serial::pts::D2U, points); + + info.ProcessPortions(points, saver); vector buffer; MemWriter > writer(buffer); diff --git a/indexer/indexer_tool/feature_sorter.cpp b/indexer/indexer_tool/feature_sorter.cpp index 4649de59cd..b5446168ff 100644 --- a/indexer/indexer_tool/feature_sorter.cpp +++ b/indexer/indexer_tool/feature_sorter.cpp @@ -167,9 +167,20 @@ namespace feature tesselator::TrianglesInfo info; tesselator::TesselateInterior(bound, holes, info); - // triangles processing serial::TrianglesChainSaver saver(m_base); - info.ProcessPortions(saver.GetBasePoint(), saver.GetMaxPoint(), &serial::pts::D2U, saver); + + // points conversion + tesselator::PointsInfo points; + info.GetPointsInfo(saver.GetBasePoint(), saver.GetMaxPoint(), &serial::pts::D2U, points); + + // triangles processing (should be optimal) + info.ProcessPortions(points, saver, true); + + // check triangles processing (to compare with optimal) + //serial::TrianglesChainSaver checkSaver(m_base); + //info.ProcessPortions(points, checkSaver, false); + + //CHECK_LESS_OR_EQUAL(saver.GetBufferSize(), checkSaver.GetBufferSize(), ()); // saving to file saver.Save(*m_rMain.m_trgFile[i]); diff --git a/indexer/tesselator.cpp b/indexer/tesselator.cpp index e9526090c5..46547f6d6f 100644 --- a/indexer/tesselator.cpp +++ b/indexer/tesselator.cpp @@ -1,6 +1,8 @@ #include "tesselator.hpp" #include "geometry_coding.hpp" +#include "../coding/writer.hpp" + #include "../base/assert.hpp" #include "../base/logging.hpp" @@ -81,7 +83,7 @@ namespace tesselator void TrianglesInfo::ListInfo::AddNeighbour(int p1, int p2, int trg) { // find or insert element for key - pair ret = m_neighbours.insert(make_pair(make_pair(p1, p2), trg)); + pair ret = m_neighbors.insert(make_pair(make_pair(p1, p2), trg)); // triangles should not duplicate CHECK ( ret.second, ("Duplicating triangles for indices : ", p1, p2) ); @@ -97,18 +99,42 @@ namespace tesselator AddNeighbour(arr32[i], arr32[(i+1)%3], trg); } + template size_t GetBufferSize(IterT b, IterT e) + { + vector buffer; + MemWriter > writer(buffer); + while (b != e) WriteVarUint(writer, *b++); + return buffer.size(); + } + /// Find best (cheap in serialization) start edge for processing. TrianglesInfo::ListInfo::iter_t - TrianglesInfo::ListInfo::FindStartTriangle() const + TrianglesInfo::ListInfo::FindStartTriangle(PointsInfo const & points) const { - for (iter_t i = m_neighbours.begin(); i != m_neighbours.end(); ++i) + iter_t ret = m_neighbors.end(); + size_t cr = numeric_limits::max(); + + for (iter_t i = m_neighbors.begin(); i != m_neighbors.end(); ++i) { - if (m_neighbours.find(make_pair(i->first.second, i->first.first)) == m_neighbours.end()) - return i; + if (m_neighbors.find(make_pair(i->first.second, i->first.first)) == m_neighbors.end()) + { + uint64_t deltas[3]; + deltas[0] = EncodeDelta(points.m_points[i->first.first], points.m_base); + deltas[1] = EncodeDelta(points.m_points[i->first.second], points.m_points[i->first.first]); + deltas[2] = EncodeDelta(points.m_points[m_triangles[i->second].GetPoint3(i->first)], + points.m_points[i->first.second]); + + size_t const sz = GetBufferSize(deltas, deltas + 3); + if (sz < cr) + { + ret = i; + cr = sz; + } + } } - ASSERT ( false, ("?WTF? There is no border triangles!") ); - return m_neighbours.end(); + ASSERT ( ret != m_neighbors.end(), ("?WTF? There is no border triangles!") ); + return ret; } /// Return indexes of common edges of [to, from] triangles. @@ -123,26 +149,26 @@ namespace tesselator } } - ASSERT ( false, ("?WTF? Triangles not neighbours!") ); + ASSERT ( false, ("?WTF? Triangles not neighbors!") ); return make_pair(-1, -1); } - /// Get neighbours of 'trg' triangle, wich was riched from 'from' triangle. - /// @param[out] nb Neighbours indexes of 'trg' if 0->1 is common edge with'from': + /// Get neighbors of 'trg' triangle, which was achieved from 'from' triangle. + /// @param[out] nb neighbors indexes of 'trg' if 0->1 is common edge with'from': /// - nb[0] - by 1->2 edge; /// - nb[1] - by 2->0 edge; - void TrianglesInfo::ListInfo::GetNeighbours( + void TrianglesInfo::ListInfo::GetNeighbors( Triangle const & trg, Triangle const & from, int * nb) const { int i = my::NextModN(CommonEdge(trg, from).first, 3); int j = my::NextModN(i, 3); int ind = 0; - iter_t it = m_neighbours.find(make_pair(trg.m_p[j], trg.m_p[i])); - nb[ind++] = (it != m_neighbours.end()) ? it->second : empty_key; + iter_t it = m_neighbors.find(make_pair(trg.m_p[j], trg.m_p[i])); + nb[ind++] = (it != m_neighbors.end()) ? it->second : empty_key; - it = m_neighbours.find(make_pair(trg.m_p[my::NextModN(j, 3)], trg.m_p[j])); - nb[ind++] = (it != m_neighbours.end()) ? it->second : empty_key; + it = m_neighbors.find(make_pair(trg.m_p[my::NextModN(j, 3)], trg.m_p[j])); + nb[ind++] = (it != m_neighbors.end()) ? it->second : empty_key; } /// Calc delta of 'from'->'to' graph edge. @@ -163,22 +189,14 @@ namespace tesselator return EncodeDelta(points.m_points[to.m_p[(p.first+2) % 3]], prediction); } - // Element with less m_delta is better than another one. - struct edge_greater_delta - { - bool operator() (Edge const & e1, Edge const & e2) const - { - return (e1.m_delta > e2.m_delta); - } - }; - - void TrianglesInfo::ListInfo::MakeTrianglesChain( + template + void TrianglesInfo::ListInfo::MakeTrianglesChainImpl( PointsInfo const & points, iter_t start, vector & chain) const { Triangle const fictive(start->first.second, start->first.first, -1); - priority_queue, edge_greater_delta> q; - q.push(Edge(-1, start->second, 0.0, -1)); + priority_queue, TPopOrder> q; + q.push(Edge(-1, start->second, 0, -1)); // marks of visited nodes vector visited; @@ -200,19 +218,48 @@ namespace tesselator Triangle const & trg = m_triangles[e.m_p[1]]; - // get neighbours + // get neighbors int nb[2]; - GetNeighbours(trg, (e.m_p[0] == -1) ? fictive : m_triangles[e.m_p[0]], nb); + GetNeighbors(trg, (e.m_p[0] == -1) ? fictive : m_triangles[e.m_p[0]], nb); - // push neighbours to queue + // push neighbors to queue for (int i = 0; i < 2; ++i) if (nb[i] != empty_key && !visited[nb[i]]) q.push(Edge(e.m_p[1], nb[i], CalcDelta(points, trg, m_triangles[nb[i]]), i)); } } + // Element with less m_delta is better than another one. + struct edge_greater_delta + { + bool operator() (Edge const & e1, Edge const & e2) const + { + return (e1.m_delta > e2.m_delta); + } + }; + + // Experimental ... + struct edge_less_delta + { + bool operator() (Edge const & e1, Edge const & e2) const + { + return (e1.m_delta < e2.m_delta); + } + }; + + void TrianglesInfo::ListInfo::MakeTrianglesChain( + PointsInfo const & points, iter_t start, vector & chain, bool goodOrder) const + { + //if (goodOrder) + MakeTrianglesChainImpl(points, start, chain); + //else + // MakeTrianglesChainImpl(points, start, chain); + } + void TrianglesInfo::Add(uintptr_t const * arr) { + // When adding triangles, check that they all have identical orientation! + m2::PointD arrP[] = { m_points[arr[0]], m_points[arr[1]], m_points[arr[2]] }; double const cp = m2::CrossProduct(arrP[1] - arrP[0], arrP[2] - arrP[1]); @@ -228,4 +275,16 @@ namespace tesselator m_triangles.back().Add(arr); } + + void TrianglesInfo::GetPointsInfo(m2::PointU const & baseP, m2::PointU const & maxP, + m2::PointU (*convert) (m2::PointD const &), PointsInfo & info) const + { + info.m_base = baseP; + info.m_max = maxP; + + size_t const count = m_points.size(); + info.m_points.reserve(count); + for (size_t i = 0; i < count; ++i) + info.m_points.push_back((*convert)(m_points[i])); + } } diff --git a/indexer/tesselator.hpp b/indexer/tesselator.hpp index fcd821cad0..9f23ff6bc9 100644 --- a/indexer/tesselator.hpp +++ b/indexer/tesselator.hpp @@ -48,11 +48,6 @@ namespace tesselator typedef m2::PointU PointT; vector m_points; PointT m_base, m_max; - - PointsInfo(PointT const & baseP, PointT const & maxP) - : m_base(baseP), m_max(maxP) - { - } }; class TrianglesInfo @@ -66,19 +61,19 @@ namespace tesselator vector m_triangles; // directed edge -> triangle - typedef unordered_map, int> neighbours_t; - neighbours_t m_neighbours; + typedef unordered_map, int> neighbors_t; + neighbors_t m_neighbors; void AddNeighbour(int p1, int p2, int trg); - void GetNeighbours( + void GetNeighbors( Triangle const & trg, Triangle const & from, int * nb) const; uint64_t CalcDelta( PointsInfo const & points, Triangle const & from, Triangle const & to) const; public: - typedef neighbours_t::const_iterator iter_t; + typedef neighbors_t::const_iterator iter_t; ListInfo(size_t count) { @@ -87,9 +82,13 @@ namespace tesselator void Add(uintptr_t const * arr); - iter_t FindStartTriangle() const; + iter_t FindStartTriangle(PointsInfo const & points) const; - void MakeTrianglesChain(PointsInfo const & points, iter_t start, vector & chain) const; + private: + template + void MakeTrianglesChainImpl(PointsInfo const & points, iter_t start, vector & chain) const; + public: + void MakeTrianglesChain(PointsInfo const & points, iter_t start, vector & chain, bool goodOrder) const; Triangle GetTriangle(int i) const { return m_triangles[i]; } }; @@ -118,30 +117,25 @@ namespace tesselator void Add(uintptr_t const * arr); //@{ + // Convert points from double to uint. + void GetPointsInfo( m2::PointU const & baseP, m2::PointU const & maxP, + m2::PointU (*convert) (m2::PointD const &), PointsInfo & info) const; + /// Triangles chains processing function. template - void ProcessPortions(m2::PointU const & baseP, m2::PointU const & maxP, - m2::PointU (*convert) (m2::PointD const &), EmitterT & emitter) + void ProcessPortions(PointsInfo const & points, EmitterT & emitter, bool goodOrder = true) const { - // convert points from double to uint - size_t const count = m_points.size(); - PointsInfo points(baseP, maxP); - points.m_points.reserve(count); - for (size_t i = 0; i < count; ++i) - points.m_points.push_back((*convert)(m_points[i])); - // process portions and push out result chains vector chain; for (list::const_iterator i = m_triangles.begin(); i != m_triangles.end(); ++i) { chain.clear(); - typename ListInfo::iter_t start = i->FindStartTriangle(); - i->MakeTrianglesChain(points, start, chain); + typename ListInfo::iter_t start = i->FindStartTriangle(points); + i->MakeTrianglesChain(points, start, chain, goodOrder); - Triangle const trg = i->GetTriangle(start->second); m2::PointU arr[] = { points.m_points[start->first.first], points.m_points[start->first.second], - points.m_points[trg.GetPoint3(start->first)] }; + points.m_points[i->GetTriangle(start->second).GetPoint3(start->first)] }; emitter(arr, chain); }