Beispiel #1
0
void TriangleMesh::buildAdjacency()
{
    int nPruned = pruneInvalidFaces( m_edgeToFace );

    int nFaces = numFaces();

    // walk over all faces
    // and build an adjacency map:
    // edge -> adjacent face
    // if nothing was pruned, then it's already valid
    if( nPruned != 0 )
    {
        m_edgeToFace.clear();

        for( int f = 0; f < nFaces; ++f )
        {
            Vector3i face = m_faces[ f ];

            Vector2i e0 = face.xy;
            Vector2i e1 = face.yz;
            Vector2i e2 = face.zx();

            m_edgeToFace[ e0 ] = f;
            m_edgeToFace[ e1 ] = f;
            m_edgeToFace[ e2 ] = f;
        }
    }

    // build face to face adjacency
    // for each face:
    //    find 3 edges
    //    flip edge: if the flipped edge has an adjacent face
    //       add it as a neighbor of this face
    m_faceToFace.clear();
    m_faceToFace.resize( nFaces );
    for( int f = 0; f < nFaces; ++f )
    {
        Vector3i face = m_faces[ f ];
        // get 3 edge twins
        Vector2i e0t = face.yx();
        Vector2i e1t = face.zy();
        Vector2i e2t = face.xz();

        if( m_edgeToFace.find( e0t ) != m_edgeToFace.end() )
        {
            m_faceToFace[ f ].push_back( m_edgeToFace[ e0t ] );
        }
        if( m_edgeToFace.find( e1t ) != m_edgeToFace.end() )
        {
            m_faceToFace[ f ].push_back( m_edgeToFace[ e1t ] );
        }
        if( m_edgeToFace.find( e2t ) != m_edgeToFace.end() )
        {
            m_faceToFace[ f ].push_back( m_edgeToFace[ e2t ] );
        }
    }

    // build edge to next edge adjacency
    // iterate over all faces
    m_edgeToPrevEdge.clear();
    m_edgeToNextEdge.clear();
    for( int f = 0; f < nFaces; ++f )
    {
        Vector3i face = m_faces[ f ];

        Vector2i e0 = face.xy;
        Vector2i e1 = face.yz;
        Vector2i e2 = face.zx();

        m_edgeToPrevEdge[ e0 ] = e2;
        m_edgeToPrevEdge[ e1 ] = e0;
        m_edgeToPrevEdge[ e2 ] = e1;

        m_edgeToNextEdge[ e0 ] = e1;
        m_edgeToNextEdge[ e1 ] = e2;
        m_edgeToNextEdge[ e2 ] = e0;
    }

    // build vertex to outgoing edge adjacency
    int nVertices = numVertices();
    m_vertexToOutgoingEdge.clear();
    m_vertexToOutgoingEdge.resize( nVertices );
    for( int f = 0; f < nFaces; ++f )
    {
        Vector3i face = m_faces[ f ];
        m_vertexToOutgoingEdge[ face[0] ] = face[ 1 ];
        m_vertexToOutgoingEdge[ face[1] ] = face[ 2 ];
        m_vertexToOutgoingEdge[ face[2] ] = face[ 0 ];
    }

    // build vertex to vertex (one-ring neighborhoods)
    // for each vertex v
    //   start with initial outgoing edge
    //   next edge = edge->next->next->twin
    m_oneRingIsClosed.clear();
    m_vertexToVertex.clear();
    m_vertexToFace.clear();
    m_oneRingIsClosed.resize( nVertices );
    m_vertexToVertex.resize( nVertices );
    m_vertexToFace.resize( nVertices );
    for( int v = 0; v < nVertices; ++v )
    {
        Vector2i initialOutgoingEdge{ v, m_vertexToOutgoingEdge[ v ] };

        m_vertexToVertex[ v ].push_back( initialOutgoingEdge.y );
        m_vertexToFace[ v ].push_back( m_edgeToFace[ initialOutgoingEdge ] );

        Vector2i nextIncomingEdge = m_edgeToNextEdge[ m_edgeToNextEdge[ initialOutgoingEdge ] ];
        Vector2i nextOutgoingEdge = nextIncomingEdge.yx();

        while( !( isBoundaryEdge( nextIncomingEdge ) ) &&
            nextOutgoingEdge != initialOutgoingEdge )
        {
            m_vertexToVertex[ v ].push_back( nextIncomingEdge.x );
            m_vertexToFace[ v ].push_back( m_edgeToFace[ nextOutgoingEdge ] );

            nextIncomingEdge = m_edgeToNextEdge[ m_edgeToNextEdge[ nextOutgoingEdge ] ];
            nextOutgoingEdge = nextIncomingEdge.yx();
        }

        // if we looped around, great, we're done
        // otherwise, we hit a boundary, need to go the other way around!
        if( isBoundaryEdge( nextIncomingEdge ) )
        {
            m_oneRingIsClosed[ v ] = false;

            // don't forget to push on the last vertex
            m_vertexToVertex[ v ].push_back( nextIncomingEdge.x );
            // no face

            // check that the initial outgoing edge is not a boundary
            // (otherwise we're done)

            if( isBoundaryEdge( initialOutgoingEdge ) )
            {
                continue;
            }

            // flip orientation: start from the initial outgoing edge
            // and go clockwise, pushing to the front
            Vector2i initialIncomingEdge = initialOutgoingEdge.yx();

            nextOutgoingEdge = m_edgeToNextEdge[ initialIncomingEdge ];
            nextIncomingEdge = nextOutgoingEdge.yx();
            while( !( isBoundaryEdge( nextOutgoingEdge ) ) )
            {
                m_vertexToVertex[ v ].push_front( nextOutgoingEdge.y );
                m_vertexToFace[ v ].push_front( m_edgeToFace[ nextOutgoingEdge ] );

                nextOutgoingEdge = m_edgeToNextEdge[ nextIncomingEdge ];
                nextIncomingEdge = nextOutgoingEdge.yx();
            }

            // don't forget the last vertex
            m_vertexToVertex[ v ].push_front( nextOutgoingEdge.y );
            m_vertexToFace[ v ].push_front( m_edgeToFace[ nextOutgoingEdge ] );
        }
        else
        {
            m_oneRingIsClosed[ v ] = true;
        }
    }
}
Beispiel #2
0
int TriangleMesh::pruneInvalidFaces( std::map< Vector2i, int >& edgeToFace )
{
    // walk over all faces
    // build for each edge (v0,v1)
    //   edgeToFace[ v0, v1 ] = face
    //   if it already exists, we have a problem
    //   and we will throw the face away

    int nFaces = numFaces();
    edgeToFace.clear();
    //edgeToFace.reserve( 3 * nFaces );
    std::vector< Vector3i > validFaces;
    validFaces.reserve( nFaces );

    //ProgressReporter pr( "Pruning invalid faces", nFaces );

    int nPruned = 0;
    for( int f = 0; f < nFaces; ++f )
    {
        Vector3i face = m_faces[ f ];

        Vector2i e0 = face.xy;
        Vector2i e1 = face.yz;
        Vector2i e2 = face.zx();

        if( edgeToFace.find( e0 ) == edgeToFace.end() &&
            edgeToFace.find( e1 ) == edgeToFace.end() &&
            edgeToFace.find( e2 ) == edgeToFace.end() )
        {
            edgeToFace[ e0 ] = f;
            edgeToFace[ e1 ] = f;
            edgeToFace[ e2 ] = f;
            validFaces.push_back( face );
        }
        else
        {
            ++nPruned;

            fprintf( stderr, "Found invalid face: (%d, %d, %d)\n",
                face.x, face.y, face.z );

            if( edgeToFace.find( e0 ) != edgeToFace.end() )
            {
                Vector3i existingFace = m_faces[ edgeToFace[ e0 ] ];
                fprintf( stderr, "Existing face: (%d, %d, %d)\n",
                    existingFace.x, existingFace.y, existingFace.z );
            }
            if( edgeToFace.find( e1 ) != edgeToFace.end() )
            {
                Vector3i existingFace = m_faces[ edgeToFace[ e1 ] ];
                fprintf( stderr, "Existing face: (%d, %d, %d)\n",
                    existingFace.x, existingFace.y, existingFace.z );
            }
            if( edgeToFace.find( e2 ) != edgeToFace.end() )
            {
                Vector3i existingFace = m_faces[ edgeToFace[ e2 ] ];
                fprintf( stderr, "Existing face: (%d, %d, %d)\n",
                    existingFace.x, existingFace.y, existingFace.z );
            }
        }

        //pr.notifyAndPrintProgressString();
    }
    if( nPruned > 0 )
    {
        fprintf( stderr, "Pruned %d faces\n", nPruned );
        m_faces = validFaces;
    }

    return nPruned;
}