Esempio n. 1
0
//
// http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
list<Polygon> Triangulate(const Polygon& poly)
{
    int n = poly.points.size();
    int *verts = new int[n];
    list<Polygon> polys;

    for (int i = 0; i < n; i++) {
        verts[i] = i;
    }

    int remaining = n;
    int v = remaining - 1;
    int count = 2*remaining;

    while (remaining > 2) {
        if (count <= 0) {
            Debug("Failed to triangulate polygon");
            return {};
        }
        count--;

        int u, w;
        u = v;
        if (u >= remaining) u = 0;
        v = u + 1;
        if (v >= remaining) v = 0;
        w = v + 1;
        if (w >= remaining) w = 0;

        if (IsEar(poly, u, v, w, remaining, verts)) {
            int a, b, c;
            a = verts[u];
            b = verts[v];
            c = verts[w];

            Polygon tri;
            tri.points.push_back(poly[a]);
            tri.points.push_back(poly[b]);
            tri.points.push_back(poly[c]);
            polys.push_back(tri);

            for (int s = v, t = v + 1; t < remaining; s++, t++) {
                verts[s] = verts[t];
            }
            remaining--;

            count = 2 * remaining;
        }
    }

    delete [] verts;
    return polys;
}
void SContour::UvTriangulateInto(SMesh *m, SSurface *srf) {
    Vector tu, tv;
    srf->TangentsAt(0.5, 0.5, &tu, &tv);
    double s = sqrt(tu.MagSquared() + tv.MagSquared());
    // We would like to apply our tolerances in xyz; but that would be a lot
    // of work, so at least scale the epsilon semi-reasonably. That's
    // perfect for square planes, less perfect for anything else.
    double scaledEps = LENGTH_EPS / s;

    int i;
    // Clean the original contour by removing any zero-length edges.
    l.ClearTags();
    for(i = 1; i < l.n; i++) {
       if((l.elem[i].p).Equals(l.elem[i-1].p)) {
            l.elem[i].tag = 1;
        }
    }
    l.RemoveTagged();

    // Now calculate the ear-ness of each vertex
    for(i = 0; i < l.n; i++) {
        (l.elem[i]).ear = IsEar(i, scaledEps) ? SPoint::EAR : SPoint::NOT_EAR;
    }

    bool toggle = false;
    while(l.n > 3) {
        // Some points may have changed ear-ness, so recalculate
        for(i = 0; i < l.n; i++) {
            if(l.elem[i].ear == SPoint::UNKNOWN) {
                (l.elem[i]).ear = IsEar(i, scaledEps) ?
                                        SPoint::EAR : SPoint::NOT_EAR;
            }
        }

        int bestEar = -1;
        double bestChordTol = VERY_POSITIVE;
        // Alternate the starting position so we generate strip-like
        // triangulations instead of fan-like
        toggle = !toggle;
        int offset = toggle ? -1 : 0;
        for(i = 0; i < l.n; i++) {
            int ear = WRAP(i+offset, l.n);
            if(l.elem[ear].ear == SPoint::EAR) {
                if(srf->degm == 1 && srf->degn == 1) {
                    // This is a plane; any ear is a good ear.
                    bestEar = ear;
                    break;
                }
                // If we are triangulating a curved surface, then try to
                // clip ears that have a small chord tolerance from the
                // surface.
                Vector prev = l.elem[WRAP((i+offset-1), l.n)].p,
                       next = l.elem[WRAP((i+offset+1), l.n)].p;
                double tol = srf->ChordToleranceForEdge(prev, next);
                if(tol < bestChordTol - scaledEps) {
                    bestEar = ear;
                    bestChordTol = tol;
                }
                if(bestChordTol < 0.1*SS.ChordTolMm()) {
                    break;
                }
            }
        }
        if(bestEar < 0) {
            dbp("couldn't find an ear! fail");
            return;
        }
        ClipEarInto(m, bestEar, scaledEps);
    }

    ClipEarInto(m, 0, scaledEps); // add the last triangle
}
Esempio n. 3
0
TriangulateEC<Real>::TriangulateEC (int iQuantity,
    const Vector2<Real>* akPosition, Query::Type eQueryType, Real fEpsilon,
    int*& raiIndex)
{
    assert(iQuantity >= 3 && akPosition);
    if (eQueryType == Query::QT_FILTERED)
    {
        assert((Real)0.0 <= fEpsilon && fEpsilon <= (Real)1.0);
    }

    Vector2<Real>* akSPosition = 0;
    Vector2<Real> kMin, kMax, kRange;
    Real fScale;
    int i;

    switch (eQueryType)
    {
    case Query::QT_INT64:
        // Transform the vertices to the square [0,2^{20}]^2.
        Vector2<Real>::ComputeExtremes(iQuantity,akPosition,kMin,kMax);
        kRange = kMax - kMin;
        fScale = (kRange[0] >= kRange[1] ? kRange[0] : kRange[1]);
        fScale *= (Real)(1 << 20);
        akSPosition = WM4_NEW Vector2<Real>[iQuantity];
        for (i = 0; i < iQuantity; i++)
        {
            akSPosition[i] = (akPosition[i] - kMin)*fScale;
        }
        m_pkQuery = WM4_NEW Query2Int64<Real>(iQuantity,akSPosition);
        break;
    case Query::QT_INTEGER:
        // Transform the vertices to the square [0,2^{24}]^2.
        Vector2<Real>::ComputeExtremes(iQuantity,akPosition,kMin,kMax);
        kRange = kMax - kMin;
        fScale = (kRange[0] >= kRange[1] ? kRange[0] : kRange[1]);
        fScale *= (Real)(1 << 24);
        akSPosition = WM4_NEW Vector2<Real>[iQuantity];
        for (i = 0; i < iQuantity; i++)
        {
            akSPosition[i] = (akPosition[i] - kMin)*fScale;
        }
        m_pkQuery = WM4_NEW Query2TInteger<Real>(iQuantity,akSPosition);
        break;
    case Query::QT_REAL:
        // Transform the vertices to the square [0,1]^2.
        Vector2<Real>::ComputeExtremes(iQuantity,akPosition,kMin,kMax);
        kRange = kMax - kMin;
        fScale = (kRange[0] >= kRange[1] ? kRange[0] : kRange[1]);
        akSPosition = WM4_NEW Vector2<Real>[iQuantity];
        for (i = 0; i < iQuantity; i++)
        {
            akSPosition[i] = (akPosition[i] - kMin)*fScale;
        }
        m_pkQuery = WM4_NEW Query2<Real>(iQuantity,akSPosition);
        break;
    case Query::QT_RATIONAL:
        // No transformation of the input data.
        m_pkQuery = WM4_NEW Query2TRational<Real>(iQuantity,akPosition);
        break;
    case Query::QT_FILTERED:
        // No transformation of the input data.
        m_pkQuery = WM4_NEW Query2Filtered<Real>(iQuantity,akPosition,
            fEpsilon);
        break;
    }

    int iQm1 = iQuantity - 1;
    raiIndex = WM4_NEW int[3*iQm1];
    int* piIndex = raiIndex;

    m_akVertex = WM4_NEW Vertex[iQuantity];
    m_iCFirst = -1;
    m_iCLast = -1;
    m_iRFirst = -1;
    m_iRLast = -1;
    m_iEFirst = -1;
    m_iELast = -1;

    // Create a circular list of the polygon vertices for dynamic removal of
    // vertices.  Keep track of two linear sublists, one for the convex
    // vertices and one for the reflex vertices.  This is an O(N) process
    // where N is the number of polygon vertices.
    for (i = 0; i <= iQm1; i++)
    {
        // link the vertices
        Vertex& rkV = V(i);
        rkV.VPrev = (i > 0 ? i-1 : iQm1);
        rkV.VNext = (i < iQm1 ? i+1 : 0);

        // link the convex/reflex vertices
        if (IsConvex(i))
        {
            InsertAfterC(i);
        }
        else
        {
            InsertAfterR(i);
        }
    }

    if (m_iRFirst == -1)
    {
        // polygon is convex, just triangle fan it
        for (i = 1; i < iQm1; i++)
        {
            *piIndex++ = 0;
            *piIndex++ = i;
            *piIndex++ = i+1;
        }
        return;
    }

    // Identify the ears and build a circular list of them.  Let V0, V1, and
    // V2 be consecutive vertices forming a triangle T.  The vertex V1 is an
    // ear if no other vertices of the polygon lie inside T.  Although it is
    // enough to show that V1 is not an ear by finding at least one other
    // vertex inside T, it is sufficient to search only the reflex vertices.
    // This is an O(C*R) process where C is the number of convex vertices and
    // R is the number of reflex vertices, N = C+R.  The order is O(N^2), for
    // example when C = R = N/2.
    for (i = m_iCFirst; i != -1; i = V(i).SNext)
    {
        if (IsEar(i))
        {
            InsertEndE(i);
        }
    }
    V(m_iEFirst).EPrev = m_iELast;
    V(m_iELast).ENext = m_iEFirst;

    // Remove the ears, one at a time.
    while (true)
    {
        // add triangle of ear to output
        int iVPrev = V(m_iEFirst).VPrev;
        int iVNext = V(m_iEFirst).VNext;
        *piIndex++ = iVPrev;
        *piIndex++ = m_iEFirst;
        *piIndex++ = iVNext;

        // remove the vertex corresponding to the ear
        RemoveV(m_iEFirst);
        if (--iQuantity == 3)
        {
            // Only one triangle remains, just remove the ear and copy it.
            RemoveE();
            iVPrev = V(m_iEFirst).VPrev;
            iVNext = V(m_iEFirst).VNext;
            *piIndex++ = iVPrev;
            *piIndex++ = m_iEFirst;
            *piIndex++ = iVNext;
            break;
        }

        // removal of the ear can cause an adjacent vertex to become an ear
        bool bWasReflex;

        Vertex& rkVPrev = V(iVPrev);
        if (!rkVPrev.IsEar)
        {
            bWasReflex = !rkVPrev.IsConvex;
            if (IsConvex(iVPrev))
            {
                if (bWasReflex)
                {
                    RemoveR(iVPrev);
                }

                if (IsEar(iVPrev))
                {
                    InsertBeforeE(iVPrev);
                }
            }
        }

        Vertex& rkVNext = V(iVNext);
        if (!rkVNext.IsEar)
        {
            bWasReflex = !rkVNext.IsConvex;
            if (IsConvex(iVNext))
            {
                if (bWasReflex)
                {
                    RemoveR(iVNext);
                }

                if (IsEar(iVNext))
                {
                    InsertAfterE(iVNext);
                }
            }
        }

        // remove the ear
        RemoveE();
    }

    WM4_DELETE[] akSPosition;
    WM4_DELETE m_pkQuery;
}