Exemplo n.º 1
0
void CPUSideTriangleMesh::generateSmoothingGroups(float maxSmoothAngle,
                                                  bool  regenerateNormals,
                                                  bool  regenerateAdjacency)
{
    if (regenerateNormals) {
        generateFaceNormals();
    }

    if (regenerateAdjacency) {
        generateFaceAdjacency();
    }

    // split faces
    float                 cSMAngle = cos(maxSmoothAngle);
    unsigned              smGroup  = 0;
    std::vector<unsigned> faceSMGroup(getNumFaces(), 0);
    //std::vector<unsigned> smGroupRepresentative(1);
    for (unsigned iFace = 0; iFace < getNumFaces(); ++iFace)
    {
        // sm group for face already set
        if (faceSMGroup[iFace] != 0) {
            continue;
        }

        // make new smoothing group
        faceSMGroup[iFace] = ++smGroup;
        //smGroupRepresentative.push_back(iFace);

        // run DFS to gather faces belonging to same smoothing group
        std::stack<unsigned> toVisit; toVisit.push(iFace);
        while ( !toVisit.empty() ) 
        {
            unsigned        curFace  = toVisit.top(); toVisit.pop();
            const unsigned* adjFaces = getAdjacentFaces(curFace);
            for (unsigned i = 0; i<getNumAdjacentFaces(curFace); ++i)
            {
                // if angle between normals is less than maxSmoothAngle put adjacent face into same smoothing group
                unsigned adjFace = adjFaces[i];
                if ( faceSMGroup[adjFace] == 0 && math::dot(faceNormals[curFace], faceNormals[adjFace]) > cSMAngle ) 
                {
                    faceSMGroup[adjFace] = smGroup;
                    toVisit.push(adjFace);
                }
            }
        }
    }

    // once smoothing groups are set try to reduce their quantity to 32 using greedy algorithm
    smoothingGroups.resize( getNumFaces() );
    for (size_t i = 0; i<getNumFaces(); ++i) {
        smoothingGroups[i] = faceSMGroup[i] % 32;
    }
}
Exemplo n.º 2
0
 // Returns the boundary edge that is not e.
 Vertex WingedEdge::getOtherBoundaryVertice(Vertex &a, Edge &forbidden_edge)
 {
     std::set<Edge> edges = vertexList[a];
     for(Edge e : edges)
     {
         if(e != forbidden_edge && getNumAdjacentFaces(e) == 1)
         {
             return getOtherVertex(e, a);
         }
     }
     
     //throw RuntimeError("No other boundary edge was found. Something might be wrong with your mesh.");
     return a;
 }
