Пример #1
0
// cut a chunk of the lattice out to roughly match the shape
static void
cut_lattice(const SDF& sdf,
            TetMesh& mesh,
            std::vector<float>& vphi) // phi evaluated at vertices
{
    std::map<Vec3i,int> lattice_map;
    // loop over tiles that overlap bounding box
    int i, j, k;
    for (k=0; k<sdf.phi.nk; k+=4) for (j=0; j<sdf.phi.nj; j+=4) 
      for (i=0; i<sdf.phi.ni; i+=4) {
        for (int t=0; t<num_lattice_tets; ++t) {
            // check this tet is entirely inside the grid & has a negative phi
            bool good_tet = true;
            bool negative_phi = false;
            for (int u=0; u<4; ++u) {
                int a = lattice_node[lattice_tet[t][u]][0]+i;
                if (a >= sdf.phi.ni) { good_tet=false; break; }
                int b = lattice_node[lattice_tet[t][u]][1]+j;
                if (b >= sdf.phi.nj) { good_tet=false; break; }
                int c = lattice_node[lattice_tet[t][u]][2]+k;
                if (c >= sdf.phi.nk) { good_tet=false; break; }
                if (sdf.phi(a,b,c) < 0)
                    negative_phi = true;
            }
            if (good_tet && negative_phi) {
                // add vertices if they don't exist yet, find actual tet to add
                Vec4i actual_tet(-1,-1,-1,-1);
                for (int u=0; u<4; ++u) {
                    Vec3i vertex=lattice_node[lattice_tet[t][u]]+Vec3i(i,j,k);
                    std::map<Vec3i,int>::iterator p = lattice_map.find(vertex);
                    if (p == lattice_map.end()) {
                        actual_tet[u] = mesh.vSize();
                        lattice_map[vertex] = actual_tet[u];
                        mesh.verts().push_back(sdf.origin+sdf.dx*Vec3f(vertex));
                        vphi.push_back(sdf.phi(vertex[0],vertex[1],vertex[2]));
                    } else {
                        actual_tet[u]=p->second;
                    }
                }
                mesh.tets().push_back(actual_tet);
            }
        }
    }
}
Пример #2
0
// assuming vphi[i] and vphi[j] have different signs, find or create a new
// vertex on the edge between them where phi interpolates to zero.
static int
cut_edge(int i, int j,
         TetMesh& mesh,
         std::vector<float> &vphi,
         std::map<Vec2i,int> &cut_map)
{
    assert((vphi[i]<0 && vphi[j]>0) || (vphi[i]>0 && vphi[j]<0));
    Vec2i edge(min(i,j), max(i,j));
    std::map<Vec2i,int>::iterator p = cut_map.find(edge);
    if (p == cut_map.end()) { // this edge hasn't been cut yet?
        int v = (int)mesh.vSize();
        float alpha = vphi[i]/(vphi[i]-vphi[j]);
        mesh.verts().push_back((1-alpha)*mesh.V(i) + alpha*mesh.V(j));
        vphi.push_back(0);
        cut_map[edge] = v;
        return v;
    } else { // already done this edge
        return p->second;
    }
}
Пример #3
0
void
make_tet_mesh(TetMesh& mesh,
              const SDF& sdf,
              FeatureSet& featureSet,
              bool optimize,
              bool intermediate,
              bool unsafe)
{
    // Initialize exact arithmetic
    initialize_exact();

    // Initialize mesh from acute lattice.
    std::vector<float> vphi; // SDF value at each lattice vertex.
    mesh.verts().resize(0);
    mesh.tets().resize(0);

    std::cout<<"  cutting from lattice"<<std::endl;
    cut_lattice(sdf, mesh, vphi);

    if (intermediate) {
        static const char* cutLatticeFile = "1_cut_lattice.tet";
        static const char* cutLatticeInfo = "1_cut_lattice.info";
        mesh.writeToFile(cutLatticeFile);
        mesh.writeInfoToFile(cutLatticeInfo);
        std::cout << "Mesh written to " << cutLatticeFile << std::endl;
    }

    // Warp any vertices close enough to phi=0 to fix sign crossings.
    static const float WARP_THRESHOLD = 0.3;
    std::cout<<"  warping vertices"<<std::endl;
    warp_vertices(WARP_THRESHOLD, mesh, vphi);

    if (intermediate) {
        static const char* warpVerticesFile = "2_warp_vertices.tet";
        static const char* warpVerticesInfo = "2_warp_vertices.info";
        mesh.writeToFile(warpVerticesFile);
        mesh.writeInfoToFile(warpVerticesInfo);
        std::cout << "Mesh written to " << warpVerticesFile << std::endl;
    }

    // Cut through tets that still poke out of the level set
    std::cout<<"  trimming spikes"<<std::endl;
    trim_spikes(mesh, vphi);

    if (intermediate) {
        static const char* trimSpikesFile = "3_trim_spikes.tet";
        static const char* trimSpikesInfo = "3_trim_spikes.info";
        mesh.writeToFile(trimSpikesFile);
        mesh.writeInfoToFile(trimSpikesInfo);
        std::cout << "Mesh written to " << trimSpikesFile << std::endl;
    }

    // At this point, there could be some bad tets with all four vertices on
    // the surface but which lie outside the level set.  Get rid of them.
    std::cout<<"  removing exterior tets"<<std::endl;
    remove_exterior_tets(mesh, vphi, sdf);

    // Compact mesh and clear away unused vertices.
    std::cout<<"  compacting mesh"<<std::endl;
    mesh.compactMesh();

    if (intermediate) {
        static const char* removeExtFile = "4_remove_exterior.tet";
        static const char* removeExtInfo = "4_remove_exterior.info";
        static const char* removeExtObj = "4_remove_exterior.obj";
        mesh.writeToFile(removeExtFile);
        mesh.writeInfoToFile(removeExtInfo);
        std::vector<Vec3f> objVerts;
        std::vector<Vec3i> objTris;
        mesh.getBoundary(objVerts, objTris);
        write_objfile(objVerts, objTris, removeExtObj);
        std::cout << "Mesh written to " << removeExtFile << std::endl;
    }

    // Compute maximum dihedral angle of mesh (unoptimized, no features).
    std::cout << "  Maximum dihedral angle = " << max_dihedral_angle(mesh) 
        << std::endl;

    if (featureSet.numFeatures() > 0 || optimize)
    {
        // Identify boundary vertices
        std::vector<int> boundary_verts;
        std::vector<Vec3i> boundary_tris;
        std::cout << "  identifying boundary" << std::endl;
        mesh.getBoundary(boundary_verts, boundary_tris);
        assert(!boundary_verts.empty());
        
        // Snap vertices to given features
        std::vector<int> feature_endpoints;
        std::map<int, int> vertex_feature_map;
        if (featureSet.numFeatures() > 0)
        {
            // Move vertices to match desired features
            std::cout << "  matching features" << std::endl;
            clock_t featureTime = clock();

            match_features(mesh, featureSet, sdf.dx,
                           boundary_verts, boundary_tris,
                           feature_endpoints, vertex_feature_map,
                           unsafe);

            featureTime = clock() - featureTime;
        
            std::cout << "  features matched in " 
                      << ((float)featureTime)/CLOCKS_PER_SEC 
                      << " seconds." << std::endl;
            std::cout << "  Maximum dihedral angle = "
                      << max_dihedral_angle(mesh) << std::endl;

            if (optimize && intermediate)
            {
                static const char* matchFeaturesFile = "5_match_features.tet";
                static const char* matchFeaturesInfo = "5_match_features.info";
                mesh.writeToFile(matchFeaturesFile);
                mesh.writeInfoToFile(matchFeaturesInfo);
                std::cout << "Mesh written to " << matchFeaturesFile 
                          << std::endl;
            }
        } 

        // Finish by optimizing the tetmesh, if desired.
        if (optimize) 
        {
            std::cout << "  optimizing mesh" << std::endl;
            clock_t optTime = clock();

            optimize_tet_mesh(mesh, sdf, 
                              boundary_verts, 
                              featureSet,
                              feature_endpoints,
                              vertex_feature_map);

            optTime = clock() - optTime;
            std::cout << "  Mesh optimization completed in " 
                      << ((float)optTime)/CLOCKS_PER_SEC
                      << " seconds." << std::endl;
            std::cout<< "  Maximum dihedral angle = "
                     << max_dihedral_angle(mesh) << std::endl;
        }

        // DEBUGGING
        // Check for inverted tets
        for (size_t t = 0; t < mesh.tSize(); ++t)
        {
            Tet tet = mesh.getTet(t);
            float signedVolume = tet.volume();
            if (signedVolume <= 0.0)
            {
                std::cerr << "Tet #" << t << " is inverted! " <<
                    "Volume = " << signedVolume << "; " <<
                    "Aspect = " << tet.aspectRatio() << std::endl <<
                    "{" << tet[0] << "} {" << tet[1] << "} {" << tet[2] <<
                    "} {" << tet[3] << "}" << std::endl;
            }
        }
    }
}