///////////////////////////////////// // put_visibility() ///////////////////////////////////// void HatchingGroupFixed::put_visibility(TAGformat &d) const { err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::put_visibility()"); BMESHptr m = _patch->mesh(); LMESHptr lm = dynamic_pointer_cast<LMESH>(m); if (lm) m = lm->cur_mesh(); Bface_list::size_type k; vector<int> indices; CBface_list& faces = m->faces(); for (k=0; k< faces.size(); k++) { HatchingSimplexDataFixed *hsdf = HatchingSimplexDataFixed::find(faces[k]); if (hsdf) { if (hsdf->exists(this)) indices.push_back(faces[k]->index()); } } err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::put_visibility() - Stored %d tri indices.", indices.size()); d.id(); *d << indices; d.end_id(); }
void LMESH::_merge(BMESHptr bm) { // merge the given mesh into this one. // error checking was done before this protected method was called. // so this convenient cast is safe: LMESHptr m = static_pointer_cast<LMESH>(bm); // merge subdivision meshes (recursively) first. but if this one // has fewer levels of subdivision, truncate the other one to the // same number of levels. if (_subdiv_mesh && m->_subdiv_mesh) _subdiv_mesh->_merge(m->_subdiv_mesh); else m->delete_subdiv_mesh(); // ensure it has no finer level meshes // Get the dirty vertices from m and put them into this // mesh's dirty list: m->_dirty_verts.clear_bits(Lvert::DIRTY_VERT_LIST_BIT); while (!m->_dirty_verts.empty()) { add_dirty_vert((Lvert*)m->_dirty_verts.back()); m->_dirty_verts.pop_back(); } // this concludes the LMESH-specific aspect of the merge // method. now just continue with the normal merge... BMESH::_merge(bm); }
///////////////////////////////////// // get_visibility() ///////////////////////////////////// void HatchingGroupFixed::get_visibility(TAGformat &d) { err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::get_visibility()"); BMESHptr m = _patch->mesh(); LMESHptr lm = dynamic_pointer_cast<LMESH>(m); if (lm) m = lm->cur_mesh(); vector<int>::size_type k; int ctr=0; vector<int> indices; CBface_list& faces = m->faces(); *d >> indices; for (k=0; k<indices.size(); k++) { HatchingSimplexDataFixed *hsdf = HatchingSimplexDataFixed::find(faces[indices[k]]); if (!hsdf) { hsdf = new HatchingSimplexDataFixed(faces[indices[k]]); ctr++; } hsdf->add(this); } err_mesg(ERR_LEV_SPAM, "HatchingGroupFixed::get_visibility() - Flagged %d tris and added %d new simplex data.", indices.size(), ctr); }
///////////////////////////////////// // load_scene() ///////////////////////////////////// void BaseJOTapp::load_scene() { while (_argc > 1) { if (_argv[1][0] == '-') { char flag = _argv[1][1]; pop_arg(); switch(flag) { case 'm': load_sm_file(_argv[1]); break; case 'o': load_obj_file(_argv[1]); break; case 'j': load_jot_file(_argv[1]); break; default: print_usage(); WORLD::Quit(); } } else { if (!load_sm_file(_argv[1])) load_jot_file(_argv[1]); } pop_arg(); } if (0) { LMESHptr m = new LMESH; m->Sphere(); create_mesh(m, "sphere"); } // Do "viewall" if: // (1) the camera was not specified in file, and // (2) at least one 3D object is outside the view frustum. for (int i=0; i<_windows.num(); i++) if (_windows[i]->_view->cam()->data()->loaded_from_file()) return; for (int j=0; j<DRAWN.num(); j++) { GEOM* geom = GEOM::upcast(DRAWN[j]); if (geom && geom->bbox().is_off_screen()) { VIEW::peek()->viewall(); return; // once is enough } } }
void LMESH::set_parent(LMESH* parent) { assert(parent); _parent_mesh = parent; _subdiv_level = parent->subdiv_level() + 1; LMESHptr c = control_mesh(); assert(c != nullptr); if (c->has_name()) { char tmp[32]; sprintf(tmp, "%d", _subdiv_level); set_name(c->get_name() + "-sub" + tmp); } }
inline void add_face(LMESHptr& mesh, Face* f) { assert(mesh && f); switch (f->nverts) { case 3: // triangle mesh->add_face(f->verts[2], f->verts[1], f->verts[0]); break; case 4: // quad mesh->add_quad(f->verts[3], f->verts[2], f->verts[1], f->verts[0]); break; default: // other // XXX - should fix this to convert to triangles err_msg("ply2sm: can't add face: %d-gon", f->nverts); } }
int main(int argc, char *argv[]) { int num_levels = 1; if (argc == 2) num_levels = max(atoi(argv[1]), 0); else if(argc != 1) { err_msg("Usage: %s [ num_levels ] < mesh.sm > mesh-sub.sm", argv[0]); return 1; } LMESHptr mesh = LMESH::read_jot_stream(cin); if (!mesh || mesh->empty()) return 1; // didn't work mesh->set_subdiv_loc_calc(new LoopLoc()); if (Config::get_var_bool("JOT_PRINT_MESH")) { cerr << "input mesh:" << endl; mesh->print(); } if (num_levels > 0) mesh->update_subdivision(num_levels); if (Config::get_var_bool("JOT_PRINT_MESH")) { cerr << "level " << num_levels << " mesh:" << endl; mesh->cur_mesh()->print(); } mesh->cur_mesh()->write_stream(cout); return 0; }
inline void read_vert(LMESHptr mesh, istream& in) { double x, y, z; in >> x >> y >> z; skip_line(in); assert(mesh); mesh->add_vertex(Wpt(x,y,z)); }
inline Bvert_list copy_verts(CBvert_list& verts, LMESHptr mesh) { Bvert_list ret(verts.size()); for (Bvert_list::size_type i=0; i<verts.size(); i++) { ret.push_back(mesh->add_vertex(verts[i]->loc())); } return ret; }
bool LMESH::update_subdivision(CBface_list& faces, int k) { static bool debug = Config::get_var_bool("DEBUG_BFACE_LIST_SUBDIVISION",false); if (debug) { cerr << "LMESH::update_subdivision: " << faces.size() << " faces to level "<< k << endl; } if (k < 0) return false; if (faces.empty()) return true; LMESHptr m = dynamic_pointer_cast<LMESH>(faces.mesh()); if (!m) { err_adv(debug, " error: non-LMESH"); return false; } // Ensure mesh is up-to-date wrt controllers BMESHobs::broadcast_update_request(m); if (k == 0) return true; // generate lext-level mesh if needed if (!m->allocate_subdiv_mesh()) { err_adv(debug, " error: can't allocate subdiv mesh"); return false; } // update subdivision for the one-ring, 1-level down update_faces(faces.one_ring_faces(), debug); update_faces(faces.secondary_faces(), debug); assert(m->subdiv_mesh()); m->subdiv_mesh()->changed(VERT_POSITIONS_CHANGED); // then recurse return update_subdivision(get_subdiv_faces(faces,1), k-1); }
LMESHptr Bbase::get_inflate_mesh() const { TEXBODY* tex = texbody(); if (!tex) { err_msg("Bbase::get_inflate_mesh: Error: geom is non-TEXBODY"); return 0; } LMESHptr ret = LMESH::upcast(tex->get_inflate_mesh(mesh())); if (!ret) { return 0; } // Use the same subdivision scheme: ret->set_subdiv_loc_calc(_mesh->loc_calc()->dup()); return ret; }
inline LMESHptr get_inflate_mesh(LMESHptr skel_mesh) { if (!skel_mesh) return nullptr; TEXBODY* tex = dynamic_cast<TEXBODY*>(skel_mesh->geom()); if (!tex) return nullptr; return dynamic_pointer_cast<LMESH>(tex->get_inflate_mesh(skel_mesh)); }
LMESHptr LMESH::get_lmesh(const string& exact_name) { // Return an LMESH with the given name. If one already exists, // return that one. Otherwise create a new LMESH with the desired // name. Fails (returns null) if the name is invalid (null string) // or the name is already taken by a BMESH that is not an LMESH. bool debug = NameLookup<BMESH>::_debug; // Make sure they're not asking for the null string: if (exact_name == "") { if (debug) cerr << "LMESH::get_lmesh: error: name is empty" << endl; return nullptr; } // Does a mesh with the requested name exist? BMESHptr mesh = dynamic_cast<BMESH*>(NameLookup<BMESH>::lookup(exact_name))->shared_from_this(); // If no mesh of that name exists, create a new one: if (!mesh) { LMESHptr ret = make_shared<LMESH>(); assert(ret && !ret->has_name()); ret->set_name(exact_name); return ret; } // A BMESH with the requested name already exists; // if it is not also an LMESH, this is an error: LMESHptr lm = dynamic_pointer_cast<LMESH>(mesh); if (debug && !lm) { cerr << "LMESH::get_lmesh: error: found requested name: " << exact_name << ", but it is not an LMESH" << endl; } return lm; }
int main(int argc, char *argv[]) { bool do_gauss_seidel = 0; if (argc == 2 && str_ptr(argv[1]) == str_ptr("-g")) do_gauss_seidel = 1; else if(argc != 1) { err_msg("Usage: %s [ -g ] < mesh.sm > mesh-fit.sm", argv[0]); return 1; } LMESHptr mesh = LMESH::read_jot_stream(cin); if (!mesh || mesh->empty()) return 1; // didn't work fit(mesh, do_gauss_seidel); mesh->write_stream(cout); return 0; }
void Lface::delete_subdiv_elements() { // Make this lightweight, so you can call // it when you're not sure if you need to: if (!is_set(SUBDIV_ALLOCATED_BIT)) return; clear_bit(SUBDIV_ALLOCATED_BIT); // After this we need to get treated as a "dirty" face. // That means the vertices have to be dirty lv(1)->mark_dirty(); lv(2)->mark_dirty(); lv(3)->mark_dirty(); LMESHptr submesh = lmesh()->subdiv_mesh(); assert(submesh); // Removing a face (or edge) also causes it to remove // *its* subdiv elements. I.e., this is recursive. Lface* subface; if ((subface = subdiv_face_center())) submesh->remove_face(subface); if ((subface = subdiv_face1())) submesh->remove_face(subface); if ((subface = subdiv_face2())) submesh->remove_face(subface); if ((subface = subdiv_face3())) submesh->remove_face(subface); Ledge* subedge; if ((subedge = subdiv_edge1())) submesh->remove_edge(subedge); if ((subedge = subdiv_edge2())) submesh->remove_edge(subedge); if ((subedge = subdiv_edge3())) submesh->remove_edge(subedge); }
SubdivUpdater::SubdivUpdater(LMESHptr m, CBvert_list& verts) : _parent(nullptr) { // Screened in SubdivUpdater::create(): assert(m && m == verts.mesh()); _mesh = m; _verts = verts; // Get bbases, add to inputs _inputs = Bbase::find_owners(verts).bnodes(); if (debug) { err_msg("SubdivUpdater::SubdivUpdater:"); cerr << " "; print_dependencies(); err_msg(" level %d, %d verts, %d boss memes", m->subdiv_level(), verts.size(), Bbase::find_boss_vmemes(verts).size()); } // If not covered, create parent if (!Bbase::is_covered(verts)) { // Get parent verts list Bvert_list parents = LMESH::get_subdiv_inputs(verts); // If non-empty create parent SubdivUpdater if (!parents.empty()) { // Create parent subdiv updater on parent verts // and add to _inputs _parent = create(parents); _inputs += _parent; } } hookup(); }
CAMwidget_anchor() : GEOM() { // Start with an empty LMESH: LMESHptr mesh = new LMESH(); // Ensure mesh knows its containing GEOM: mesh->set_geom(this); // Make a ball shape mesh->Icosahedron(); mesh->refine(); // smooth it once // Regardless of current rendering mode, // always use Gouraud shading: mesh->set_render_style(SmoothShadeTexture::static_name()); // Color the Patch blue: mesh->patch(0)->set_color(COLOR(0.1, 0.1, 0.9)); // Store the mesh: _body = mesh; set_name("CAMwidget_anchor"); }
/****************************************************************************** Write out a jot .sm file. ******************************************************************************/ void write_sm() { LMESHptr mesh = make_shared<LMESH>(); int i=0; //******** Build the mesh ******** err_adv(debug, "read ply file: %d vertices, %d faces\n", nverts, nfaces); err_adv(debug, "building mesh:"); // Add vertices to mesh err_adv(debug, " adding vertices..."); for (i = 0; i < nverts; i++) mesh->add_vertex(Wpt(vlist[i]->x, vlist[i]->y, vlist[i]->z)); err_adv(debug, " done\n"); // Add per-vertex colors if needed if (per_vertex_color) { err_adv(debug, " adding colors..."); for (i = 0; i < nverts; i++) mesh->bv(i)->set_color(COLOR(vlist[i]->r, vlist[i]->g, vlist[i]->b)); err_adv(debug, " done\n"); } // Add faces err_adv(debug, " adding faces..."); for (i = 0; i < nfaces; i++) add_face(mesh, flist[i]); err_adv(debug, " done\n"); //******** Filter the mesh ******** err_adv(debug, "filtering mesh..."); // Remove any isolated vertices for (i=mesh->nverts()-1; i>=0; i--) { if (mesh->bv(i)->degree() == 0) { mesh->remove_vertex(mesh->bv(i)); } } mesh->changed(); // Remove duplicate vertices while we're at it mesh->remove_duplicate_vertices(false); // don't keep the bastards // Check for consistent orientation of normals bool is_bad = false; for (i=0; i<mesh->nedges(); i++) if (!mesh->be(i)->consistent_orientation()) is_bad = true; if (is_bad) err_msg("Warning: inconsistently oriented triangles -- can't fix"); // Optional: recenter mesh if (Config::get_var_bool("JOT_RECENTER")) mesh->recenter(); // Optional: print stats if (Config::get_var_bool("JOT_PRINT_MESH")) mesh->print(); err_adv(debug, "done\n"); //******** Write mesh ******** err_adv(debug, "writing mesh..."); mesh->write_stream(cout); err_adv(debug, "done\n"); }
inline string get_name(LMESHptr m) { return (m && m->geom()) ? m->geom()->name() : (m ? "null geom" : "null mesh"); }
void fit(LMESHptr& mesh, bool do_gauss_seidel) { if (mesh->empty()) return; // time this stop_watch clock; double max_err = mesh->get_bb().dim().length() * 1e-5; int n = mesh->nverts(); // get original control point locations Wpt_list C(n); // original control points Wpt_list L(n); // current limit points for (int i=0; i<n; i++) { C += mesh->bv(i)->loc(); L += Wpt::Origin(); } // do 50 iterations... double prev_err = 0; for (int k=0; k<50; k++) { double err = 0; if (do_gauss_seidel) { // Gauss-Seidel iteration: use updated values from the // current iteration as they are computed... for (int j=0; j<n; j++) { // don't need that L[] array... Wpt limit; mesh->lv(j)->limit_loc(limit); Wvec delt = C[j] - limit; err += delt.length(); mesh->bv(j)->offset_loc(delt); } } else { // compute the new offsets from the offsets computed in the // previous iteration int j; for (j=0; j<n; j++) mesh->lv(j)->limit_loc(L[j]); for (j=0; j<n; j++) { Wvec delt = C[j] - L[j]; err += delt.length(); mesh->bv(j)->offset_loc(delt); } } // compute the average error: err /= n; if (prev_err != 0) { err_msg("Iter %d: avg error: %f, reduction: %f", k, err, err/prev_err); } else { err_msg("Iter %d: avg error: %f", k, err); } prev_err = err; if (err < max_err) break; } err_msg("fitting took %.2f seconds", clock.elapsed_time()); }