void EdgeStrip::build(Bvert* v, Bedge* e, CSimplexFilter& filter) { // continue building the edge strip, starting with the // given edge e. if v is not null, e must contain v. // in that case v will be the leading vertex of the strip. // must have an edge to proceed, // and the edge must be accepted by the filter. if (!(e && filter.accept(e))) // someone has to punch its ticket return; assert(!v || e->contains(v)); static Bvert_list stack(64); stack.clear(); // first loop: build_line_strip(v ? v : e->v1(), e, filter, stack); // get the rest of them while (!stack.empty()) { if ((v = stack.pop()) && (e = next_edge(v, stack, filter))) build_line_strip(v, e, filter, stack); } }
Bvert_list BvertGrid::col(int i) const { Bvert_list ret; for (int j=0; j<nrows(); j++) ret.push_back(vert(i,j)); return ret; }
bool Bface::get_quad_verts(Bvert_list& verts) const { verts.clear(); Bvert *v1=nullptr, *v2=nullptr, *v3=nullptr, *v4=nullptr; if (!get_quad_verts(v1,v2,v3,v4)) return 0; verts.push_back(v1); verts.push_back(v2); verts.push_back(v3); verts.push_back(v4); return 1; }
Bvert_list Bface_list::interior_verts() const { // Return list vertices that are not adjacent to any external face. Bvert_list ret = get_verts(); for (Bvert_list::size_type i=0; i<get_boundary().verts().size(); i++) { Bvert_list::iterator it; it = std::find(ret.begin(), ret.end(), get_boundary().verts()[i]); ret.erase(it); } return ret; // mark internal faces w/ flag 1, external faces with flag 0: mark_faces(); return get_verts().filter(VertFaceDegreeFilter(0, SimplexFlagFilter(0))); }
inline VertMapper subdiv_mapper(CVertMapper& pmap) { Bedge_list a_edges = pmap.a_edges(); Bedge_list b_edges = pmap.a_to_b(a_edges); assert(a_edges.num() == b_edges.num()); if (0 && debug) { err_msg("parents: verts: %d --> %d, edges: %d --> %d", pmap.A().num(), pmap.B().num(), a_edges.num(), b_edges.num()); err_msg("children: verts: %d --> %d", (child_verts<Bvert_list,Lvert>(pmap.A()) + child_verts<Bedge_list,Ledge>(a_edges)).num(), (child_verts<Bvert_list,Lvert>(pmap.B()) + child_verts<Bedge_list,Ledge>(b_edges)).num()); Bvert_list c = (child_verts<Bvert_list,Lvert>(pmap.A()) + child_verts<Bedge_list,Ledge>(a_edges)); if (c.has_duplicates()) { err_msg("*** child verts have duplicates ***"); if (pmap.A().has_duplicates()) { err_msg(" A verts have duplicates"); } if (pmap.a_edges().has_duplicates()) { err_msg(" A edges have duplicates"); } if (child_verts<Bvert_list,Lvert>(pmap.A()).has_duplicates()) { err_msg(" vert children have duplicates"); } if (child_verts<Bedge_list,Ledge>(pmap.a_edges()).has_duplicates()) { err_msg(" edge children have duplicates"); } WORLD::show_pts(c.pts()); } } return VertMapper( child_verts<Bvert_list,Lvert>(pmap.A()) + child_verts<Bedge_list,Ledge>(a_edges), child_verts<Bvert_list,Lvert>(pmap.B()) + child_verts<Bedge_list,Ledge>(b_edges) ); }
/*! Given edge e containing endpoint v, return the subdiv verts at the current level, in order starting at v and running to the other endpoint. */ inline Bvert_list get_cur_level_verts(Bvert* v, Bedge* e) { assert(v && e && e->contains(v)); Bvert_list ret; LMESH* mesh = LMESH::upcast(e->mesh()); if (mesh) { ((Ledge*)e)->get_subdiv_verts(mesh->rel_cur_level(), ret); } else { ret += e->v1(); ret += e->v2(); } if (e->v1() != v) ret.reverse(); return ret; }
bool EdgeStrip::get_chain(int& k, Bvert_list& chain) const { // Return the chain starting at index k, // and advance k to the start of the next chain. chain.clear(); // get set... if (k < 0 || k >= num()) // if out of range, reject return false; if (!has_break(k)) // if k is not a chain endpoint, reject return false; chain += vert(k); // add leading vertex do { chain.add(next_vert(k)); // add subsequent vertex } while (!has_break(++k)); // advance k, break at chain end return true; }
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(); }
inline double compute_h(Bvert* v) { assert(v); PCell_list cells = Panel::find_cells(v->get_faces()); if (cells.size() == 2) { // common case: vertex in a tube ring (2 neighboring cells) if (Bpoint::find_controller(v) || Bcurve::find_controller(v)) return cells[0]->shared_boundary(cells[1]).avg_len()/2; Bvert_list verts = reorder(cells[0]->shared_boundary(cells[1])); double num = verts.size()-1; assert(num > 1); int index = verts.get_index(v); assert(index != -1); double h = (compute_h(verts.front()) + compute_h(verts.back())) / 2; return h * (1 + min(index/num, 1-index/num)); } else if (cells.size() > 2) { // multiple adjacent cells return PCell::shared_edges(cells).avg_len()/2; } else if (cells.size() == 1) { // just one cell, e.g. tip of a tube, or part of a disk if (cells[0]->num_corners() == 3) { if (cells[0]->nbrs().size() != 1) { return cells[0]->boundary_edges().avg_len()/2; } assert(cells[0]->nbrs().size() == 1); return 0; // it's the tip of the triangle } else if (cells[0]->num_corners() == 4) { if (cells[0]->nbrs().size() == 0) { return cells[0]->boundary_edges().avg_len()/2; } else if (cells[0]->nbrs().size() == 1) { // or maybe should do same rule as next case Bedge_list end_edges = quad_cell_end_edges(cells[0]); err_adv(debug, "found %d end edges", end_edges.size()); return end_edges.avg_len()/2; } return v->strong_edges().avg_len()/2; } if (Bpoint::find_controller(v) || Bcurve::find_controller(v)) return cells[0]->boundary_edges().filter(BorderEdgeFilter()||BcurveFilter()).avg_len()/2; Bvert_list nbrs; v->get_nbrs(nbrs); assert(!nbrs.empty()); return 1.5 * compute_h(nbrs[0]); } err_adv(debug, "compute_h: unexpected number of cells: %d", cells.size()); return -1; }
inline int match_span(Bvert* v, Bedge* e, CPIXEL_list& trail, int k, double thresh) { // Ensure various required conditions are true: if (!(v && e && e->contains(v) && trail.valid_index(k))) { err_adv(debug, "match_span: invalid vert/edge/index"); return -1; } // Get the chain of vertices at the "current" mesh level: Bvert_list verts = get_cur_level_verts(v, e); assert(verts.num() > 1); // Ensure the vertex chain starts near the current // position in the pixel trail: if (trail[k].dist(verts.first()->wloc()) > thresh) { err_adv(debug, "match_span: vert chain too far from pixel trail: %f > %f", trail[k].dist(verts.first()->wloc()), thresh); return -1; } // Test that the length of the refined edge is // close to the length of the chosen span. // // This is a cheap way of seeing that the projected edge // lies reasonably along the given portion of the pixel trail. int ret = next_match(verts.last(), trail, k, thresh); if (ret < 0) { err_adv(debug, "match_span: can't match next vert"); return -1; } double vlen = pix_len(verts.wpts()); if (vlen < 0) return -1; // Measure length of the trail, including distance to // beginning and end of the projected edge: double tlen = length(trail, k, ret); double e1 = verts.first()->pix().dist(trail[ k]); double e2 = verts.last ()->pix().dist(trail[ret]);; err_adv(debug, "adding %3.0f, %3.0f", e1, e2); err_adv(debug, "edge length: %3.0f, span length: %3.0f, ratio: %1.2f: %s", vlen, tlen, tlen/vlen, (tlen > 1.2*vlen) ? "rejected" : "accepted"); if (tlen > 1.2*vlen) return -1; return ret; }
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 (!dynamic_pointer_cast<LMESH>(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.size(), vp.size(), ep.size()); // 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.size()); try_append(faces, ep.get_primary_faces()); err_adv(debug, "parent faces from edges too: %d", faces.size()); // Pull out the vertices: return faces.get_verts(); }
bool OVERSKETCH::compute_offsets(CPIXEL_list& pts, CEdgeStrip& sils) { double yardstick = compute_yardstick(sils.edges(), debug); assert(sils.num_line_strips() == 1); Bvert_list chain; int k = 0; sils.get_chain(k, chain); int count = 0; vector<double> offsets; Wpt_list new_locs = chain.pts(); for (Bvert_list::size_type i=0; i<chain.size(); i++) { offsets.push_back(compute_offset(chain[i], pts, yardstick)); if (offsets.back() > 0) { count++; } } err_adv(debug, "found %d/%d offsets", count, chain.size()); apply_offsets(chain, offsets); return true; }
inline void debug_check_verts(const string& msg, CBvert_list& verts, CBvert_list& dirty_verts) { Bvert_list A = verts.filter(BitSetSimplexFilter(Lvert::DIRTY_VERT_LIST_BIT)); if (!dirty_verts.contains_all(A)) { Bvert_list bad = A.minus(dirty_verts); cerr << msg << ": found " << bad.size() << " vertices missing from dirty list" << endl; WORLD::show_pts(bad.pts(), 8, Color::red); } Bvert_list B = verts.filter(BitClearSimplexFilter(Lvert::DIRTY_VERT_LIST_BIT)); if (dirty_verts.contains_any(B)) { Bvert_list bad = dirty_verts.minus(B); cerr << msg << ": found " << bad.size() << " unexpected vertices in dirty list" << endl; WORLD::show_pts(bad.pts(), 8, Color::blue); } }
inline void add_p(Lvert* v, Bvert_list& vp, Bedge_list& ep) { // Helper method used below in get_parents(); // Given an Lvert, add its parent simplex to the // appropriate list depending on whether the parent // is an Lvert or Ledge. assert(v); Bsimplex* p = v->parent(); if (!p) return; if (is_vert(p)) vp.push_back((Bvert*)p); else if (is_edge(p)) ep.push_back((Bedge*)p); else assert(0); }
inline void make_strip(Bvert_list chain, int k0, int k1, EdgeStrip& strip) { assert(chain.forms_chain()); assert(0 <= k0 && k0 < (int)chain.size() && 0 <= k1 && k1 < (int)chain.size()); assert(k0 != k1); if (k0 > k1) { std::reverse(chain.begin(), chain.end()); int n = chain.size()-1; k0 = n - k0; k1 = n - k1; } strip.reset(); for (int i=k0; i<k1; i++) { strip.add(chain[i], lookup_edge(chain[i], chain[i+1])); } }
void Skin::draw_debug() { if (!_show_memes) return; //if (!debug) // return; // frozen: blue // sticky: orange // unglued: grey Skin* cur = upcast(cur_subdiv_bbase()); if (!cur) return; Bvert_list verts = cur->skin_verts(); Bvert_list frozen = cur->frozen_verts(verts); verts = verts.minus(frozen); Bvert_list sticky = cur->sticky_verts(verts); Bvert_list unglued = verts.minus(sticky); GL_VIEW::draw_pts(frozen.pts(), Color::blue, 0.8, 8); GL_VIEW::draw_pts(sticky.pts(), Color::orange, 0.8, 8); GL_VIEW::draw_pts(unglued.pts(), Color::grey6, 0.8, 8); if (debug) GL_VIEW::draw_lines( bundle_lines(verts.pts(), cur->track_points(verts)), Color::yellow, 0.8, 1, false ); if (debug) GL_VIEW::draw_lines( bundle_lines(verts.pts(), centroids(verts)), Color::red, 0.8, 1, false ); }
bool BvertGrid::build( CBvert_list& bottom, // bottom row CBvert_list& top, // top row CBvert_list& left, // left column CBvert_list& right // right column ) { // Vertices of bottom and top run left to right. // On the left and right they run bottom to top. // Check everything is righteous: if (bottom.size() < 2 || bottom.size() != top.size() || left.size() < 2 || left.size() != right.size() || bottom.front() != left.front() || bottom.back() != right.front() || top.front() != left.back() || top.back() != right.back() || !bottom.same_mesh() || !top.same_mesh() || !left.same_mesh() || !right.same_mesh() || bottom.mesh() == nullptr) { err_msg("BvertGrid::build: can't deal with CRAP input"); std::ostream_iterator<Bvert*> err_it (std::cerr, ", "); cerr << "bottom: "; std::copy(bottom.begin(), bottom.end(), err_it); cerr << endl; cerr << "top: "; std::copy(top.begin(), top.end(), err_it); cerr << endl; cerr << "left: "; std::copy(left.begin(), left.end(), err_it); cerr << endl; cerr << "right: "; std::copy(right.begin(), right.end(), err_it); cerr << endl; return false; } // Wipe the old: clear(); // Build the new... // bottom row: _grid.push_back(bottom); BMESHptr m = bottom.mesh(); assert(m); // Internal rows: for (Bvert_list::size_type j=1; j<left.size()-1; j++) { Bvert_list row; // vertices for row j row.push_back(left[j]); // add first vertex for row j for (Bvert_list::size_type i=1; i<bottom.size()-1; i++) row.push_back(m->add_vertex()); // add internal vertices row.push_back(right[j]); // add last vertex for row j _grid.push_back(row); } // top row: _grid.push_back(top); // Now compute cached values: cache(); return true; }
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(); }
inline Bvert_list reorder(CBedge_list& edges) { Bvert_list ret; Bvert_list verts = edges.get_verts(); for (Bvert_list::size_type i = 0; i < verts.size(); i++) if (Bpoint::find_controller(verts[i]) || Bcurve::find_controller(verts[i])) { ret.push_back(verts[i]); break; } if (ret.empty()) return ret; for (Bvert_list::size_type i = 1; i < verts.size(); i++) { for (Bedge_list::size_type j = 0; j < edges.size(); j++) { Bvert* v = edges[j]->other_vertex(ret.back()); if (v && std::find(ret.begin(), ret.end(), v) == ret.end()) { ret.push_back(v); break; } } } err_adv(debug, " reorder: num of verts: %d", ret.size()); return ret; }