void send_d(CBvert* v, CBface* f) { assert(v && f); Bface_list faces = v->get_faces(); Wvec acc_U(0,0,0); Wvec acc_V(0,0,0); Wvec U_vec,V_vec; UVvec derivative; Wvec vertex_normal = v->norm(); Wvec base_2 = cross(vertex_normal,Wvec(1.0,0.0,0.0)); //use perpend!! Wvec base_3 = cross(vertex_normal,base_2); base_2 = base_2.normalized(); base_3 = base_3.normalized(); for(int i=0; i<faces.num(); i++) { //getting the previously computed face gradients UV_grad grad = face_gradient_map[faces[i]]; U_vec = grad.U_grad; V_vec = grad.V_grad; //rotate to tangent plane double U_magnitude = U_vec.length(); double V_magnitude = V_vec.length(); U_vec = Wvec((base_2 * (base_2 * U_vec)) + (base_3 * (base_3 * U_vec))); V_vec = Wvec((base_2 * (base_2 * V_vec)) + (base_3 * (base_3 * V_vec))); U_vec = U_vec.normalized() * U_magnitude; V_vec = V_vec.normalized() * V_magnitude; acc_U += U_vec; acc_V += V_vec; } //just simple average for now acc_U = (acc_U / double(faces.num()) ); acc_V = (acc_V / double(faces.num()) ); //cerr << " dV = " << acc_V << endl; send_dU(acc_U); send_dV(acc_V); }
inline Wpt_list get_pts(Bface_list& flist, ARRAY<Wvec>& blist) { assert(flist.num() == blist.num()); Wpt_list pts; for (int i = 0; i < flist.num(); i++) { Wpt pt; flist[i]->bc2pos(blist[i], pt); pts += pt; } return pts; }
//compute face gradients and store them inside the map void compute_face_gradients(Patch* patch) { if(valid_gradients) return; face_gradient_map.clear(); Bface_list faces = patch->faces(); UV_grad gradient; UVvec derivative; for(int i=0; i<faces.num(); i++) { derivative = att_function->dFdx(faces[i]); gradient.U_grad[0] = derivative[0]; gradient.V_grad[0] = derivative[1]; derivative = att_function->dFdy(faces[i]); gradient.U_grad[1] = derivative[0]; gradient.V_grad[1] = derivative[1]; derivative = att_function->dFdz(faces[i]); gradient.U_grad[2] = derivative[0]; gradient.V_grad[2] = derivative[1]; face_gradient_map[faces[i]]= gradient; //uses the face pointer as a key } valid_gradients = true; }
void UVdata::split(Bvert* v) { if (!v) return; UVdata* uvd = lookup(v); if (uvd && uvd->_uv_valid) { // If uvd->_uv_valid is true, we must set it to false // and then push the old uv coord onto all the // neighboring faces. Bface_list faces = v->get_all_faces(); for (int i=0; i<faces.num(); i++) { if (lookup(faces[i]) == NULL) { if (debug) { err_msg("UVdata::split: continous vert next to non-uv face!"); GtexUtil::show_tris(Bface_list(faces[i])); WORLD::show(v->loc(), 6, Color::red); } continue; } // get_data(faces[i]); assert(lookup(faces[i]) != NULL); // must be, right? faces[i]->tex_coord(v) = uvd->_uv; } uvd->_uv_valid = false; } }
Skin::Skin( Skin* parent, CBface_list& skel_faces, MULTI_CMDptr cmd) : _skel_faces(skel_faces), _updater(0), _partner(0), _reverse(false) { _inflate = parent->_inflate; err_adv(debug, "Skin::Skin: (child)"); assert(parent && parent->_res_level > 0); set_name(parent->name()); _reverse = parent->_reverse; // assert(!_skel_faces.has_any_secondary()); // Update parent mesh elements to our level. // This also ensures the child patch is created and filled. LMESH::update_subdivision(parent->skin_faces(), 1); err_adv(debug, " updated subdivision at parent"); // Bsurface method: record parent/child relationship mutually. // set _parent = parent and parent->_child = this. // set Patch = child of parent's Patch. // set mesh = child of parent's mesh. // set res level = parent res level - 1. set_parent(parent); err_adv(debug, " set parent"); // Set up our vert mapper, based on the parent: _mapper = subdiv_mapper(parent->_mapper); if (_mapper.is_valid()) err_adv(debug, " set mapper"); else err_adv(debug, " failed to get subdiv mapper"); // Generate verts, edges, faces of the new skin. // But if any already exist, it does not duplicate them. // Also add memes as needed. gen_faces(); err_adv(debug, " generated elements"); Bface_list extras = skin_faces().minus(_mapper.a_to_b(_skel_faces)); if (debug && !extras.empty()) { cerr << "found " << extras.num() << " unexpected faces" << endl; push(extras, cmd); } // finish up: create child or join to skeleton: finish_ctor(cmd); }
//! 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; }
Bvert_list LMESH::get_subdiv_inputs(CBvert_list& verts) { static bool debug = Config::get_var_bool("DEBUG_LMESH_SUBDIV_INPUTS",false); // Given a set of vertices from the same LMESH, return // the vertices of the parent LMESH that affect the // subdivision locations of the given vertices. // Require verts share common LMESH // XXX - could relax this, provided we test each Bvert // to ensure it is really an Lvert. if (!isa(verts.mesh())) return Bvert_list(); // Get direct parent vertices and edges Bvert_list vp; // vertex parents Bedge_list ep; // edge parents get_parents(verts, vp, ep); err_adv(debug, "%d verts: parents: %d verts, %d edges", verts.num(), vp.num(), ep.num()); // Clear flags of all adjacent faces clear_face_flags(vp); ep.clear_flag02(); // Put all adjacent faces into a list Bface_list faces = get_q_faces(vp); err_adv(debug, "parent faces from verts: %d", faces.num()); try_append(faces, ep.get_primary_faces()); err_adv(debug, "parent faces from edges too: %d", faces.num()); // Pull out the vertices: return faces.get_verts(); }
bool SELECT_WIDGET::select_faces(CPIXEL_list& pts) { err_adv(debug, "SELECT_WIDGET::select_faces:"); if (pts.num() < 2) { err_adv(debug, " too few points: %d", pts.num()); return false; } Bface* f = find_face(pts[0], 0.25, MIN_PIX_AREA); if (!(f && f->is_selected())) { err_adv(debug, " bad starter face"); return false; } // // XXX - Old code (to be deleted). Selects faces individually instead of as // // a group: // for (int i=0; i<pts.num(); i++) // try_select_face(pts[i], 0.1); Bface_list flist; for(int i = 0; i < pts.num(); ++i){ f = find_face(pts[i], 0.1, MIN_PIX_AREA); if (!f || f->is_selected()) continue; flist += f; } if(flist.num() > 0){ WORLD::add_command(new MESH_SELECT_CMD(flist)); err_adv(debug, " succeeded"); return true; } err_adv(debug, " no faces selected"); return false; }
//! 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; }
void remove_nodes(Bface_list& flist, ARRAY<Wvec>& blist, double min_dist, ARRAY<OctreeNode*>& t) { // if (flist.num() != blist.num()) { // return; // } assert(flist.num() == blist.num()); Wpt_list pts = get_pts(flist, blist); ARRAY< ARRAY<int> > N; ARRAY<bool> to_remove; for (int i = 0; i < pts.num(); i++) { N += ARRAY<int>(); to_remove += false; } for (int i = 0; i < pts.num(); i++) { for (int j = 0; j < t[i]->neibors().num(); j++) { int index = t[i]->neibors()[j]->get_term_index(); if (index < pts.num()) { if (pts[i].dist(pts[index]) < min_dist) { N[i] += index; N[index] += i; } } else { //cerr << "Sps Warning, index > pts.num()" << endl; } } } priority_queue< Priority, vector<Priority> > queue; ARRAY<int> versions; for (int i = 0; i < pts.num(); i++) { if (!to_remove[i] && !N[i].empty()) { Priority p; p._priority = center(pts, N[i]).dist(pts[i]); p._index = i; p._version = 0; queue.push(p); } versions += 0; } while (!queue.empty()) { Priority p = queue.top(); queue.pop(); int r = p._index; if (p._version == versions[r]) { to_remove[r] = true; for (int i = 0; i < N[r].num(); i++) { N[N[r][i]] -= r; versions[N[r][i]]++; if (!N[N[r][i]].empty()) { Priority q; q._priority = center(pts, N[N[r][i]]).dist(pts[N[r][i]]); q._index = N[r][i]; q._version = versions[N[r][i]]; queue.push(q); } } } } versions.clear(); Bface_list ftemp(flist); ARRAY<Wvec> btemp(blist); flist.clear(); blist.clear(); for (int i = 0; i < ftemp.num(); i++) if (!to_remove[i]) { flist += ftemp[i]; blist += btemp[i]; } }
void ProxySurface::trim_proxy_surface() { assert(_proxy_mesh); int n = 0; //number of faces outside the bounding box //get all the quads Bface_list faces = _proxy_mesh->faces(); //clear out all the markings for(int i=0; i < faces.num(); ++i) { if(faces[i]) ProxyData::set_mark(faces[i],this, false); //else // cerr << "FACE is NULL" << endl; } //mark all the faces that do not overap bounding box for(int i=0; i < faces.num(); ++i) { if(faces[i]){ bool t1 = (is_inside_bounding_box(faces[i]->e1())) ? true : false; bool t2 = (is_inside_bounding_box(faces[i]->e2())) ? true : false; bool t3 = (is_inside_bounding_box(faces[i]->e3())) ? true : false; // If all the edges are outside, then mark the face if(!t1 && !t2 && !t3){ //cerr << "we can delete this face" << endl; ProxyData::set_mark(faces[i], this, true); n++; } }else { //cerr << "FACE is NULL" << endl; } } if(n < 1) return; //for all verts check to see if all the faces that it is attached to has a marked Bvert_list verts = _proxy_mesh->verts(); for(int i=0; i < verts.num(); ++i) { ARRAY<Bface*> ret; verts[i]->get_quad_faces(ret); // Make sure that all adjasent faces need to be deleted bool do_it=true; for(int k=0; k < ret.num(); ++k) { if(ret[k]){ assert(ret[k]->is_quad()); if(!ProxyData::get_mark(ret[k], this) || !ProxyData::get_mark(ret[k]->quad_partner(), this)) { // cerr << "vert degree " << verts[i]->p_degree() << endl; do_it = false; break; } } } if(do_it){ UVpt remove_uv; UVdata::get_uv(verts[i], remove_uv); remove_vert_grid(remove_uv); _proxy_mesh->remove_vertex(verts[i]); _proxy_mesh->changed(); } } //clean up faces Bface_list faces2 = _proxy_mesh->faces(); for(int i=0; i < faces2.num(); ++i) { if(!(faces2[i]->is_quad()) || !(faces2[i]->quad_partner())){ _proxy_mesh->remove_face(faces2[i]); _proxy_mesh->changed(); } } //debug_grid(); }
Skin* Skin::create_multi_sleeve( Bface_list interior, // interior skeleton surface VertMapper skel_map, // tells how some skel verts are identified MULTI_CMDptr cmd) { err_adv(debug, "Skin::create_multi_sleeve"); //assert(!has_secondary_any_level(interior)); assert(cmd != 0); if (!skel_map.is_valid()) { err_msg("Skin::create_multi_sleeve: invalid skel map"); return 0; } Bface_list exterior = interior.exterior_faces(); Bface_list all_skel_faces = interior + exterior; // need an LMESH that contains all faces LMESH* mesh = LMESH::upcast(all_skel_faces.mesh()); if (!mesh) { err_adv(debug, " bad skel mesh"); return 0; } // Get relative refinement level int R = max_subdiv_edit_level(all_skel_faces, interior); err_adv(debug, " skel region res level: %d", R); LMESH* ctrl = mesh->control_mesh(); int old_lev = ctrl->cur_level(); int ref_lev = mesh->subdiv_level() + R; ctrl->update_subdivision(ref_lev); if (ref_lev < old_lev) ctrl->update_subdivision(old_lev); Skin* cur = new Skin(mesh, exterior, skel_map, R, false, "sleeve", cmd); cur->set_all_sticky(); cur->freeze(cur->skin_faces().get_boundary().edges().get_verts()); for (int k=1; k<=R; k++) { err_adv(debug, " top of loop: k = %d", k); // XXX - temporary if (!check(interior.mesh()->faces())) return cur; // Update the skeleton to the next level LMESH::update_subdivision(interior + exterior, 1); // Map skel faces to next level. Avoid new holes. // Take account of new regions that don't exist at // previous level. err_adv(debug, " getting interior subdiv faces"); int n = interior.num(); interior = get_subdiv_faces(interior, 1); // no holes can form here if (4*n != interior.num()) { err_adv(debug, " *** ERROR *** got %d interior subdiv faces from %d", interior.num(), n); } err_adv(debug, " getting skel subdiv faces"); n = cur->skel_faces().num(); exterior = get_subdiv_faces(cur->skel_faces(), 1); if (4*n != exterior.num()) { err_adv(debug, " *** ERROR *** got %d exterior subdiv faces from %d", exterior.num(), n); } // check for holes: if (exterior.has_any_secondary()) { err_adv(debug, " removing secondary skel faces at level %d", k); exterior = exterior.primary_faces(); // remove holes } // check for new regions: err_adv(debug, " checking for new faces"); Bface_list new_faces = interior.two_ring_faces().minus(interior + exterior); assert(new_faces.is_all_primary()); // must be true (we think) if (!new_faces.empty()) { err_adv(debug, " adding %d new faces at level %d", new_faces.num(), k); exterior.append(new_faces); } // get version of skel_map at new level: cur = new Skin(cur, exterior, cmd); // make the ones on or near the boundary "sticky" cur->set_all_sticky(false); cur->set_sticky( cur->skin_faces(). get_boundary(). edges(). get_verts(). one_ring_faces(). get_verts() ); cur->freeze(cur->skin_faces().get_boundary().edges().get_verts()); // put memes in place, not just use position they inherited // from subdivision cur->do_update(); } // Join skin to skel at level R err_adv(debug, " joining to skel..."); if (cur->join_to_skel(interior, cmd)) { err_adv(debug, " ...succeeded"); } else { err_adv(debug, " ...failed"); } _debug_instance = cur; return upcast(cur->control()); }
bool UVdata::handle_subdiv_calc() { // Some of you may have been wondering why anyone would // need UVdata on an edge. The whole reason is to pick up // this here callback, which is generated when it is time // to recompute subdivision values for an edge or vertex. // (I.e., this is also why you need UVdata on a vertex). // // XXX - Currently we aren't keeping track of when // subdivision uv-coords need to be recomputed. We // just get this callback whenever subdivision // *locations* need to be recomputed. So the wrong // thing happens if you change the uv-coords of the // control mesh but not the vertex locations or // connectivity. And if you change the vertex // locations but not the uv-coords the latter get // recomputed even though they don't need to be. // XXX - even worser: working on a deadline, we're changing // mesh connectivity at arbitrary subdivision levels // (not previously done), and that's leading to an assertion // failure in subdiv_uv(Bedge*, Bface*) below... // needs to get fixed (later) // lem - 1/6/2002 // return 0; // Don't compute it more than once. Current policy is uv // coords are assigned but not later edited or changed ever. // Why? Because with mesh connectivity edits happening at // arbitrary levels of subdivision, we don't want parent // elements forcing inappropriate uv values on elements at // current level. -- lem 12/29/2004; same deadline :( if (_did_subdiv) { // return false; } _did_subdiv = true; if (is_edge(simplex())) { Ledge* e = (Ledge*) simplex(); if ( !e->get_face() ) return false; if (is_continuous(e)) { // Set a single uv-coord on the subdivision vertex // to be used regardless of the face containing it. _set(e->subdiv_vertex(), subdiv_uv(e, e->get_face())); } else { // Compute 2 separate subdiv uv-coords, set each one // on the 3 sub-faces on each side of the edge. // (If a face is missing or has no uv-coords it's a no-op). set_subdiv_uv(e, (Lface*)e->f1()); set_subdiv_uv(e, (Lface*)e->f2()); } } else if (is_vert(simplex())) { Lvert* v = (Lvert*) simplex(); if ( !v->get_face() ) return false; if (is_continuous(v)) { // Set a single uv-coord on the subdivision vertex // to be used regardless of the face containing it. _set(v->subdiv_vertex(), subdiv_uv(v, v->get_face())); } else { // Compute and set a separate uv-coord for each face // surrounding the subdiv vert: Bface_list faces; v->get_faces(faces); for (int i=0; i<faces.num(); i++) set_subdiv_uv(v, (Lface*)faces[i]); } } else { // We get here if this UVdata is on a Bface or a null simplex. // Neither should ever happen. assert(0); } // Returning 0 means we are not overriding the normal // subdivision calculation. return 0; }