void SHAPE_POLY_SET::importTree( PolyTree* tree)
{
    m_polys.clear();

    for( PolyNode* n = tree->GetFirst(); n; n = n->GetNext() )
    {
        if( !n->IsHole() )
        {
            POLYGON paths;
            paths.push_back( convertFromClipper( n->Contour ) );

            for( unsigned int i = 0; i < n->Childs.size(); i++ )
                paths.push_back( convertFromClipper( n->Childs[i]->Contour ) );

            m_polys.push_back(paths);
        }
    }
}
示例#2
0
    void triangulate(const Polygon& inputPoly, std::vector<Mesh>& outputMeshes)
    {
        // Use Clipper to ensure strictly simple polygons
        using namespace ClipperLib;
        Clipper clipper;
        clipper.StrictlySimple(true);

        try
        {
            clipper.AddPaths(polyToClipperPaths(inputPoly), ptSubject, true);
        }
        catch (...)
        {
            std::cerr << "Error in Clipper::AddPaths" << std::endl;
            return;
        }

        PolyTree polyTree;
        clipper.Execute(ctUnion, polyTree, pftNonZero, pftNonZero);

        // Traverse the PolyTree nodes and triangulate them with only their children holes
        PolyNode *currentNode = polyTree.GetFirst();
        while(currentNode != NULL)
        {
            // The holes are only used as the children of the contours
            if (currentNode->IsHole())
            {
                currentNode = currentNode->GetNext();
                continue;
            }

            // Convert to poly2tri's format
            std::vector<p2t::Point> allPoints;
            std::vector<size_t> linesSizes;

            // Contour
            for (const auto& pt : currentNode->Contour)
                allPoints.emplace_back(static_cast<double>(pt.X), static_cast<double>(pt.Y));
            linesSizes.push_back(allPoints.size());

            // Holes
            for(const auto childNode : currentNode->Childs)
            {
                // Slightly modify the polygon to guarantee no duplicate points
                edgeShrink(childNode->Contour);

                for (const auto& pt : childNode->Contour)
                    allPoints.emplace_back(static_cast<double>(pt.X), static_cast<double>(pt.Y));
                linesSizes.push_back(allPoints.size());
            }

            // Poly2Tri uses pointers to points
            std::vector<p2t::Point*> contourLine;
            std::vector<std::vector<p2t::Point*>> holes;

            auto nbLines = linesSizes.size();
            size_t start = 0;
            for (size_t i = 0; i < nbLines; ++i)
            {
                size_t end = linesSizes[i];
                std::vector<p2t::Point*> line;
                line.reserve(end - start);
                for (size_t j = start; j < end; ++j)
                    line.push_back(&allPoints[j]);
                start = end;

                if (!i) contourLine = std::move(line);
                else	holes.push_back(std::move(line));
            }

            // Set the contour in poly2tri
            p2t::CDT cdt(contourLine);

            // Add the holes
            for(auto& hole : holes)
                cdt.AddHole(hole);

            // Do the actual triangulation
            cdt.Triangulate();

            // Downscale the points and add them to the mesh
            Mesh mesh;
            for (const auto pt : allPoints)
                mesh.addPoint(convert(pt));

            // Convert the triangles
            auto triangles = cdt.GetTriangles();
            auto firstPt = allPoints.data();
            for (const auto triangle : triangles)
            {
                int ptId1 = std::distance(firstPt, triangle->GetPoint(0));
                int ptId2 = std::distance(firstPt, triangle->GetPoint(1));
                int ptId3 = std::distance(firstPt, triangle->GetPoint(2));
                mesh.addTriangle(ptId1, ptId2, ptId3);
            }
            outputMeshes.push_back(mesh);

            currentNode = currentNode->GetNext();
        }
    }