//! Given the starting face "orig_face" and an offset amount "dist", //! determine the appropriate edit level, re-map orig_face to that //! level, and "inflate" the portion of the mesh reachable from //! orig_face by amount dist. The offset may be made relative to the //! local edge length. bool INFLATE::do_inflate( Bface* orig_face, double dist, Bsurface*& output, Bface_list*& reversed_faces, MULTI_CMDptr cmd) { // Reject garbage if (fabs(dist) < epsAbsMath()) { err_adv(debug, "INFLATE::do_inflate: bad offset distance: %f", dist); return 0; } // Throw out trash if (!get_lmesh(orig_face)) { err_adv(debug, "INFLATE::do_inflate: error: bad face"); return 0; } Lface* face = (Lface*)orig_face; err_adv(debug, "INFLATE::do_inflate: face at level %d", subdiv_level(face)); // Decide which level to do inflation -- should match offset dist int rel_level = 0; // XXX - it may not be a good idea //if (!choose_level(face, dist, rel_level)) // defined above // return 0; // Remap face to chosen level face = remap(face, rel_level); if (!face) { err_adv(debug, "INFLATE::do_inflate: can't remap %d from level %d", rel_level, subdiv_level(face)); return 0; } assert(face && face->mesh()); err_adv(debug, "chosen edit level: %d", subdiv_level(face)); // Get set of reachable faces: Bface_list set = Bface_list::reachable_faces(face); assert(set.mesh() != NULL); err_adv(debug, "reachable faces: %d, subdiv level: %d, total faces: %d", set.num(), set.mesh()->subdiv_level(), set.mesh()->nfaces()); if (!set.is_consistently_oriented()) { err_msg("INFLATE::do_inflate: rejecting inconsistently \ oriented surface..."); return 0; }
//! Given a set of enclosed face, activate the widget to sweep out a //! shape. Checks for errors, returns true on success. bool SWEEP_DISK::setup(CGESTUREptr& gest, double dur) { static bool debug = Config::get_var_bool("DEBUG_SWEEP_SETUP",false) || debug_all; if (!(gest && gest->is_dslash())) { err_adv(debug, "SWEEP_DISK::setup: bad gesture"); return false; } // XXX - shouldn't require it is a Panel: Panel* p = dynamic_cast<Panel*>(Bsurface::hit_ctrl_surface(gest->start())); if (!p) { err_adv(debug, "SWEEP_DISK::setup: non-panel"); return false; } Bface_list faces = p->bfaces(); _boundary = faces.get_boundary(); if (_boundary.num_line_strips() != 1) { err_adv(debug, "SWEEP_DISK::setup: error: boundary is not a single piece"); return false; } // Get the best-fit plane, rejecting if the boundary Wpt_list // doesn't lie within 0.1 of its total length from the plane: if (!_boundary.verts().pts().get_plane(_plane, 0.1)) { err_adv(debug,"SWEEP_DISK::setup: Error: can't find plane"); return false; } // Find the center Wpt o = _boundary.verts().pts().average(); // decide guideline direction (normal to plane): Wvec n = _plane.normal(); if (VIEW::eye_vec(o) * n > 0) n = -n; // decide the length for the guideline: double len = world_length(o, GUIDE_LEN); // compute guideline endpoint: Wpt b = o + n.normalized()*len; // try basic setup if (!SWEEP_BASE::setup(dynamic_pointer_cast<LMESH>(faces.mesh()), o, b, dur)) return false; // ******** From here on we accept it ******** _enclosed_faces = faces; return true; }
static int max_subdiv_edit_level(Bface_list all, Bface_list core=Bface_list()) { // what is the deepest subdiv level that is either: // - controlled by a Bbase // - has holes cut // - has new surface regions attached err_adv(debug, "max_subdiv_edit_level:"); if (all.empty()) { assert(core.empty()); err_adv(debug, " face list is empty"); return 0; } assert(all.mesh() && all.contains_all(core)); int R = 0; // level at which deepest edits happened int k = 0; // current level being examined while (!all.empty()) { k++; all = get_subdiv_faces(all,1); if (all.empty()) break; // check for controllers if (!Bbase::find_owners(all).empty()) { err_adv(debug, " controllers at level %d", k); R = k; } // check for holes at this level: if (all.has_any_secondary()) { all = all.primary_faces(); err_adv(debug, " hole at level %d", k); R = k; // holes exist at this level } // check for new regions if (core.empty()) continue; core = get_subdiv_faces(core,1); Bface_list new_faces = core.two_ring_faces().primary_faces(); // see if any of these new ones are actually new: new_faces.set_flags(1); all.clear_flags(); new_faces = new_faces.filter(SimplexFlagFilter(1)); if (!new_faces.empty()) { all.append(new_faces); err_adv(debug, " new faces at level %d", k); R = k; // new stuff exists at this level } } return R; }
//! Being re-activated bool SWEEP_DISK::setup(Panel* p, Bpoint_list points, Bcurve_list curves, Bsurface_list surfs, Wpt_list profile) { static bool debug = Config::get_var_bool("DEBUG_SWEEP_SETUP",false) || debug_all; // XXX - some of the code here is the same as the code in the other setup method // - better to wrap these code into a helper method Bface_list faces = p->bfaces(); _boundary = faces.get_boundary(); if (_boundary.num_line_strips() != 1) { err_adv(debug, "SWEEP_DISK::setup: error: boundary is not a single piece"); return false; } // Get the best-fit plane, rejecting if the boundary Wpt_list // doesn't lie within 0.1 of its total length from the plane: if (!_boundary.verts().pts().get_plane(_plane, 0.1)) { err_adv(debug,"SWEEP_DISK::setup: Error: can't find plane"); return false; } // Find the center Wpt o = _boundary.verts().pts().average(); // decide guideline direction (normal to plane): Wvec n = _plane.normal(); if (VIEW::eye_vec(o) * n > 0) n = -n; // decide the length for the guideline: double len = world_length(o, GUIDE_LEN); // compute guideline endpoint: Wpt b = o + n.normalized()*len; // try basic setup if (!SWEEP_BASE::setup(dynamic_pointer_cast<LMESH>(faces.mesh()), o, b, default_timeout())) return false; // ******** From here on we accept it ******** _points = points; _curves = curves; _surfs = surfs; _surfs.mesh()->toggle_show_secondary_faces(); _profile = profile; _enclosed_faces = faces; return true; }
//! Given boundary curve (near-planar), activate the //! widget to inflate ... bool INFLATE::setup(Bface *bf, double dist, double dur) { reset(); // Given the starting face f and an offset amount h, // determine the appropriate edit level, re-map f to that // level, and "inflate" the portion of the mesh reachable // from f by h, relative to the local edge length. // reject garbage if (!(bf && LMESH::isa(bf->mesh()))) { err_adv(debug, "INFLATE::setup: error: bad face"); return 0; } Lface* f = (Lface*)bf; err_adv(debug, "setup: face at level %d", bf->mesh()->subdiv_level()); // get avg edge length of edges in face: double avg_len = avg_strong_edge_len(f); if (avg_len < epsAbsMath()) { err_adv(debug, "INFLATE::setup: bad average edge length: %f", avg_len); return 0; } // Get set of reachable faces: Bface_list set = Bface_list::reachable_faces(f); assert(set.mesh() != NULL); err_adv(debug, "reachable faces: %d, subdiv level: %d, total faces: %d", set.num(), set.mesh()->subdiv_level(), set.mesh()->nfaces()); // given face set should be an entire connected piece. if (!is_maximal_connected(set )) { err_adv(debug, "INFLATE::setup: rejecting subset of surface..."); return 0; } Bface_list p = set;//get_top_level(set); assert(LMESH::isa(p.mesh())); err_adv(debug, "top level: %d faces (out of %d)", p.num(), p.mesh()->nfaces()); BMESH* m = p.mesh(); if (!m) { err_adv(debug, "INFLATE::setup: Error: null mesh"); return 0; } if (!LMESH::isa(m)) { err_adv(debug, "INFLATE::setup: Error: non-LMESH"); return 0; } if (!p.is_consistently_oriented()) { err_adv(debug, "INFLATE::setup: Error: inconsistently oriented faces"); return 0; } // We ensured the mesh in an LMESH so this is okay: _boundary=p.get_boundary(); if (_boundary.edges().empty()) { err_adv(debug, "INFLATE::setup: Error: No boundary. Quitting."); _boundary.reset(); return 0; } // ******** From here on, we accept it ******** err_adv(debug, "Inflating... %d boundary loops", _boundary.num_line_strips()); _faces = p; _mode = false; _d = _boundary.cur_edges().avg_len(); _mesh = (LMESH*)m; _orig_face = bf; _preview_dist = dist; // Set the timeout duration set_timeout(dur); // Become the active widget and get in the world's DRAWN list: activate(); return true; }