//----------------------------------------------------------------------- // note : input must not contain cutting segment void Triangulator::triangulatePolygon(const std::vector<int>& input, const DelaunaySegment& seg, DelaunayTriangleBuffer& tbuffer, const PointList& pointList) { // Find a point which, when associated with seg.i1 and seg.i2, builds a Delaunay triangle std::vector<int>::const_iterator currentPoint = input.begin(); bool found = true; while (!found) { Circle c(pointList[*currentPoint], pointList[seg.i1], pointList[seg.i2]); for (std::vector<int>::const_iterator it = input.begin();it!=input.end();it++) { if (c.isPointInside(pointList[*it]) ) { currentPoint = it; break; } } found = true; } // Insert current triangle Triangle t(&pointList, tbuffer.end()); t.setVertices(*currentPoint, seg.i1, seg.i2); tbuffer.push_back(t); // Recurse std::vector<int> part1(input.begin(), currentPoint-1); if (!part1.empty()) triangulatePolygon(part1, seg, tbuffer, pointList); std::vector<int> part2(currentPoint+1, input.end()); if (!part2.empty()) triangulatePolygon(part2, seg, tbuffer, pointList); }
void CreateHexCore::createBoundaryFaces() { EG_VTKSP(vtkUnstructuredGrid, new_grid); // find all polygons which need to be triangulated and collect the new triangles m_Part.setAllCells(); QList<QVector<vtkIdType> > new_triangles; QVector<bool> adapt_cell(m_Grid->GetNumberOfCells(), false); for (vtkIdType id_cell = 0; id_cell < m_Grid->GetNumberOfCells(); ++id_cell) { vec3_t xc = cellCentre(m_Grid, id_cell); if (isVolume(id_cell, m_Grid)) { for (int i = 0; i < m_Part.c2cGSize(id_cell); ++i) { if (m_Part.c2cGG(id_cell, i) == -1) { QVector<vtkIdType> face; getFaceOfCell(m_Grid, id_cell, i, face); QVector<QVector<vtkIdType> > triangles; triangulatePolygon(m_Grid, face, triangles); foreach (QVector<vtkIdType> triangle, triangles) { vec3_t x1, x2, x3; m_Grid->GetPoint(triangle[0], x1.data()); m_Grid->GetPoint(triangle[1], x2.data()); m_Grid->GetPoint(triangle[2], x3.data()); vec3_t xt = (1.0/3.0)*(x1 + x2 + x3); vec3_t nt = GeometryTools::triNormal(x1, x2, x3); if (nt*(xt - xc) < 0) { swap(triangle[0], triangle[1]); } new_triangles.append(triangle); } if (face.size() > 3) { adapt_cell[id_cell] = true; } } } }
void PolygonNode::calcFillVertexes(const VertexDataPtr& pVertexData, Pixel32 color) { if (getNumDifferentPts(m_Pts) < 3) { return; } // Remove duplicate points vector<glm::vec2> pts; vector<unsigned int> holeIndexes; pts.reserve(m_Pts.size()); if (glm::distance2(m_Pts[0], m_Pts[m_Pts.size()-1]) > 0.1) { pts.push_back(m_Pts[0]); } for (unsigned i = 1; i < m_Pts.size(); ++i) { if (glm::distance2(m_Pts[i], m_Pts[i-1]) > 0.1) { pts.push_back(m_Pts[i]); } } if (m_Holes.size() > 0) { for (unsigned int i = 0; i < m_Holes.size(); i++) { //loop over collection holeIndexes.push_back(pts.size()); for (unsigned int j = 0; j < m_Holes[i].size(); j++) { //loop over vector pts.push_back(m_Holes[i][j]); } } } if (color.getA() > 0) { glm::vec2 minCoord = pts[0]; glm::vec2 maxCoord = pts[0]; for (unsigned i = 1; i < pts.size(); ++i) { if (pts[i].x < minCoord.x) { minCoord.x = pts[i].x; } if (pts[i].x > maxCoord.x) { maxCoord.x = pts[i].x; } if (pts[i].y < minCoord.y) { minCoord.y = pts[i].y; } if (pts[i].y > maxCoord.y) { maxCoord.y = pts[i].y; } } vector<unsigned int> triIndexes; triangulatePolygon(triIndexes, pts, holeIndexes); for (unsigned i = 0; i < pts.size(); ++i) { glm::vec2 texCoord = calcFillTexCoord(pts[i], minCoord, maxCoord); pVertexData->appendPos(pts[i], texCoord, color); } for (unsigned i = 0; i < triIndexes.size(); i+=3) { pVertexData->appendTriIndexes(triIndexes[i], triIndexes[i+1], triIndexes[i+2]); } } }
void ConcaveShape::ensureDecomposed() const { if (!mNeedsDecomposition) return; // Split the concave polygon into convex triangles triangulatePolygon(mPoints.begin(), mPoints.end(), TriangleGenerator(mTriangleVertices, mFillColor)); mNeedsDecomposition = false; }
// ---------------------------------------------------- void SpotsScene::addPoints() { pts.clear(); for(int i=0; i<6; i++) { float x = ofRandom(10, CUBE_SCREEN_WIDTH-10); float y = ofRandom(10, CUBE_SCREEN_HEIGHT-10); pts.push_back(ofVec2f(x, y)); } tris = triangulatePolygon(pts); }
/** * @see testBurnTrianglePolygonAndTriangulateResult1() * * В треугольнике делается две неперекрывающиеся дыры. */ void testBurnTrianglePolygonAndTriangulateResult2() { // Треугольник polygon_t tri; bg::append( tri, bg::make< p_t >( 0.0, 0.0 ) ); bg::append( tri, bg::make< p_t >( 0.0, 100.0 ) ); bg::append( tri, bg::make< p_t >( 100.0, 0.0 ) ); bg::correct( tri ); cout << "Треугольник: " << bg::dsv( tri ) << endl; // Кольцо 1 внутри треугольника polygon_t ring1; bg::append( ring1, bg::make< p_t >( 10.0, 10.0 ) ); bg::append( ring1, bg::make< p_t >( 10.0, 50.0 ) ); bg::append( ring1, bg::make< p_t >( 20.0, 50.0 ) ); bg::append( ring1, bg::make< p_t >( 20.0, 10.0 ) ); bg::correct( ring1 ); cout << "Кольцо 1 внутри треугольника (дыра): " << bg::dsv( ring1 ) << endl; // Кольцо 2 внутри треугольника, не перекрывает кольцо 1 polygon_t ring2; bg::append( ring2, bg::make< p_t >( 1.0, 1.0 ) ); bg::append( ring2, bg::make< p_t >( 1.0, 5.0 ) ); bg::append( ring2, bg::make< p_t >( 2.0, 5.0 ) ); bg::append( ring2, bg::make< p_t >( 2.0, 2.0 ) ); bg::correct( ring2 ); cout << "Кольцо 2 внутри треугольника (дыра): " << bg::dsv( ring2 ) << endl; assert( !bg::intersects( ring1, ring2) && "Кольца не должны пересекаться." ); cout << endl << "Выжигаем в треугольнике дыру по форме кольца 1." << endl; std::vector< polygon_t > figure; bg::difference( tri, ring1, figure ); assert( (figure.size() == 1) && "Должен получиться 1 полигон." ); cout << endl << "Выжигаем в треугольнике дыру по форме кольца 2." << endl; polygon_t firstPoly = *figure.cbegin(); figure.clear(); bg::difference( firstPoly, ring2, figure ); assert( (figure.size() == 1) && "Должен получиться 1 полигон." ); cout << endl << "Полигонов после выжигания 2 дыр: " << figure.size() << endl; for (auto itr = figure.cbegin(); itr != figure.cend(); ++itr) { cout << "Полигон " << bg::dsv( *itr ) << endl; } // Отдаём полученную фигуру на триангуляцию firstPoly = *figure.cbegin(); const std::vector< triangle_t > r = triangulatePolygon( firstPoly ); assert( (r.size() > 1) && "Должно получиться много треугольников." ); }
void PolygonBuilder::triangulate(const std::vector<float>& verts, std::vector<GLuint>& triangleInds) { if (!m_valid) return; if (m_outerRingInds.size() == 3 && m_innerRingSizes.empty()) { // Already a triangle - nothing to do. for (int i = 0; i < 3; ++i) triangleInds.push_back(m_outerRingInds[i]); return; } triangulatePolygon(verts, m_outerRingInds, m_innerRingSizes, m_innerRingInds, triangleInds); }
/** * Пересечение треугольника и кольца (полигон без дырок). Кольцо много * меньше треугольника и лежит внутри треугольника, прожигая в нём дыру. * После вычисления фигуры пересечения делаем её триангуляцию. */ void testBurnTrianglePolygonAndTriangulateResult1() { // Треугольник /* triangle_t tri( bg::make< p_t >( 0.0, 0.0 ), bg::make< p_t >( 0.0, 100.0 ), bg::make< p_t >( 100.0, 0.0 ) ); */ polygon_t tri; bg::append( tri, bg::make< p_t >( 0.0, 0.0 ) ); bg::append( tri, bg::make< p_t >( 0.0, 100.0 ) ); bg::append( tri, bg::make< p_t >( 100.0, 0.0 ) ); bg::correct( tri ); cout << "Треугольник: " << bg::dsv( tri ) << endl; // Кольцо внутри треугольника polygon_t ring; bg::append( ring, bg::make< p_t >( 10.0, 10.0 ) ); bg::append( ring, bg::make< p_t >( 10.0, 50.0 ) ); bg::append( ring, bg::make< p_t >( 20.0, 50.0 ) ); bg::append( ring, bg::make< p_t >( 20.0, 10.0 ) ); bg::correct( ring ); cout << "Кольцо внутри треугольника (дыра): " << bg::dsv( ring ) << endl; cout << endl << "Выжигаем в треугольнике дыру по форме кольца." << endl << endl; // @see http://www.boost.org/doc/libs/1_47_0/libs/geometry/doc/html/geometry/reference/algorithms/difference.html std::vector< polygon_t > figure; bg::difference( tri, ring, figure ); cout << endl << "Полигонов после выжигания дыры: " << figure.size() << endl; for (auto itr = figure.cbegin(); itr != figure.cend(); ++itr) { cout << "Полигон " << bg::dsv( *itr ) << endl; } assert( (figure.size() == 1) && "Должен получиться 1 полигон." ); // Отдаём полученную фигуру на триангуляцию polygon_t firstPoly = *figure.cbegin(); const std::vector< triangle_t > r = triangulatePolygon( firstPoly ); assert( (r.size() > 1) && "Должно получиться много треугольников." ); }
/** * @see testBurnTrianglePolygonAndTriangulateResult1() * * В треугольнике делается дыра, делающая из него вогнутый полигон. */ void testBurnTrianglePolygonAndTriangulateResult3() { // Треугольник polygon_t tri; bg::append( tri, bg::make< p_t >( 0.0, 0.0 ) ); bg::append( tri, bg::make< p_t >( 0.0, 100.0 ) ); bg::append( tri, bg::make< p_t >( 100.0, 0.0 ) ); bg::correct( tri ); cout << "Треугольник: " << bg::dsv( tri ) << endl; // Кольцо, часть - внутри треугольника, часть - снаружи polygon_t ring; bg::append( ring, bg::make< p_t >( -5.0, -5.0 ) ); bg::append( ring, bg::make< p_t >( -5.0, 50.0 ) ); bg::append( ring, bg::make< p_t >( 20.0, 50.0 ) ); bg::append( ring, bg::make< p_t >( 20.0, -5.0 ) ); bg::correct( ring ); cout << "Кольцо выбивает часть треугольника: " << bg::dsv( ring ) << endl; //assert( bg::overlaps( tri, ring ) && "Треугольник и кольцо должны частично перекрывать друг друга." ); //assert( bg::intersects( tri, ring ) && !bg::within( ring, tri ) && "Треугольник и кольцо должны частично перекрывать друг друга." ); cout << endl << "Выбиваем в треугольнике часть по форме кольца." << endl << endl; std::vector< polygon_t > figure; bg::difference( tri, ring, figure ); cout << endl << "Полигонов после выбивания: " << figure.size() << endl; for (auto itr = figure.cbegin(); itr != figure.cend(); ++itr) { cout << "Полигон " << bg::dsv( *itr ) << endl; } assert( (figure.size() == 1) && "Должен получиться 1 полигон." ); // Отдаём вогнутый полигон на триангуляцию polygon_t firstPoly = *figure.cbegin(); assert( (firstPoly.inners().size() == 0) && "Фигура должна быть с выбоиной, но без дыры." ); const std::vector< triangle_t > r = triangulatePolygon( firstPoly ); assert( (r.size() > 1) && "Должно получиться много треугольников." ); }
void PHBezierPath::rebuildVAO(PHGLVertexArrayObject * vao, const PHRect & texCoord) { const vector<anchorPoint> * a = tesselate(calculatedVertices()); size_t nVertices; GLfloat * r = vertexDataFromAnchorList(*a, texCoord, nVertices); delete a; vao->bindToEdit(); PHGLVBO * vbo = vao->attributeVBO(PHIMAGEATTRIBUTE_POS); if (!vbo) vbo = new PHGLVertexBufferObject(vao->gameManager()); else vbo->retain(); vbo->bindTo(PHGLVBO::arrayBuffer); vbo->setData(NULL, nVertices*4*sizeof(GLfloat), PHGLVBO::dynamicDraw); vbo->setSubData(r, 0, nVertices*4*sizeof(GLfloat)); vao->vertexPointer(PHIMAGEATTRIBUTE_POS, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 0, vbo); vao->vertexPointer(PHIMAGEATTRIBUTE_TXC, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 2*sizeof(GLfloat), vbo); vbo->unbind(); vbo->release(); size_t nIndexes; GLushort * indexes = triangulatePolygon(r, 4, nVertices, nIndexes); delete r; PHGLVBO * ivbo = vao->elementArrayVBO(); if (!ivbo) ivbo = new PHGLVertexBufferObject(vao->gameManager()); else ivbo->retain(); ivbo->bindTo(PHGLVBO::elementArrayBuffer); ivbo->setData(indexes, nIndexes*sizeof(GLushort), PHGLVBO::dynamicDraw); vao->setDrawElements(GL_TRIANGLES, nIndexes, GL_UNSIGNED_SHORT, 0); ivbo->release(); delete indexes; vao->unbind(); }
void LcpFinder::triangulate(int polygon) { if (this->triangulated[polygon]) { return; } this->triangulated[polygon] = true; auto points = this->polygons.at(polygon); std::vector<Triangle*> newTriangles = triangulatePolygon(points, polygon); int nodecount = 0; for (auto ring : points) { nodecount += ring.size(); } for (int i = 0; i < newTriangles.size(); i++) { //std::cout<<"i"<<i<<std::endl; Triangle* newTri = newTriangles[i]; for (int n = 0; n < 3; n++) { if (newTri->neighbours[n] == nullptr) { const Coords* lb = newTri->points[(n + 2) % 3]; const Coords* rb = newTri->points[(n + 1) % 3]; double d = eucDistance(lb, rb); if (d>this->maxDist) { //std::cout << "intermediate points between" << lb->toString() << rb->toString(); //std::cout << newTri; int toAdd = std::ceil(d / this->maxDist) - 1; //std::cout << "adding: " << toAdd << std::endl; //std::cout<<"toAdd: "<<toAdd<<std::endl; for (int i = 1; i <= toAdd; i++) { double x{((rb->getX() - lb->getX()) / (toAdd + 1)) * i + lb->getX()}; double y{((rb->getY() - lb->getY()) / (toAdd + 1)) * i + lb->getY()}; std::pair < std::tr1::unordered_set<Coords, CoordsHasher>::iterator, bool> success = this->coordmap.insert(Coords{x, y, polygon, false}); const Coords* intermediate = &*success.first; intermediate->addToPolygon(polygon); //std::cout << intermediate->toString(); newTri->interiorPoints.push_back(intermediate); const Coords* thirdCorner = newTri->points[n]; Triangle* t1 = new Triangle{}; t1->points[0] = intermediate; t1->points[1] = thirdCorner; t1->points[2] = rb; Triangle* t2 = new Triangle{}; t2->points[0] = intermediate; t2->points[1] = lb; t2->points[2] = thirdCorner; t1->neighbours[2] = t2; t1->neighbours[0] = newTri->neighbours[(n + 2) % 3]; t2->neighbours[1] = t1; t2->neighbours[0] = newTri->neighbours[(n + 1) % 3]; for (const Coords* interior : newTri->interiorPoints) { if (coordsInTriangle(t1, interior)) { t1->interiorPoints.push_back(interior); } if (coordsInTriangle(t2, interior)) { t2->interiorPoints.push_back(interior); } } checkTargets(polygon, t1); //change to using old triangle interior points to make faster checkTargets(polygon, t2); intermediate->addTriangle(t1, polygon); intermediate->addTriangle(t2, polygon); } } } } if (coordsInTriangle(newTri, this->startPoint)) { subTriangles(newTri, polygon, this->startPoint); } this->checkTargets(polygon, newTri); this->checkLinear(polygon, newTri, true); } }
//---------------------------------------- void ofxBox2dPolygon::triangulate() { vector <ofxVec2f> orgPts = vertices; vertices = triangulatePolygon(vertices); bIsTriangulated = true; }