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; --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()) { first_run = false; next = _vertex_list.begin(); } 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); ++next; } 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; ++next; } } }
void EarClippingTriangulation::initLists () { // go through points checking ccw, cw or collinear order and identifying ears std::list<size_t>::iterator it (_vertex_list.begin()), prev(_vertex_list.end()), next; prev--; next = it; next++; MathLib::Orientation orientation; while (next != _vertex_list.end()) { orientation = getOrientation (_pnts[*prev], _pnts[*it], _pnts[*next]); if (orientation == COLLINEAR) { it = _vertex_list.erase (it); next++; } else { if (orientation == CW) { _convex_vertex_list.push_back (*it); if (isEar (*prev, *it, *next)) _ear_list.push_back (*it); } prev = it; it = next; next++; } } next = _vertex_list.begin(); orientation = getOrientation (_pnts[*prev], _pnts[*it], _pnts[*next]); if (orientation == COLLINEAR) it = _vertex_list.erase (it); if (orientation == CW) { _convex_vertex_list.push_back (*it); if (isEar (*prev, *it, *next)) _ear_list.push_back (*it); } }
PolygonTriangulation EarRemovalAlgorithm::triangulate(const vector<Point2D> & polygon){ int n = polygon.size(); PolygonTriangulation t(polygon); if(n < 3) return t; list<int> currPoly; // Lista que armazena os índices do polígono atual do algoritmo de remoção de orelhas vector<int> isEar(n, 0); // Vetor que armazena indicador de formação de orelha nos pontos do polígono // Adiciona todos os pontos do polígono na lista de pontos do polígono atual do algoritmo for(int i=0; i<n; i++){ currPoly.push_back(i); } // Determina para cada ponto se no mesmo se forma uma orelha no triângulo formado com seus vizinhos for(list<int>::iterator it = currPoly.begin(); it != currPoly.end(); it++){ int p = *it; isEar[p] = checkEar(currPoly, it, polygon); } // Equanto não tivermos apenas um triângulo, então removemos ums orelha while(currPoly.size() > 3){ // Procura uma orelha no polígono atual for(list<int>::iterator it = currPoly.begin(); it != currPoly.end(); it++){ int p = *it; if(isEar[p]){ list<int>::iterator prevIt = getPrevIterator(currPoly, it); list<int>::iterator nextIt = getNextIterator(currPoly, it); // Determina índice dos pontos da orelha int p0 = *prevIt; int p1 = *it; int p2 = *nextIt; // Adicioa orelha a triangulação do polígono t.addTriangle(p0, p1, p2); // Remove o ponto central do triângulo do polígono currPoly.erase(it); // Atualiza o indicador de orelha nos pontos vizinhos de p1 no novo polígono formado após a remoção de p1 isEar[p0] = checkEar(currPoly, prevIt, polygon); isEar[p2] = checkEar(currPoly, nextIt, polygon); break; } } } // Adiciona o triângulo final na triangulação list<int>::iterator it = currPoly.begin(); int p0 = *it; it++; int p1 = *it; it++; int p2 = *it; t.addTriangle(p0, p1, p2); return t; }
void triangulate(const Vertices& vertices, PolygonMesh& output) { const int n_vertices = vertices.vertices.size(); if (n_vertices <= 3) { output.polygons.push_back(vertices); return; } std::vector<uint32_t> remaining_vertices(n_vertices); if (area(vertices.vertices) > 0) // clockwise? { remaining_vertices = vertices.vertices; } else { for (int v = 0; v < n_vertices; v++) remaining_vertices[v] = vertices.vertices[n_vertices - 1 - v]; } // Avoid closed loops. if (remaining_vertices.front() == remaining_vertices.back()) remaining_vertices.erase(remaining_vertices.end()-1); // null_iterations avoids infinite loops if the polygon is not simple. for (int u = remaining_vertices.size() - 1, null_iterations = 0; remaining_vertices.size() > 2 && null_iterations < remaining_vertices.size()*2; ++null_iterations, u=(u+1)%remaining_vertices.size()) { int v = (u + 1) % remaining_vertices.size(); int w = (u + 2) % remaining_vertices.size(); if (isEar(u, v, w, remaining_vertices)) { Vertices triangle; triangle.vertices.resize(3); triangle.vertices[0] = remaining_vertices[u]; triangle.vertices[1] = remaining_vertices[v]; triangle.vertices[2] = remaining_vertices[w]; output.polygons.push_back(triangle); remaining_vertices.erase(remaining_vertices.begin()+v); null_iterations = 0; } } for (int i = 0; i < remaining_vertices.size(); ++i) ntk_dbg_print(remaining_vertices[i], 1); }
void pcl::EarClipping::triangulate (const Vertices& vertices, PolygonMesh& output) { const int n_vertices = static_cast<const int> (vertices.vertices.size ()); if (n_vertices <= 3) return; std::vector<uint32_t> remaining_vertices (n_vertices); if (area (vertices.vertices) > 0) // clockwise? remaining_vertices = vertices.vertices; else for (int v = 0; v < n_vertices; v++) remaining_vertices[v] = vertices.vertices[n_vertices - 1 - v]; // Avoid closed loops. if (remaining_vertices.front () == remaining_vertices.back ()) remaining_vertices.erase (remaining_vertices.end () - 1); // null_iterations avoids infinite loops if the polygon is not simple. for (int u = static_cast<int> (remaining_vertices.size ()) - 1, null_iterations = 0; remaining_vertices.size () > 2 && null_iterations < static_cast<int >(remaining_vertices.size () * 2); ++null_iterations, u = (u+1) % static_cast<int> (remaining_vertices.size ())) { int v = (u + 1) % static_cast<int> (remaining_vertices.size ()); int w = (u + 2) % static_cast<int> (remaining_vertices.size ()); if (isEar (u, v, w, remaining_vertices)) { Vertices triangle; triangle.vertices.resize (3); triangle.vertices[0] = remaining_vertices[u]; triangle.vertices[1] = remaining_vertices[v]; triangle.vertices[2] = remaining_vertices[w]; output.polygons.push_back (triangle); remaining_vertices.erase (remaining_vertices.begin () + v); null_iterations = 0; } } }
void EarClippingTriangulation::clipEars() { std::list<size_t>::iterator it, prev, next; // *** clip an ear while (_vertex_list.size() > 3) { // pop ear from list 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 bool nfound(true); it = _vertex_list.begin(); prev = _vertex_list.end(); prev--; while (nfound && it != _vertex_list.end()) { if (*it == ear) { nfound = false; it = _vertex_list.erase(it); // remove ear tip next = it; if (next == _vertex_list.end()) { next = _vertex_list.begin(); prev = _vertex_list.end(); prev--; } // add triangle _triangles.push_back(GEOLIB::Triangle(_pnts, *prev, ear, *next)); // check the orientation of prevprev, prev, next std::list<size_t>::iterator prevprev; if (prev == _vertex_list.begin()) prevprev = _vertex_list.end(); else prevprev = prev; prevprev--; // apply changes to _convex_vertex_list and _ear_list looking "backward" MathLib::Orientation orientation = getOrientation(_pnts[*prevprev], _pnts[*prev], _pnts[*next]); if (orientation == CW) { BASELIB::uniqueListInsert(_convex_vertex_list, *prev); // prev is convex if (isEar(*prevprev, *prev, *next)) // prev is an ear tip BASELIB::uniqueListInsert(_ear_list, *prev); else // if necessary remove prev _ear_list.remove(*prev); } else { // prev is not convex => reflex or collinear _convex_vertex_list.remove(*prev); _ear_list.remove(*prev); if (orientation == COLLINEAR) { prev = _vertex_list.erase(prev); if (prev == _vertex_list.begin()) { prev = _vertex_list.end(); prev--; } else prev--; } } // check the orientation of prev, next, nextnext std::list<size_t>::iterator nextnext, help_it(_vertex_list.end()); help_it--; if (next == help_it) nextnext = _vertex_list.begin(); else { nextnext = next; nextnext++; } // apply changes to _convex_vertex_list and _ear_list looking "forward" orientation = getOrientation(_pnts[*prev], _pnts[*next], _pnts[*nextnext]); if (orientation == CW) { BASELIB::uniqueListInsert(_convex_vertex_list, *next); // next is convex if (isEar(*prev, *next, *nextnext)) // next is an ear tip BASELIB::uniqueListInsert(_ear_list, *next); else // if necessary remove *next _ear_list.remove(*next); } else { // next is not convex => reflex or collinear _convex_vertex_list.remove(*next); _ear_list.remove(*next); if (orientation == COLLINEAR) { next = _vertex_list.erase(next); if (next == _vertex_list.end()) next = _vertex_list.begin(); } } } else { prev = it; it++; } } } // add last triangle next = _vertex_list.begin(); prev = next; next++; it = next; next++; if (getOrientation(_pnts[*prev], _pnts[*it], _pnts[*next]) == CCW) _triangles.push_back(GEOLIB::Triangle(_pnts, *prev, *next, *it)); else _triangles.push_back(GEOLIB::Triangle(_pnts, *prev, *it, *next)); }
Graph <Point2D> EarClipper::triangulate(const Graph <Point2D> &arg, std::vector <Triangle2D> *triangles) { Graph <Point2D> result (arg); std::vector<bool> vertexStatus (arg.getVertexCount(), false); //1 - ear, 0 - not ear std::list<int> remainingVertices; short direction = determineDirection(arg); for (unsigned int i = 0; i < arg.getVertexCount(); ++i) { remainingVertices.push_back(i); } for (std::list<int>::iterator it = remainingVertices.begin(); it != remainingVertices.end(); ++it) { vertexStatus[*it] = isEar(arg, remainingVertices, it, direction); } std::list<int>::iterator currentVertex = remainingVertices.begin(); while (remainingVertices.size() > 3) { bool earFound = false; for (unsigned int i = remainingVertices.size(); i > 0 && remainingVertices.size() > 3; --i) { if (vertexStatus[*currentVertex] == 1) { earFound = true; addTriangle(result, remainingVertices, currentVertex, triangles); std::list<int>::iterator vertexToRemove = currentVertex; if (++currentVertex == remainingVertices.end()) { currentVertex = remainingVertices.begin(); } remainingVertices.erase(vertexToRemove); vertexStatus[*currentVertex] = isEar(arg, remainingVertices, currentVertex, direction); if (currentVertex == remainingVertices.begin()) { currentVertex = --remainingVertices.end(); } else { --currentVertex; } vertexStatus[*currentVertex] = isEar(arg, remainingVertices, currentVertex, direction); } else { if (++currentVertex == remainingVertices.end()) { currentVertex = remainingVertices.begin(); } } } if (!earFound) { result.connectVertices(); triangles->clear(); std::cerr << "Impossoble to triangulate\n"; return result; } } if (triangles != 0 && remainingVertices.size() == 3) { //add remains to triangulation triangles->push_back(Triangle2D(arg.getVertex(*remainingVertices.begin()), arg.getVertex(*++remainingVertices.begin()), arg.getVertex(*--remainingVertices.end()))); } if (triangles != 0) { if (validateTriangulation(arg, *triangles)) { std::cout << "Validation OK\n"; } else { std::cerr << "Validation failed\n"; } } return result; }