From 1dabcc2ed735e9d987068678d3f74366a813f627 Mon Sep 17 00:00:00 2001 From: Alex Zolotarev Date: Sat, 29 Aug 2015 17:10:32 -0700 Subject: [PATCH] Integrated libtess2 library into our code. --- 3party/3party.pro | 2 +- 3party/libtess2/libtess2.pro | 31 +++++ generator/feature_sorter.cpp | 6 +- generator/generator_tests/generator_tests.pro | 2 +- generator/generator_tests/tesselator_test.cpp | 3 +- .../triangles_tree_coding_test.cpp | 2 +- generator/generator_tool/generator_tool.pro | 2 +- generator/tesselator.cpp | 114 ++++++------------ generator/tesselator.hpp | 19 ++- .../integration_tests/integration_tests.pro | 4 +- 10 files changed, 83 insertions(+), 102 deletions(-) create mode 100644 3party/libtess2/libtess2.pro diff --git a/3party/3party.pro b/3party/3party.pro index 05a49fd5d9..e6a6a21bb7 100644 --- a/3party/3party.pro +++ b/3party/3party.pro @@ -12,6 +12,6 @@ SUBDIRS += opening_hours \ !iphone*:!tizen*:!android* { SUBDIRS += gflags \ - sgitess \ + libtess2 \ gmock \ } diff --git a/3party/libtess2/libtess2.pro b/3party/libtess2/libtess2.pro new file mode 100644 index 0000000000..8f7ec8db30 --- /dev/null +++ b/3party/libtess2/libtess2.pro @@ -0,0 +1,31 @@ +TARGET = tess2 +TEMPLATE = lib +CONFIG += staticlib + +ROOT_DIR = ../.. + +include($$ROOT_DIR/common.pri) + +CONFIG -= warn_on +CONFIG *= warn_off + +INCLUDEPATH *= Include + +HEADERS += \ + Include/tesselator.h \ + Source/bucketalloc.h \ + Source/dict.h \ + Source/geom.h \ + Source/mesh.h \ + Source/priorityq.h \ + Source/sweep.h \ + Source/tess.h \ + +SOURCES += \ + Source/bucketalloc.c \ + Source/dict.c \ + Source/geom.c \ + Source/mesh.c \ + Source/priorityq.c \ + Source/sweep.c \ + Source/tess.c \ diff --git a/generator/feature_sorter.cpp b/generator/feature_sorter.cpp index 97d25bf392..25654a96a7 100644 --- a/generator/feature_sorter.cpp +++ b/generator/feature_sorter.cpp @@ -215,11 +215,9 @@ namespace feature { // tesselation tesselator::TrianglesInfo info; - tesselator::TesselateInterior(polys, info); - - if (info.IsEmpty()) + if (0 == tesselator::TesselateInterior(polys, info)) { - LOG(LINFO, ("NO TRIANGLES")); + LOG(LINFO, ("NO TRIANGLES in", polys)); return; } diff --git a/generator/generator_tests/generator_tests.pro b/generator/generator_tests/generator_tests.pro index 490c056990..1a3cae120c 100644 --- a/generator/generator_tests/generator_tests.pro +++ b/generator/generator_tests/generator_tests.pro @@ -4,7 +4,7 @@ CONFIG -= app_bundle TEMPLATE = app ROOT_DIR = ../.. -DEPENDENCIES = generator map routing indexer platform geometry coding base expat sgitess protobuf tomcrypt osrm succinct +DEPENDENCIES = generator map routing indexer platform geometry coding base expat tess2 protobuf tomcrypt osrm succinct include($$ROOT_DIR/common.pri) diff --git a/generator/generator_tests/tesselator_test.cpp b/generator/generator_tests/tesselator_test.cpp index 86f235714f..76740d609e 100644 --- a/generator/generator_tests/tesselator_test.cpp +++ b/generator/generator_tests/tesselator_test.cpp @@ -27,10 +27,11 @@ namespace size_t RunTest(list > const & l) { tesselator::TrianglesInfo info; - tesselator::TesselateInterior(l, info); + int const trianglesCount = tesselator::TesselateInterior(l, info); size_t count; info.ForEachTriangle(DoDump(count)); + ASSERT_EQUAL(count, trianglesCount, ()); return count; } diff --git a/generator/generator_tests/triangles_tree_coding_test.cpp b/generator/generator_tests/triangles_tree_coding_test.cpp index dd90fbe992..c21c933477 100644 --- a/generator/generator_tests/triangles_tree_coding_test.cpp +++ b/generator/generator_tests/triangles_tree_coding_test.cpp @@ -56,7 +56,7 @@ namespace info.Reserve(countT); for (size_t i = 0; i < countT; ++i) - info.Add(arrT[i]); + info.Add(arrT[i][0], arrT[i][1], arrT[i][2]); serial::CodingParams cp; diff --git a/generator/generator_tool/generator_tool.pro b/generator/generator_tool/generator_tool.pro index 013286ab7e..4c3ffe0f1f 100644 --- a/generator/generator_tool/generator_tool.pro +++ b/generator/generator_tool/generator_tool.pro @@ -2,7 +2,7 @@ ROOT_DIR = ../.. DEPENDENCIES = generator routing storage indexer platform geometry coding base \ - osrm gflags expat sgitess jansson protobuf tomcrypt \ + osrm gflags expat tess2 jansson protobuf tomcrypt \ succinct stats_client include($$ROOT_DIR/common.pri) diff --git a/generator/tesselator.cpp b/generator/tesselator.cpp index 7d6f4bbe2a..73ae2a07fb 100644 --- a/generator/tesselator.cpp +++ b/generator/tesselator.cpp @@ -10,65 +10,44 @@ #include "base/logging.hpp" #include "std/queue.hpp" +#include "std/unique_ptr.hpp" -#include "3party/sgitess/interface.h" +#include "3party/libtess2/Include/tesselator.h" namespace tesselator { - struct AddTessPointF + int TesselateInterior(PolygonsT const & polys, TrianglesInfo & info) { - tess::Tesselator & m_tess; - AddTessPointF(tess::Tesselator & tess) : m_tess(tess) - {} - void operator()(m2::PointD const & p) + int const kCoordinatesPerVertex = 2; + int const kVerticesInPolygon = 3; + + auto const deleter = [](TESStesselator * tess){ tessDeleteTess(tess); }; + unique_ptr tess(tessNewTess(nullptr), deleter); + for (auto const & contour : polys) + tessAddContour(tess.get(), kCoordinatesPerVertex, &contour[0], sizeof(contour[0]), contour.size()); + if (0 == tessTesselate(tess.get(), TESS_WINDING_ODD, TESS_CONSTRAINED_DELAUNAY_TRIANGLES, + kVerticesInPolygon, kCoordinatesPerVertex, nullptr)) { - m_tess.add(tess::Vertex(p.x, p.y)); - } - }; - - void TesselateInterior(PolygonsT const & polys, TrianglesInfo & info) - { - tess::VectorDispatcher disp; - tess::Tesselator tess; - tess.setDispatcher(&disp); - tess.setWindingRule(tess::WindingOdd); - - tess.beginPolygon(); - - for (PolygonsT::const_iterator it = polys.begin(); it != polys.end(); ++it) - { - tess.beginContour(); - for_each(it->begin(), it->end(), AddTessPointF(tess)); - tess.endContour(); + LOG(LERROR, ("Tesselator error for polygon", polys)); + return 0; } - tess.endPolygon(); - - // assign points - vector const & vert = disp.vertices(); - info.AssignPoints(vert.begin(), vert.end()); - - for (size_t i = 0; i < disp.indices().size(); ++i) + int const elementCount = tessGetElementCount(tess.get()); + if (elementCount) { - if (disp.indices()[i].first != tess::TrianglesList) - { - LOG(LERROR, ("We've got invalid type during teselation:", disp.indices()[i].first)); - continue; - } + int const vertexCount = tessGetVertexCount(tess.get()); + TESSreal const * vertices = tessGetVertices(tess.get()); + m2::PointD const * points = reinterpret_cast(vertices); + info.AssignPoints(points, points + vertexCount); - vector const & indices = disp.indices()[i].second; - size_t const count = indices.size(); - ASSERT_GREATER(count, 0, ()); - ASSERT_EQUAL(count % 3, 0, ()); - - info.Reserve(count / 3); - for (size_t j = 0; j < count; j += 3) - { - ASSERT_LESS ( j+2, count, () ); - info.Add(&indices[j]); - } + // Elements are triplets of vertex indices. + TESSindex const * elements = tessGetElements(tess.get()); + info.Reserve(elementCount); + for (int i = 0; i < elementCount; ++i) + info.Add(elements[i * 3], elements[i * 3 + 1], elements[i * 3 + 2]); } + return elementCount; } /////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -77,7 +56,7 @@ namespace tesselator int TrianglesInfo::ListInfo::empty_key = -1; - void TrianglesInfo::ListInfo::AddNeighbour(int p1, int p2, int trg) + void TrianglesInfo::ListInfo::AddNeighbour(int p1, int p2, size_t trg) { // find or insert element for key pair ret = m_neighbors.insert(make_pair(make_pair(p1, p2), trg)); @@ -86,17 +65,14 @@ namespace tesselator CHECK ( ret.second, ("Duplicating triangles for indices : ", p1, p2) ); } - void TrianglesInfo::ListInfo::Add(uintptr_t const * arr) + void TrianglesInfo::ListInfo::Add(int p0, int p1, int p2) { - ASSERT_EQUAL(arr[0], static_cast(arr[0]), ()); - ASSERT_EQUAL(arr[1], static_cast(arr[1]), ()); - ASSERT_EQUAL(arr[2], static_cast(arr[2]), ()); - int const arr32[] = { static_cast(arr[0]), static_cast(arr[1]), static_cast(arr[2]) }; - m_triangles.push_back(Triangle(arr32)); + m_triangles.emplace_back(p0, p1, p2); - size_t const trg = m_triangles.size()-1; - for (int i = 0; i < 3; ++i) - AddNeighbour(arr32[i], arr32[(i+1)%3], trg); + size_t const trg = m_triangles.size() - 1; + AddNeighbour(p0, p1, trg); + AddNeighbour(p1, p2, trg); + AddNeighbour(p2, p0, trg); } template size_t GetBufferSize(IterT b, IterT e) @@ -255,29 +231,9 @@ namespace tesselator // MakeTrianglesChainImpl(points, start, chain); } - void TrianglesInfo::Add(uintptr_t const * arr) + void TrianglesInfo::Add(int p0, int p1, int p2) { - // This checks are useless. We don't care about triangle orientation. - - // 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::robust::OrientedS(arrP[0], arrP[1], arrP[2]); - - if (cp != 0.0) - { - bool const isCCW = (cp > 0.0); - - if (m_isCCW == 0) - m_isCCW = (isCCW ? 1 : -1); - else - CHECK_EQUAL ( m_isCCW == 1, isCCW, () ); - - m_triangles.back().Add(arr); - } - */ - - m_triangles.back().Add(arr); + m_triangles.back().Add(p0, p1, p2); } void TrianglesInfo::GetPointsInfo(m2::PointU const & baseP, diff --git a/generator/tesselator.hpp b/generator/tesselator.hpp index 43fcfeafde..39bb9b93cc 100644 --- a/generator/tesselator.hpp +++ b/generator/tesselator.hpp @@ -72,10 +72,10 @@ namespace tesselator } }; - typedef unordered_map, int, HashPair> TNeighbours; + typedef unordered_map, size_t, HashPair> TNeighbours; TNeighbours m_neighbors; - void AddNeighbour(int p1, int p2, int trg); + void AddNeighbour(int p1, int p2, size_t trg); void GetNeighbors( Triangle const & trg, Triangle const & from, int * nb) const; @@ -91,7 +91,7 @@ namespace tesselator m_triangles.reserve(count); } - void Add(uintptr_t const * arr); + void Add(int p0, int p1, int p2); void Start() const { @@ -126,20 +126,14 @@ namespace tesselator {} /// @name Making functions. - //@{ template void AssignPoints(IterT b, IterT e) { - m_points.reserve(distance(b, e)); - while (b != e) - { - m_points.push_back(m2::PointD(b->x, b->y)); - ++b; - } + m_points.assign(b, e); } void Reserve(size_t count) { m_triangles.push_back(ListInfo(count)); } - void Add(uintptr_t const * arr); + void Add(int p0, int p1, int p2); //@} inline bool IsEmpty() const { return m_triangles.empty(); } @@ -187,5 +181,6 @@ namespace tesselator }; /// Main tesselate function. - void TesselateInterior(PolygonsT const & polys, TrianglesInfo & info); + /// @returns number of resulting triangles after triangulation. + int TesselateInterior(PolygonsT const & polys, TrianglesInfo & info); } diff --git a/search/integration_tests/integration_tests.pro b/search/integration_tests/integration_tests.pro index 18ada8fa2f..4b1acac89f 100644 --- a/search/integration_tests/integration_tests.pro +++ b/search/integration_tests/integration_tests.pro @@ -7,8 +7,8 @@ TEMPLATE = app ROOT_DIR = ../.. DEPENDENCIES = generator routing search storage stats_client jansson indexer platform geometry coding base \ - sgitess protobuf tomcrypt - + tess2 protobuf tomcrypt + !linux* { DEPENDENCIES += opening_hours \