Exemplo n.º 3
0
    // Subdivides only the edges on the boundary.
    WingedEdge WingedEdge::BoundaryTrianglularSubdivide(float min_len)
    {
        
        WingedEdge mesh;// = *this;

        
        for (auto face_iter = faceList.begin(); face_iter != faceList.end(); ++face_iter)
        {
            const Face face = face_iter -> first;
            
            
            /* massive assumption that there is 3 edges in our face */
            Edge e1 = face.E1();
            Edge e2 = face.E2();
            Edge e3 = face.E3();
            
            // Compute the vertices opposite the cooresponding indiced edges.
            bool success = true;
            Vertex v1 = GetAdjacentVertex(face, e1, success);
            Vertex v2 = GetAdjacentVertex(face, e2, success);
            Vertex v3 = GetAdjacentVertex(face, e3, success);
            
            if(!success)
            {
                throw new RuntimeError("Error : Winged Edge topology is malformed!");
            }
            
            // -- Compute boundary predicates that answer whether or not an edge should be divided.
            bool b1, b2, b3;
            b1 = getNumAdjacentFaces(e1) == 1;
            b2 = getNumAdjacentFaces(e2) == 1;
            b3 = getNumAdjacentFaces(e3) == 1;
            
            // Non Boundary --> do not subdivide the face.
            if(!(b1 || b2 || b3))
            {
                
                e1 = mesh.AddEdge(e1);
                e2 = mesh.AddEdge(e2);
                e2 = mesh.AddEdge(e2);
                
                mesh.AddFace(e1, e2, e3);
                
                continue;
            }
            
            
            // FIXME : Only compute butterfly midpoints, if the original predicate is true.
            
            // Compute interpolated midpoints.
            Vertex mid_b1, mid_b2, mid_b3;
            mid_b1 = SubdivideEdge(face, e1, v1, false);
            mid_b2 = SubdivideEdge(face, e2, v2, false);
            mid_b3 = SubdivideEdge(face, e3, v3, false);
            
            
            // Bound the change in midpoint.
            if(min_len > 0)
            {
                // Compute linear mid points.
                Vertex mid_l1, mid_l2, mid_l3;
                mid_l1 = SubdivideEdge(face, e1, v1, true);
                mid_l2 = SubdivideEdge(face, e2, v2, true);
                mid_l3 = SubdivideEdge(face, e3, v3, true);
                
                float sqr_len_min = min_len > 1 ? min_len*min_len : min_len;
                
                b1 = b1 && computeSqrOffset(mid_b1, mid_l1) > sqr_len_min;
                b2 = b2 && computeSqrOffset(mid_b2, mid_l2) > sqr_len_min;
                b3 = b3 && computeSqrOffset(mid_b3, mid_l3) > sqr_len_min;
            }
            
            
            
            // -- Count the number of edges that are on the boundary.
            int boundary_count = 0;
            boundary_count = b1 ? boundary_count + 1 : boundary_count;
            boundary_count = b2 ? boundary_count + 1 : boundary_count;
            boundary_count = b3 ? boundary_count + 1 : boundary_count;
     
            // Non Boundary --> do not subdivide the face.
            if(boundary_count == 0)
            {
                e1 = mesh.AddEdge(e1);
                e2 = mesh.AddEdge(e2);
                e2 = mesh.AddEdge(e2);
                
                mesh.AddFace(e1, e2, e3);
                continue;
            }
            
            
            // 1 boundary --> subdivide into 2 vertices.
            if(boundary_count == 1)
            {
                
                Vertex v_new, v_old1, v_old2, v_old3;
                
                if(b1)
                {
                    v_new = mid_b1;
                    v_old1 = v1;
                    v_old2 = v2;
                    v_old3 = v3;
                }
                else if(b2)
                {
                    v_new = mid_b2;
                    v_old1 = v2;
                    v_old2 = v3;
                    v_old3 = v1;
                }
                else
                {
                    v_new = mid_b3;
                    v_old1 = v3;
                    v_old2 = v1;
                    v_old3 = v2;
                }
                
                // face1
                e1 = mesh.AddEdge(v_new, v_old1);
                e2 = mesh.AddEdge(v_new, v_old2);
                e3 = mesh.AddEdge(v_old1, v_old2);
                mesh.AddFace(e1, e2, e3);
                
                // Face 2.
                e2 = mesh.AddEdge(v_new, v_old3);
                e3 = mesh.AddEdge(v_old1, v_old3);
                mesh.AddFace(e1, e2, e3);
                
                continue;
            }
            
            // 2 - 3 boundaries. Perform the full 4 face triangulation.
            
            if(boundary_count == 3)
            {
                performTriangulation(mesh,
                                     v1, v2, v3,
                                     mid_b1, mid_b2, mid_b3);
                
                continue;
            }
            
            if(boundary_count > 3)
            {
                throw new RuntimeError("Face has more than 3 edges. This is not a triangle!");
            }
            
            // -- 2 boundary case. Subdivide into 3 triangles.
            Vertex v_new1, v_new2, v_old1, v_old2, v_old3;
            
            if(!b1)
            {
                v_old1 = v1;
                v_old2 = v2;
                v_old3 = v3;
                v_new1 = mid_b2;
                v_new2 = mid_b3;
            }
            else if(!b2)
            {
                v_old1 = v2;
                v_old2 = v3;
                v_old3 = v1;
                v_new1 = mid_b3;
                v_new2 = mid_b1;
            }
            else
            {
                v_old1 = v3;
                v_old2 = v1;
                v_old3 = v2;
                v_new1 = mid_b1;
                v_new2 = mid_b2;
            }

            
            // Boundary triangles.
            e1 = mesh.AddEdge(v_old1, v_new1);
            e2 = mesh.AddEdge(v_old1, v_new2);
            e3 = mesh.AddEdge(v_new1, v_new2);
            mesh.AddFace(e1, e2, e3);
            
            
            e1 = mesh.AddEdge(v_old3, v_new1);
            e2 = mesh.AddEdge(v_old3, v_new2);
            e3 = mesh.AddEdge(v_new1, v_new2);
            mesh.AddFace(e1, e2, e3);
            
            // Constant edge triangle.
            e1 = mesh.AddEdge(v_old2, v_new2);
            e2 = mesh.AddEdge(v_old3, v_new2);
            e3 = mesh.AddEdge(v_old3, v_old2);
            mesh.AddFace(e1, e2, e3);
            
        }
       
        return mesh;
    }
