From fb3fc35c714ceb61bfc9406a6b53a8940adab8b7 Mon Sep 17 00:00:00 2001 From: rinkk <karsten.rink@ufz.de> Date: Mon, 7 Jun 2021 14:44:57 +0200 Subject: [PATCH] Bringing old ear clipping code up to current standards more optimisations, range loops, typos, etc. --- Applications/FileIO/Legacy/createSurface.cpp | 15 +- GeoLib/EarClippingTriangulation.cpp | 324 +++++++++++-------- GeoLib/EarClippingTriangulation.h | 16 +- GeoLib/Polygon.cpp | 6 +- 4 files changed, 209 insertions(+), 152 deletions(-) diff --git a/Applications/FileIO/Legacy/createSurface.cpp b/Applications/FileIO/Legacy/createSurface.cpp index c0d6c6b62b5..80f62e60ad7 100644 --- a/Applications/FileIO/Legacy/createSurface.cpp +++ b/Applications/FileIO/Legacy/createSurface.cpp @@ -146,20 +146,15 @@ GeoLib::Surface* createSurfaceWithEarClipping(GeoLib::Polyline const& line) std::list<GeoLib::Polygon*> const& list_of_simple_polygons = polygon->computeListOfSimplePolygons(); - for (std::list<GeoLib::Polygon*>::const_iterator simple_polygon_it( - list_of_simple_polygons.begin()); - simple_polygon_it != list_of_simple_polygons.end(); - ++simple_polygon_it) + for (auto const& simple_polygon : list_of_simple_polygons) { std::list<GeoLib::Triangle> triangles; - GeoLib::EarClippingTriangulation(*simple_polygon_it, triangles); + GeoLib::EarClippingTriangulation(*simple_polygon, triangles); // add Triangles to Surface - std::list<GeoLib::Triangle>::const_iterator it(triangles.begin()); - while (it != triangles.end()) + for (auto const& t : triangles) { - sfc->addTriangle((*it)[0], (*it)[1], (*it)[2]); - ++it; + sfc->addTriangle(t[0], t[1], t[2]); } } // delete polygon; @@ -167,7 +162,7 @@ GeoLib::Surface* createSurfaceWithEarClipping(GeoLib::Polyline const& line) { WARN( "Surface::createSurface(): Triangulation does not contain any " - "triangle."); + "triangles."); delete sfc; return nullptr; } diff --git a/GeoLib/EarClippingTriangulation.cpp b/GeoLib/EarClippingTriangulation.cpp index 3b1bdcf1007..5415521cb87 100644 --- a/GeoLib/EarClippingTriangulation.cpp +++ b/GeoLib/EarClippingTriangulation.cpp @@ -14,119 +14,137 @@ #include "EarClippingTriangulation.h" -//#include "BaseLib/uniqueInsert.h" +#include <numeric> +#include "BaseLib/Algorithm.h" #include "MathLib/GeometricBasics.h" - +#include "Point.h" #include "Polygon.h" #include "Triangle.h" -#include "Point.h" - -template <typename Container> -void uniquePushBack(Container& container, - typename Container::value_type const& element) -{ - if (std::find(container.begin(), container.end(), element) == - container.end()) - container.push_back(element); -} namespace GeoLib { -EarClippingTriangulation::EarClippingTriangulation(const GeoLib::Polygon* polygon, - std::list<GeoLib::Triangle> &triangles, bool rot) +EarClippingTriangulation::EarClippingTriangulation( + GeoLib::Polygon const& polygon, std::list<GeoLib::Triangle>& triangles, + bool rot) { - copyPolygonPoints (polygon); + copyPolygonPoints(polygon); - if (rot) { - rotatePointsToXY (_pnts); - ensureCWOrientation (); + if (rot) + { + rotatePointsToXY(_pnts); + ensureCWOrientation(); } - initVertexList (); - initLists (); - clipEars (); + initVertexList(); + initLists(); + clipEars(); - std::vector<GeoLib::Point*> const& ref_pnts_vec (polygon->getPointsVec()); - std::list<GeoLib::Triangle>::const_iterator it (_triangles.begin()); - if (_original_orient == GeoLib::CW) { - while (it != _triangles.end()) { - const std::size_t i0 (polygon->getPointID ((*it)[0])); - const std::size_t i1 (polygon->getPointID ((*it)[1])); - const std::size_t i2 (polygon->getPointID ((*it)[2])); - triangles.push_back (GeoLib::Triangle (ref_pnts_vec, i0, i1, i2)); - ++it; + std::vector<GeoLib::Point*> const& ref_pnts_vec(polygon.getPointsVec()); + if (_original_orientation == GeoLib::CW) + { + for (auto const& t : _triangles) + { + const std::size_t i0(polygon.getPointID(t[0])); + const std::size_t i1(polygon.getPointID(t[1])); + const std::size_t i2(polygon.getPointID(t[2])); + triangles.emplace_back(ref_pnts_vec, i0, i1, i2); } - } else { - std::size_t n_pnts (_pnts.size() - 1); - while (it != _triangles.end()) { - const std::size_t i0 (polygon->getPointID (n_pnts - (*it)[0])); - const std::size_t i1 (polygon->getPointID (n_pnts - (*it)[1])); - const std::size_t i2 (polygon->getPointID (n_pnts - (*it)[2])); - triangles.push_back (GeoLib::Triangle (ref_pnts_vec, i0, i1, i2)); - ++it; + } + else + { + std::size_t n_pnts(_pnts.size() - 1); + for (auto const& t : _triangles) + { + const std::size_t i0(polygon.getPointID(n_pnts - t[0])); + const std::size_t i1(polygon.getPointID(n_pnts - t[1])); + const std::size_t i2(polygon.getPointID(n_pnts - t[2])); + triangles.emplace_back(ref_pnts_vec, i0, i1, i2); } } } EarClippingTriangulation::~EarClippingTriangulation() { - const std::size_t n_pnts (_pnts.size()); - for (std::size_t k(0); k<n_pnts; k++) { - delete _pnts[k]; + for (auto p : _pnts) + { + delete p; } } -void EarClippingTriangulation::copyPolygonPoints (const GeoLib::Polygon* polygon) +void EarClippingTriangulation::copyPolygonPoints(GeoLib::Polygon const& polygon) { // copy points - last point is identical to the first - std::size_t n_pnts (polygon->getNumberOfPoints() - 1); - for (std::size_t k(0); k < n_pnts; k++) { - _pnts.push_back (new GeoLib::Point (*(polygon->getPoint(k)))); + std::size_t n_pnts(polygon.getNumberOfPoints() - 1); + for (std::size_t k(0); k < n_pnts; k++) + { + _pnts.push_back(new GeoLib::Point(*(polygon.getPoint(k)))); } } -void EarClippingTriangulation::ensureCWOrientation () +void EarClippingTriangulation::ensureCWOrientation() { - std::size_t n_pnts (_pnts.size()); + std::size_t n_pnts(_pnts.size()); // get the left most upper point - std::size_t min_x_max_y_idx (0); // for orientation check - for (std::size_t k(0); k<n_pnts; k++) { - if ((*(_pnts[k]))[0] <= (*(_pnts[min_x_max_y_idx]))[0]) { - if ((*(_pnts[k]))[0] < (*(_pnts[min_x_max_y_idx]))[0]) { + std::size_t min_x_max_y_idx(0); // for orientation check + for (std::size_t k(0); k < n_pnts; k++) + { + if ((*(_pnts[k]))[0] <= (*(_pnts[min_x_max_y_idx]))[0]) + { + if ((*(_pnts[k]))[0] < (*(_pnts[min_x_max_y_idx]))[0]) + { min_x_max_y_idx = k; - } else { - if ((*(_pnts[k]))[1] > (*(_pnts[min_x_max_y_idx]))[1]) { + } + else + { + if ((*(_pnts[k]))[1] > (*(_pnts[min_x_max_y_idx]))[1]) + { min_x_max_y_idx = k; } } } } // determine orientation - if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts-1) { - _original_orient = GeoLib::getOrientation ( - *_pnts[min_x_max_y_idx-1], *_pnts[min_x_max_y_idx], *_pnts[min_x_max_y_idx+1]); - } else { - if (0 == min_x_max_y_idx) { - _original_orient = GeoLib::getOrientation (*_pnts[n_pnts-1], *_pnts[0], *_pnts[1]); - } else { - _original_orient = GeoLib::getOrientation (*_pnts[n_pnts-2], *_pnts[n_pnts-1], *_pnts[0]); + if (0 < min_x_max_y_idx && min_x_max_y_idx < n_pnts - 1) + { + _original_orientation = + GeoLib::getOrientation(*_pnts[min_x_max_y_idx - 1], + *_pnts[min_x_max_y_idx], + *_pnts[min_x_max_y_idx + 1]); + } + else + { + if (0 == min_x_max_y_idx) + { + _original_orientation = GeoLib::getOrientation( + *_pnts[n_pnts - 1], *_pnts[0], *_pnts[1]); + } + else + { + _original_orientation = GeoLib::getOrientation( + *_pnts[n_pnts - 2], *_pnts[n_pnts - 1], *_pnts[0]); } } - if (_original_orient == GeoLib::CCW) { + if (_original_orientation == GeoLib::CCW) + { // switch orientation - for (std::size_t k(0); k<n_pnts/2; k++) { - std::swap (_pnts[k], _pnts[n_pnts-1-k]); + for (std::size_t k(0); k < n_pnts / 2; k++) + { + std::swap(_pnts[k], _pnts[n_pnts - 1 - k]); } } } -bool EarClippingTriangulation::isEar(std::size_t v0, std::size_t v1, std::size_t v2) const +bool EarClippingTriangulation::isEar(std::size_t v0, std::size_t v1, + std::size_t v2) const { - for (std::list<std::size_t>::const_iterator it (_vertex_list.begin ()); - it != _vertex_list.end(); ++it) { - if (*it != v0 && *it != v1 && *it != v2) { - if (MathLib::isPointInTriangle (*_pnts[*it], *_pnts[v0], *_pnts[v1], *_pnts[v2])) { + for (auto const& v : _vertex_list) + { + if (v != v0 && v != v1 && v != v2) + { + if (MathLib::isPointInTriangle(*_pnts[v], *_pnts[v0], *_pnts[v1], + *_pnts[v2])) + { return false; } } @@ -134,42 +152,50 @@ bool EarClippingTriangulation::isEar(std::size_t v0, std::size_t v1, std::size_t return true; } -void EarClippingTriangulation::initVertexList () +void EarClippingTriangulation::initVertexList() { - std::size_t n_pnts (_pnts.size()); - for (std::size_t k(0); k<n_pnts; k++) - _vertex_list.push_back (k); + _vertex_list.resize(_pnts.size()); + std::iota(begin(_vertex_list), end(_vertex_list), 0); } -void EarClippingTriangulation::initLists () +void EarClippingTriangulation::initLists() { - // go through points checking ccw, cw or collinear order and identifying ears - std::list<std::size_t>::iterator it (_vertex_list.begin()), prev(_vertex_list.end()), next; + // go through points checking ccw, cw or collinear order and identifying + // ears + std::list<std::size_t>::iterator it(_vertex_list.begin()), + prev(_vertex_list.end()), next; --prev; next = it; ++next; GeoLib::Orientation orientation; - bool first_run(true); // saves special handling of the last case with identical code - while (_vertex_list.size() >= 3 && first_run) { - if (next == _vertex_list.end()) { + bool first_run( + true); // saves special handling of the last case with identical code + while (_vertex_list.size() >= 3 && first_run) + { + if (next == _vertex_list.end()) + { first_run = false; next = _vertex_list.begin(); } - orientation = getOrientation (*_pnts[*prev], *_pnts[*it], *_pnts[*next]); - if (orientation == GeoLib::COLLINEAR) { + orientation = getOrientation(*_pnts[*prev], *_pnts[*it], *_pnts[*next]); + if (orientation == GeoLib::COLLINEAR) + { WARN( "EarClippingTriangulation::initLists(): collinear points " "({:f}, {:f}, {:f}), ({:f}, {:f}, {:f}), ({:f}, {:f}, {:f})", - (*_pnts[*prev])[0], (*_pnts[*prev])[1], (*_pnts[*prev])[2], - (*_pnts[*it])[0], (*_pnts[*it])[1], (*_pnts[*it])[2], - (*_pnts[*next])[0], (*_pnts[*next])[1], (*_pnts[*next])[2]); - it = _vertex_list.erase (it); + (*_pnts[*prev])[0], (*_pnts[*prev])[1], (*_pnts[*prev])[2], + (*_pnts[*it])[0], (*_pnts[*it])[1], (*_pnts[*it])[2], + (*_pnts[*next])[0], (*_pnts[*next])[1], (*_pnts[*next])[2]); + it = _vertex_list.erase(it); ++next; - } else { - if (orientation == GeoLib::CW) { - _convex_vertex_list.push_back (*it); - if (isEar (*prev, *it, *next)) - _ear_list.push_back (*it); + } + else + { + if (orientation == GeoLib::CW) + { + _convex_vertex_list.push_back(*it); + if (isEar(*prev, *it, *next)) + _ear_list.push_back(*it); } prev = it; it = next; @@ -182,63 +208,82 @@ void EarClippingTriangulation::clipEars() { std::list<std::size_t>::iterator it, prev, next; // *** clip an ear - while (_vertex_list.size() > 3) { + while (_vertex_list.size() > 3) + { // pop ear from list std::size_t ear = _ear_list.front(); _ear_list.pop_front(); // remove ear tip from _convex_vertex_list _convex_vertex_list.remove(ear); - // remove ear from vertex_list, apply changes to _ear_list, _convex_vertex_list + // remove ear from vertex_list, apply changes to _ear_list, + // _convex_vertex_list bool nfound(true); it = _vertex_list.begin(); prev = _vertex_list.end(); --prev; - while (nfound && it != _vertex_list.end()) { - if (*it == ear) { + while (nfound && it != _vertex_list.end()) + { + if (*it == ear) + { nfound = false; - it = _vertex_list.erase(it); // remove ear tip + it = _vertex_list.erase(it); // remove ear tip next = it; - if (next == _vertex_list.end()) { + if (next == _vertex_list.end()) + { next = _vertex_list.begin(); prev = _vertex_list.end(); --prev; } // add triangle - _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *next, ear)); + _triangles.emplace_back(_pnts, *prev, *next, ear); // check the orientation of prevprev, prev, next std::list<std::size_t>::iterator prevprev; - if (prev == _vertex_list.begin()) { + if (prev == _vertex_list.begin()) + { prevprev = _vertex_list.end(); - } else { + } + else + { prevprev = prev; } --prevprev; - // apply changes to _convex_vertex_list and _ear_list looking "backward" - GeoLib::Orientation orientation = GeoLib::getOrientation(*_pnts[*prevprev], *_pnts[*prev], - *_pnts[*next]); - if (orientation == GeoLib::CW) { - uniquePushBack(_convex_vertex_list, *prev); + // apply changes to _convex_vertex_list and _ear_list looking + // "backward" + GeoLib::Orientation orientation = GeoLib::getOrientation( + *_pnts[*prevprev], *_pnts[*prev], *_pnts[*next]); + if (orientation == GeoLib::CW) + { + BaseLib::uniquePushBack(_convex_vertex_list, *prev); // prev is convex - if (isEar(*prevprev, *prev, *next)) { + if (isEar(*prevprev, *prev, *next)) + { // prev is an ear tip - uniquePushBack(_ear_list, *prev); - } else { + BaseLib::uniquePushBack(_ear_list, *prev); + } + else + { // if necessary remove prev _ear_list.remove(*prev); } - } else { + } + else + { // prev is not convex => reflex or collinear _convex_vertex_list.remove(*prev); _ear_list.remove(*prev); - if (orientation == GeoLib::COLLINEAR) { + if (orientation == GeoLib::COLLINEAR) + { prev = _vertex_list.erase(prev); - if (prev == _vertex_list.begin()) { + if (prev == _vertex_list.begin()) + { prev = _vertex_list.end(); --prev; - } else { + } + else + { --prev; } } @@ -246,44 +291,56 @@ void EarClippingTriangulation::clipEars() // check the orientation of prev, next, nextnext std::list<std::size_t>::iterator nextnext, - help_it(_vertex_list.end()); + help_it(_vertex_list.end()); --help_it; - if (next == help_it) { + if (next == help_it) + { nextnext = _vertex_list.begin(); - } else { + } + else + { nextnext = next; ++nextnext; } - // apply changes to _convex_vertex_list and _ear_list looking "forward" + // apply changes to _convex_vertex_list and _ear_list looking + // "forward" orientation = getOrientation(*_pnts[*prev], *_pnts[*next], - *_pnts[*nextnext]); - if (orientation == GeoLib::CW) { - uniquePushBack(_convex_vertex_list, *next); + *_pnts[*nextnext]); + if (orientation == GeoLib::CW) + { + BaseLib::uniquePushBack(_convex_vertex_list, *next); // next is convex - if (isEar(*prev, *next, *nextnext)) { + if (isEar(*prev, *next, *nextnext)) + { // next is an ear tip - uniquePushBack(_ear_list, *next); - } else { + BaseLib::uniquePushBack(_ear_list, *next); + } + else + { // if necessary remove *next _ear_list.remove(*next); } - } else { + } + else + { // next is not convex => reflex or collinear _convex_vertex_list.remove(*next); _ear_list.remove(*next); - if (orientation == GeoLib::COLLINEAR) { + if (orientation == GeoLib::COLLINEAR) + { next = _vertex_list.erase(next); if (next == _vertex_list.end()) next = _vertex_list.begin(); } } - } else { + } + else + { prev = it; ++it; } } - } // add last triangle @@ -291,16 +348,25 @@ void EarClippingTriangulation::clipEars() prev = next; ++next; if (next == _vertex_list.end()) + { return; + } it = next; ++next; if (next == _vertex_list.end()) + { return; + } - if (getOrientation(*_pnts[*prev], *_pnts[*it], *_pnts[*next]) == GeoLib::CCW) - _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *it, *next)); + if (getOrientation(*_pnts[*prev], *_pnts[*it], *_pnts[*next]) == + GeoLib::CCW) + { + _triangles.emplace_back(_pnts, *prev, *it, *next); + } else - _triangles.push_back(GeoLib::Triangle(_pnts, *prev, *next, *it)); + { + _triangles.emplace_back(_pnts, *prev, *next, *it); + } } -} // end namespace GeoLib +} // end namespace GeoLib diff --git a/GeoLib/EarClippingTriangulation.h b/GeoLib/EarClippingTriangulation.h index 4eec2a09ba3..eac383b153b 100644 --- a/GeoLib/EarClippingTriangulation.h +++ b/GeoLib/EarClippingTriangulation.h @@ -12,8 +12,7 @@ * */ -#ifndef EARCLIPPINGTRIANGULATION_H_ -#define EARCLIPPINGTRIANGULATION_H_ +#pragma once #include <list> #include <vector> @@ -26,18 +25,19 @@ namespace GeoLib class Polygon; class Triangle; -class EarClippingTriangulation +class EarClippingTriangulation final { public: - EarClippingTriangulation(const GeoLib::Polygon* ply, + EarClippingTriangulation(GeoLib::Polygon const& polygon, std::list<GeoLib::Triangle> &triangles, bool rot = true); - virtual ~EarClippingTriangulation(); + ~EarClippingTriangulation(); + private: /** * copies the points of the polygon to the vector _pnts */ - inline void copyPolygonPoints (const GeoLib::Polygon* polygon); + inline void copyPolygonPoints(GeoLib::Polygon const& polygon); inline void ensureCWOrientation (); inline bool isEar(std::size_t v0, std::size_t v1, std::size_t v2) const; @@ -59,8 +59,6 @@ private: */ std::list<GeoLib::Triangle> _triangles; - GeoLib::Orientation _original_orient; + GeoLib::Orientation _original_orientation; }; } // end namespace GeoLib - -#endif /* EARCLIPPINGTRIANGULATION_H_ */ diff --git a/GeoLib/Polygon.cpp b/GeoLib/Polygon.cpp index dbcdaf8043a..f87d194e06f 100644 --- a/GeoLib/Polygon.cpp +++ b/GeoLib/Polygon.cpp @@ -620,11 +620,9 @@ std::list<Polygon*> const& Polygon::computeListOfSimplePolygons() splitPolygonAtPoint(_simple_polygon_list.begin()); splitPolygonAtIntersection(_simple_polygon_list.begin()); - for (std::list<GeoLib::Polygon*>::iterator it(_simple_polygon_list.begin()); - it != _simple_polygon_list.end(); - ++it) + for (auto polygon : _simple_polygon_list) { - (*it)->initialise(); + polygon->initialise(); } return _simple_polygon_list; } -- GitLab