//! 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; }
bool PAPER_DOLL::init(CGESTUREptr& g) { if (!(g && g->is_stroke())) return false; if (g->below_min_length() || g->below_min_spread()) return false; if (!g->is_ellipse()) { err_adv(debug, "PAPER_DOLL::init: non-ellipse"); return false; } Panel* p = dynamic_cast<Panel*>( Bsurface::get_surface(get_top_level(VisRefImage::get_faces(g->pts()))) ); err_adv(debug, "PAPER_DOLL::init: %s panel", p?"found":"could not find"); if (!(p && p->is_selected())) { err_adv(debug, "PAPER_DOLL::init: ellipse not over selected panel"); return false; } assert(p && p->bfaces().size() > 0); Bface_list faces = Bface_list::reachable_faces(p->bfaces().front()); assert(!faces.empty()); if (!faces.is_planar(deg2rad(1.0))) { err_adv(debug, "PAPER_DOLL::init: region is not planar"); return false; } EdgeStrip boundary = faces.get_boundary(); if (boundary.empty()) { err_adv(debug, "PAPER_DOLL::init: region has no boundary"); return false; } Bsurface_list surfs = Bsurface::get_surfaces(faces); if (!are_all_bsurfaces<Panel>(surfs)) { err_adv(debug, "PAPER_DOLL::init: region not all panels"); return 0; } err_adv(debug, "PAPER_DOLL::init: proceeding..."); err_adv(debug, " boundary edges: %d, components: %d, panels: %d", boundary.edges().size(), boundary.num_line_strips(), surfs.num() ); if (get_instance()->build_primitive(faces)) { err_adv(debug, " ... succeeded"); return true; } err_adv(debug, " ... failed"); return false; }
//! 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; }
bool OVERSKETCH::apply_offsets(CBvert_list& sil_verts, const vector<double>& sil_offsets) { // XXX - preliminary... assert(sil_verts.size() == sil_offsets.size()); // Expand region around oversketched silhouette verts. // XXX - Should compute the one-ring size, not use "3" Bface_list region = sil_verts.one_ring_faces().n_ring_faces(3); // Find the minimum distance to the silhouette verts from the // outer boundary of the region Wpt_list sil_path = sil_verts.pts(); double R = min_dist(region.get_boundary().verts().pts(), sil_path); Bvert_list region_verts = region.get_verts(); Wpt_list new_locs = region_verts.pts(); vector<double> offsets; for (Bvert_list::size_type i=0; i<region_verts.size(); i++) { Wpt foo; int k = -1; double d = sil_path.closest(region_verts[i]->loc(), foo, k); if (k < 0 || k >= (int)sil_offsets.size()) { err_adv(debug, "OVERSKETCH::apply_offsets: error: can't find closest"); continue; } double s = swell_profile(d/R); double h = sil_offsets[k] * s; // err_adv(debug, " d: %f, d/R: %f, s: %f", d, d/R, s); offsets.push_back(h); new_locs[i] += region_verts[i]->norm()*h; // WORLD::show(region_verts[i]->loc(), new_locs[i], 1); } // now apply new locs // FIT_VERTS_CMDptr cmd = make_shared<FIT_VERTS_CMD>(region_verts, new_locs); SUBDIV_OFFSET_CMDptr cmd = make_shared<SUBDIV_OFFSET_CMD>(region_verts, offsets); cmd->doit(); WORLD::add_command(cmd); 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; }