Exemplo n.º 4
0
 // Private work function.
 WingedEdge WingedEdge::Subdivide(bool linear, bool pascal, std::map<Vertex, std::vector<Vertex> > &derivations)
 {
     WingedEdge mesh;
     std::set<Edge> edges;
     
     for (auto face = faceList.begin(); face != faceList.end(); ++face)
     {
         
         /* massive assumption that there is 3 edges in our face */
         Edge e1 = face -> first.E1();
         Edge e2 = face -> first.E2();
         Edge e3 = face -> first.E3();
         
         /* might need to verify this doesn't pick duplicates */
         Vertex v1 = e1.V1();
         Vertex v2 = e1.V2();
         Vertex v3 = (e2.V1() == v1 || e2.V1() == v2) ? e2.V2() : e2.V1();
         
         /* guarantee we know what e2 is */
         if (v1 == e3.V1() || v1 == e3.V2())
         {
             Edge tmp = e3;
             e3 = e2;
             e2 = tmp;
         }
         
         int f1, f2, f3;
         f1 = getNumAdjacentFaces(e1);
         f2 = getNumAdjacentFaces(e2);
         f3 = getNumAdjacentFaces(e3);
         
         // Do not subdivide and do not incorporate non boundary faces.
         // This is the part the creates the pascal behavior,
         if(pascal && f1 == 2 && f2 == 2 && f3 == 2)
         {
             continue;
         }
         
         bool success = true;
         Vertex v4 = SubdivideEdge(face->first, e1, GetAdjacentVertex(face->first, e1, success), linear, derivations);
         Vertex v5 = SubdivideEdge(face->first, e2, GetAdjacentVertex(face->first, e2, success), linear, derivations);
         Vertex v6 = SubdivideEdge(face->first, e3, GetAdjacentVertex(face->first, e3, success), linear, derivations);
         
         // A half hearted success check.
         if(!success)
         {
             throw RuntimeError("WindgedEdge Error: Something is wrong with the mesh to be subdivided.");
         }
         
         {
             e1 = mesh.AddEdge(v1, v4);
             e2 = mesh.AddEdge(v1, v5);
             e3 = mesh.AddEdge(v5, v4);
             mesh.AddFace(e1, e2, e3);
         }
         
         {
             e1 = mesh.AddEdge(v4, v2);
             e2 = mesh.AddEdge(v4, v6);
             e3 = mesh.AddEdge(v6, v2);
             mesh.AddFace(e1, e2, e3);
         }
         
         {
             e1 = mesh.AddEdge(v5, v6);
             e2 = mesh.AddEdge(v5, v3);
             e3 = mesh.AddEdge(v3, v6);
             mesh.AddFace(e1, e2, e3);
         }
         
         {
             e1 = mesh.AddEdge(v6, v5);
             e2 = mesh.AddEdge(v6, v4);
             e3 = mesh.AddEdge(v4, v5);
             mesh.AddFace(e1, e2, e3);
         }
         
     }
     
     /*
      std::cout << "Subdivide info: " << std::endl;
      std::cout << "VertexList: " << mesh.NumVertices() << std::endl;
      std::cout << "EdgeList: " << mesh.NumEdges() << std::endl;
      std::cout << "FaceList: " << mesh.NumFaces() << std::endl;
      */
     
     return mesh;
 }