void create_sphere( const Vec3d& sphere_centre, double sphere_radius, double dx, std::vector<Vec3d>& verts, std::vector<Vec3st>& tris ) { const Vec3d domain_low = sphere_centre - Vec3d(sphere_radius + 3*dx); const Vec3d domain_high = sphere_centre + Vec3d(sphere_radius + 3*dx); Array3d phi; create_sphere_signed_distance( sphere_centre, sphere_radius, dx, domain_low, domain_high, phi ); MarchingTilesHiRes marching_tiles( domain_low, dx, phi ); marching_tiles.contour(); marching_tiles.improve_mesh(); std::vector<Vec3d> new_verts( marching_tiles.x.size() ); for ( size_t i = 0; i < new_verts.size(); ++i ) { new_verts[i] = marching_tiles.x[i]; } std::vector<Vec3st> new_tris( marching_tiles.tri.size() ); for ( size_t i = 0; i < new_tris.size(); ++i ) { new_tris[i] = Vec3st( marching_tiles.tri[i] ); } project_to_exact_sphere( new_verts, sphere_centre, sphere_radius ); Vec3st offset( verts.size() ); for ( size_t i = 0; i < new_verts.size(); ++i ) { verts.push_back( new_verts[i] ); } for ( size_t i = 0; i < new_tris.size(); ++i ) { tris.push_back( new_tris[i] + offset ); } }
ErrorCode ReadCCMIO::read_vertices(CCMIOSize_t /* proc */, CCMIOID /* processorID */, CCMIOID verticesID, CCMIOID /* topologyID */, Range *verts, TupleList &vert_map) { CCMIOError error = kCCMIONoErr; // pre-read the number of vertices, so we can pre-allocate & read directly in CCMIOSize_t nverts = CCMIOSIZEC(0); CCMIOEntitySize(&error, verticesID, &nverts, NULL); CHKCCMERR(error, "Couldn't get number of vertices."); // get # dimensions CCMIOSize_t dims; float scale; CCMIOReadVerticesf(&error, verticesID, &dims, NULL, NULL, NULL, CCMIOINDEXC(0), CCMIOINDEXC(1)); CHKCCMERR(error, "Couldn't get number of dimensions."); // allocate vertex space EntityHandle node_handle = 0; std::vector<double*> arrays; readMeshIface->get_node_coords(3, GETINT32(nverts), MB_START_ID, node_handle, arrays); // read vertex coords CCMIOID mapID; std::vector<double> tmp_coords(GETINT32(dims)*GETINT32(nverts)); CCMIOReadVerticesd(&error, verticesID, &dims, &scale, &mapID, &tmp_coords[0], CCMIOINDEXC(0), CCMIOINDEXC(0+nverts)); CHKCCMERR(error, "Trouble reading vertex coordinates."); // copy interleaved coords into moab blocked coordinate space int i = 0, threei = 0; for (; i < nverts; i++) { arrays[0][i] = tmp_coords[threei++]; arrays[1][i] = tmp_coords[threei++]; if (3 == GETINT32(dims)) arrays[2][i] = tmp_coords[threei++]; else arrays[2][i] = 0.0; } // scale, if necessary if (1.0 != scale) { for(i = 0; i < nverts; i++) { arrays[0][i] *= scale; arrays[1][i] *= scale; if (3 == GETINT32(dims)) arrays[2][i] *= scale; } } // read gids for vertices std::vector<int> gids(GETINT32(nverts)); CCMIOReadMap(&error, mapID, &gids[0], CCMIOINDEXC(kCCMIOStart), CCMIOINDEXC(kCCMIOEnd)); CHKCCMERR(error, "Trouble reading vertex global ids."); // put new vertex handles into range, and set gids for them Range new_verts(node_handle, node_handle+nverts-1); ErrorCode rval = mbImpl->tag_set_data(mGlobalIdTag, new_verts, &gids[0]); CHKERR(rval, "Couldn't set gids on vertices."); // pack vert_map with global ids and handles for these vertices #ifdef TUPLE_LIST vert_map.resize(GETINT32(nverts)); for (i = 0; i < GETINT32(nverts); i++) { vert_map.push_back(NULL, &gids[i], &node_handle, NULL); #else for (i = 0; i < GETINT32(nverts); i++) { (vert_map[gids[i]]).push_back(node_handle); #endif node_handle += 1; } if (verts) verts->merge(new_verts); return MB_SUCCESS; } ErrorCode ReadCCMIO::get_processors(CCMIOID stateID, CCMIOID &processorID, CCMIOID &verticesID, CCMIOID &topologyID, CCMIOID &solutionID, std::vector<CCMIOSize_t> &procs, bool & /* has_solution */) { CCMIOSize_t proc = CCMIOSIZEC(0); CCMIOError error = kCCMIONoErr; CCMIONextEntity(&error, stateID, kCCMIOProcessor, &proc, &processorID); CHKCCMERR(error, NULL); if (CCMIOReadProcessor(NULL, processorID, &verticesID, &topologyID, NULL, &solutionID) != kCCMIONoErr) { // Maybe no solution; try again CCMIOReadProcessor(&error, processorID, &verticesID, &topologyID, NULL, NULL); hasSolution = false; } CHKCCMERR(error, NULL); procs.push_back(proc); return MB_SUCCESS; }
void BasicMesh::Subdivide() { // Loop subdivision // NOTE The indices of the original set of vertices do not change after // subdivision. The new vertices are simply added to the set of vertices. // However, the faces change their indices after subdivision. See how new // faces are added to the face set for details. // In short, the new mesh is created as follows: // [old vertices] // [new vertices] // [faces] // For each edge, compute its center point struct edge_t { edge_t() {} edge_t(int s, int t) : s(s), t(t) {} edge_t(const edge_t& e) : s(e.s), t(e.t) {} bool operator<(const edge_t& other) const { if(s < other.s) return true; else if( s > other.s ) return false; else return t < other.t; } int s, t; }; struct face_edge_t { face_edge_t() {} face_edge_t(int fidx, edge_t e) : fidx(fidx), e(e) {} bool operator<(const face_edge_t& other) const { if(fidx < other.fidx) return true; else if(fidx > other.fidx) return false; return e < other.e; } int fidx; edge_t e; }; const int num_faces = NumFaces(); map<edge_t, Vector3d> midpoints; // iterate over all edges for (HalfEdgeMesh::EdgeIter e=hemesh.edges_begin(); e!=hemesh.edges_end(); ++e) { auto heh = hemesh.halfedge_handle(e, 0); auto hefh = hemesh.halfedge_handle(e, 1); auto v0h = hemesh.to_vertex_handle(heh); auto v1h = hemesh.to_vertex_handle(hefh); int v0idx = vhandles_map[v0h]; int v1idx = vhandles_map[v1h]; auto v0 = verts.row(v0idx); auto v1 = verts.row(v1idx); if(hemesh.is_boundary(*e)) { // simply compute the mid point midpoints.insert(make_pair(edge_t(v0idx, v1idx), 0.5 * (v0 + v1))); } else { // use [1/8, 3/8, 3/8, 1/8] weights auto v2h = hemesh.to_vertex_handle(hemesh.next_halfedge_handle(heh)); auto v3h = hemesh.to_vertex_handle(hemesh.next_halfedge_handle(hefh)); int v2idx = vhandles_map[v2h]; int v3idx = vhandles_map[v3h]; auto v2 = verts.row(v2idx); auto v3 = verts.row(v3idx); midpoints.insert(make_pair(edge_t(v0idx, v1idx), (v0 * 3 + v1 * 3 + v2 + v3) / 8.0)); } } // Now create a new set of vertices and faces const int num_verts = NumVertices() + midpoints.size(); MatrixX3d new_verts(num_verts, 3); // Smooth these points for(int i=0;i<NumVertices();++i) { auto vh = vhandles[i]; if(hemesh.is_boundary(vh)) { // use [1/8, 6/8, 1/8] weights auto heh = hemesh.halfedge_handle(vh); if(heh.is_valid()) { assert(hemesh.is_boundary(hemesh.edge_handle(heh))); auto prev_heh = hemesh.prev_halfedge_handle(heh); auto to_vh = hemesh.to_vertex_handle(heh); auto from_vh = hemesh.from_vertex_handle(prev_heh); Vector3d p = 6 * verts.row(i); p += verts.row(vhandles_map[to_vh]); p += verts.row(vhandles_map[from_vh]); p /= 8.0; new_verts.row(i) = p; } } else { // loop through the neighbors and count them int valence = 0; Vector3d p(0, 0, 0); for(auto vvit = hemesh.vv_iter(vh); vvit.is_valid(); ++vvit) { ++valence; p += verts.row(vhandles_map[*vvit]); } const double PI = 3.1415926535897; const double wa = (0.375 + 0.25 * cos(2.0 * PI / valence)); const double w = (0.625 - wa * wa); p *= (w / valence); p += verts.row(i) * (1 - w); new_verts.row(i) = p; } } // Add the midpoints map<edge_t, int> midpoints_indices; int new_idx = NumVertices(); for(auto p : midpoints) { midpoints_indices.insert(make_pair(p.first, new_idx)); midpoints_indices.insert(make_pair(edge_t(p.first.t, p.first.s), new_idx)); new_verts.row(new_idx) = p.second; ++new_idx; } // Process the texture coordinates map<face_edge_t, Vector2d> midpoints_texcoords; for(int fidx=0;fidx<NumFaces();++fidx){ int j[] = {1, 2, 0}; for(int i=0;i<3;++i) { int v0idx = faces(fidx, i); int v1idx = faces(fidx, j[i]); // if v0 = f[index_of(v0)], the tv0 = tf[index_of(v0)] int tv0idx = face_tex_index(fidx, i); // if v1 = f[index_of(v1)], the tv1 = tf[index_of(v1)] int tv1idx = face_tex_index(fidx, j[i]); auto t0 = texcoords.row(tv0idx); auto t1 = texcoords.row(tv1idx); // the texture coordinates is always the mid point midpoints_texcoords.insert(make_pair(face_edge_t(fidx, edge_t(v0idx, v1idx)), 0.5 * (t0 + t1))); } } const int num_texcoords = texcoords.rows() + midpoints_texcoords.size(); MatrixX2d new_texcoords(num_texcoords, 2); // Just copy the existing texture coordinates new_texcoords.topRows(texcoords.rows()) = texcoords; // Tex-coords for the mid points map<face_edge_t, int> midpoints_texcoords_indices; int new_texcoords_idx = texcoords.rows(); for(auto p : midpoints_texcoords) { //cout << p.first.fidx << ": " << p.first.e.s << "->" << p.first.e.t << endl; //getchar(); midpoints_texcoords_indices.insert(make_pair(p.first, new_texcoords_idx)); midpoints_texcoords_indices.insert(make_pair(face_edge_t(p.first.fidx, edge_t(p.first.e.t, p.first.e.s)), new_texcoords_idx)); new_texcoords.row(new_texcoords_idx) = p.second; ++new_texcoords_idx; } MatrixX3i new_faces(num_faces*4, 3); MatrixX3i new_face_tex_index(num_faces*4, 3); for(int i=0;i<num_faces;++i) { // vertex indices of the original triangle auto vidx0 = faces(i, 0); auto vidx1 = faces(i, 1); auto vidx2 = faces(i, 2); // texture coordinates indices of the original triangle auto tvidx0 = face_tex_index(i, 0); auto tvidx1 = face_tex_index(i, 1); auto tvidx2 = face_tex_index(i, 2); // indices of the mid points int nvidx01 = midpoints_indices[edge_t(vidx0, vidx1)]; int nvidx12 = midpoints_indices[edge_t(vidx1, vidx2)]; int nvidx20 = midpoints_indices[edge_t(vidx2, vidx0)]; // indices of the texture coordinates of the mid points int tnvidx01 = midpoints_texcoords_indices.at(face_edge_t(i, edge_t(vidx0, vidx1))); int tnvidx12 = midpoints_texcoords_indices.at(face_edge_t(i, edge_t(vidx1, vidx2))); int tnvidx20 = midpoints_texcoords_indices.at(face_edge_t(i, edge_t(vidx2, vidx0))); // add the 4 new faces new_faces.row(i*4+0) = Vector3i(vidx0, nvidx01, nvidx20); new_faces.row(i*4+1) = Vector3i(nvidx20, nvidx01, nvidx12); new_faces.row(i*4+2) = Vector3i(nvidx20, nvidx12, vidx2); new_faces.row(i*4+3) = Vector3i(nvidx01, vidx1, nvidx12); new_face_tex_index.row(i*4+0) = Vector3i(tvidx0, tnvidx01, tnvidx20); new_face_tex_index.row(i*4+1) = Vector3i(tnvidx20, tnvidx01, tnvidx12); new_face_tex_index.row(i*4+2) = Vector3i(tnvidx20, tnvidx12, tvidx2); new_face_tex_index.row(i*4+3) = Vector3i(tnvidx01, tvidx1, tnvidx12); } verts = new_verts; faces = new_faces; texcoords = new_texcoords; face_tex_index = new_face_tex_index; // Update the normals after subdivision ComputeNormals(); }