bool Bface::get_quad_verts(Bvert*& a, Bvert*& b, Bvert*& c, Bvert*& d) const { // Return CCW verts a, b, c, d as in the picture, orienting // things so that the weak edge runs NE as shown: // // d ---------- c = w->v2() ^ // | / | | // | / | | // | w / | tan1 tan2 | // | / | --------> | // | / f | | // |/ | // a ---------- b // = w->v1() // if (!is_quad()) return 0; Bedge* w = weak_edge(); Bface* f = w->ccw_face(w->v2()); a = w->v1(); b = f->next_vert_ccw(a); c = w->v2(); d = f->quad_vert(); return true; }
bool Bface_list::grow_connected(Bface* f, CSimplexFilter& pass) { // Collect all reachable faces whose flag == 1, starting at f, // crossing only edges that are accepted by the given filter. if (!(f && f->flag() == 1)) return false; f->set_flag(2); push_back(f); // check each neighboring edge: for (int i=1; i<4; i++) { Bedge* e = f->e(i); if (pass.accept(e)) { // check each adjacent face // (includes this, but that will be a no-op): for (int j=1; j<=e->num_all_faces(); j++) grow_connected(e->f(j), pass); } } return true; }
/********************************************************************** * TriStrip: **********************************************************************/ Bface* TriStrip::backup_strip(Bface* f, Bvert*& a) { // we'd like to draw a triangle strip starting at the // given triangle and proceeding "forward." but to get // the most bang for the buck, we'll first "backup" over // as many triangles as possible to find a starting place // from which we can generate a longer strip. assert(!f->flag()); mark_face(f); Bface* ret = f; Bvert* b = f->next_vert_ccw(a); Bedge* e; int i = 0; while((e = f->edge_from_vert((i%2) ? b : a)) && e->consistent_orientation() && e->is_crossable() && (f = e->other_face(f)) && is_cleared(f)) { mark_face(f); ret = f; Bvert* d = f->other_vertex(a,b); b = a; a = d; i++; } _orientation = ((i%2) != 0); return ret; }
void EdgeStrip::build_with_tips(CBedge_list& edges, CSimplexFilter& filter) { // Build the strip from the given pool of edges, with the // given filter. Try to start the edge strip at the "tips" of // chains of edges of the desired type. The given filter // should just screen for edges of the desired kind; // internally this method also screens for edges that have not // yet been reached (added to the strip). // Clear edge flags to screen for unreached edges: set_adjacent_edges(edges.get_verts(), 1); edges.clear_flags(); // Pull out the edge tips: Bedge_list tips = edges.filter(ChainTipEdgeFilter(filter)); // Construct the filter that screens out previously reached // edges: UnreachedSimplexFilter unreached; AndFilter wanted = unreached + filter; int k; // Start from all the tips first: for (k=0; k<tips.num(); k++) { Bedge* e = tips[k]; Bvert* v = (e->v2()->degree(filter) != 2) ? e->v2() : e->v1(); build(v, e, wanted); } // Now check the rest: for (k=0; k<edges.num(); k++) build(0, edges[k], wanted); }
inline Bedge* find_edge(CPIXEL& pix) { Wvec bc; Bedge* e = near_edge(find_face(pix, 1, bc), bc); if (e && e->is_weak()) return 0; return e; }
//! Same as try_select_edge(), but deselects. //! Also requires the found edge is currently selected. bool SELECT_WIDGET::try_deselect_edge(CPIXEL &pix) { Bedge* e = find_edge(pix); if (!(e && e->is_selected())) return false; WORLD::add_command(new MESH_DESELECT_CMD(e)); return true; }
virtual bool accept(CBsimplex* s) const { if (!is_edge(s)) // reject if non-edge return false; Bedge* e = (Bedge*)s; if (e->sil_stamp() == _stamp) // reject if previously checked return 0; e->set_sil_stamp(_stamp); // mark as checked this frame if (_skip_secondary && e->is_secondary()) // reject secondary edges as needed return false; return e->is_sil(); // accept if silhouette }
bool OVERSKETCH::find_matching_sil(CGESTUREptr& g) { err_adv(debug, "OVERSKETCH::find_matching_sil"); const size_t MIN_GEST_PTS = 10; if (!(g && g->pts().size() >= MIN_GEST_PTS)) return false; if (BMESH::_freeze_sils) return false; VisRefImage *vis_ref = VisRefImage::lookup(VIEW::peek()); if (!vis_ref) return false; // 1. see if the gesture runs along a silhouette // of a single mesh. SilEdgeFilter sil_filter; const PIXEL_list& pts = g->pts(); BMESHptr mesh = nullptr; for (PIXEL_list::size_type i=0; i<pts.size(); i++) { Bedge* e = (Bedge*) vis_ref->find_near_simplex(pts[i], SIL_SEARCH_RAD, sil_filter); if (!(e && e->mesh())) { err_adv(debug, " gesture too far from silhouette"); return false; } if (mesh && mesh != e->mesh()) { err_adv(debug, " found a second mesh, rejecting"); return false; } mesh = e->mesh(); } if (!dynamic_pointer_cast<LMESH>(mesh)) { err_adv(debug, " found non-LMESH, rejecting"); return false; } err_adv(debug, " gesture aligns with silhouette"); err_adv(debug, " mesh level %d", mesh->subdiv_level()); // 2. extract the portion of the silhouette that matches // the gesture, store in _selected_sils return find_matching_sil(pts, mesh->sil_strip()); }
bool Skin::copy_edge(Bedge* a) const { // copy edge attributes, e.g. from skel to skin Bedge* b = _mapper.a_to_b(a); if (!(a && b)) return false; if (a->is_weak()) b->set_bit(Bedge::WEAK_BIT); // more? return true; }
inline bool copy_edge(Bedge* a, CVertMapper& vmap) { // copy edge attributes, e.g. from skel to skin Bedge* b = vmap.a_to_b(a); if (!(a && b)) return false; if (a->is_weak()) b->set_bit(Bedge::WEAK_BIT); // more? return true; }
CWvec& Bface::vert_normal(CBvert* v, Wvec& n) const { // for gouraud shading: return appropriate // normal to use at a vertex of this face assert(this->contains(v)); if(!v->is_crease()) { n = v->norm(); return n; } // take average of face normals in star of v, // using faces which can be reached from this // face without crossing a crease edge n = weighted_vnorm(this, v); // add weighted normal from this face int count = 1; // count of faces processed // wind around v in clockwise direction // but don't cross a crease edge CBface* f = this; Bedge* e = edge_from_vert(v); for (; e&&!e->is_crease() && (f=e->other_face(f)); e=f->edge_from_vert(v)) { n += weighted_vnorm(f, v); if (++count > v->degree()) { // this should never happen, but it does // happen on effed up models // (i.e. when "3rd faces" get added) break; } } // wind around v in counter-clockwise direction; // as before, don't cross a crease edge f = this; e = edge_before_vert(v); for(; e&&!e->is_crease()&&(f=e->other_face(f)); e=f->edge_before_vert(v)) { n += weighted_vnorm(f, v); if(++count > v->degree()) break; } n = n.normalized(); return n; }
int Bedge::redefine(Bvert *v, Bvert *u) { // redefine this edge, replacing v with u // precondition: // edge does not already contain u. // v is a vertex of this edge. // faces have already been detached. // can't duplicate an existing edge. assert(contains(v) && nfaces() == 0); if (contains(u)) return 0; Bedge* dup = 0; if (v == _v1) { if ((dup = u->lookup_edge(_v2))) { // can't redefine, but if this is a crease edge // should ensure the duplicated edge is also if (is_crease()) dup->set_crease(crease_val()); return 0; } // can redefine: *_v1 -= this; // say bye to old _v1 _v1 = u; // record new _v1 *_v1 += this; // say hi to new _v1 } else if (v == _v2) { // see comments above if ((dup = u->lookup_edge(_v1))) { if (is_crease()) dup->set_crease(crease_val()); return 0; } *_v2 -= this; _v2 = u; *_v2 += this; } else assert(0); geometry_changed(); return 1; }
EdgeStrokePool::~EdgeStrokePool() { int i = 0; // loop index for (i = 0; i < _strip.edges().num(); i++) { Bedge* edge = _strip.edges()[i]; assert(edge); //SimplexData* d = edge->find_data(this->static_name()); SimplexData* d = edge->find_data((uintptr_t)&(this->foo)); edge->rem_simplex_data(d); } i = 0; while (i < _num) { assert( _array[i]->is_of_type(EdgeStroke::static_name())); ((EdgeStroke*)_array[i++])->clear_simplex_data(); } }
/***************************************************************** * InflateCreaseFilter: *****************************************************************/ bool InflateCreaseFilter::accept(CBsimplex* s) const { // Reject non-edges: if (!is_edge(s)) return false; Bedge* e = (Bedge*)s; if (e->nfaces() < 2) return false; // Accept it if it's labelled a crease, is owned by a // Bcurve, or the adjacent faces make a sharp angle: return ( e->is_crease() || Bcurve::find_controller(e) || rad2deg(norm_angle(e)) > 50 ); }
void EdgeStrip::build_ccw_boundaries( CBedge_list& edges, CSimplexFilter& face_filter ) { // Similar to previous... // // XXX - needs comments // Clear edge flags to screen for unreached edges: // set edge flags to 1 in 1-ring of verts, // then clear edge flags of internal edges set_adjacent_edges(edges.get_verts(), 1); edges.clear_flags(); // get an edge filter that accepts "boundary" edges WRT the // given face filter BoundaryEdgeFilter boundary(face_filter); // Pull out the edge tips: Bedge_list tips = edges.filter(ChainTipEdgeFilter(boundary)); // Construct the filter that screens out previously reached // edges: UnreachedSimplexFilter unreached; AndFilter wanted = unreached + boundary; int k; // Start from all the tips first: for (k=0; k<tips.num(); k++) { Bedge* e = tips[k]; Bvert* v = (e->v2()->degree(boundary) != 2) ? e->v2() : e->v1(); Bface* f = e->screen_face(face_filter); assert(f); // e must have 1 face satisfying the filter // If this will start out running ccw, take it. // otherwise skip: if (f->next_vert_ccw(v) == e->other_vertex(v)) build(v, e, wanted); } // Now check the rest: for (k=0; k<edges.num(); k++) { Bedge* e = edges[k]; Bface* f = e->screen_face(face_filter); assert(f); // e must have 1 face satisfying the filter // Go CCW around faces build(f->leading_vert_ccw(e), e, wanted); } }
Bedge_list Bface_list::get_edges() const { // Extract a list of the edges found in the given faces. // Get clean slate clear_edge_flags(); // Put edges into output array uniquely: Bedge_list ret(size()*2); // pre-allocate plenty for (Bface_list::size_type i=0; i<size(); i++) { for (int j=1; j<4; j++) { Bedge* e = at(i)->e(j); if (e->flag() == 0) { e->set_flag(1); ret.push_back(e); } } } return ret; }
bool SELECT_WIDGET::select_edges(CPIXEL_list& pts) { err_adv(debug, "SELECT_WIDGET::select_edges:"); if (pts.num() < 2) { err_adv(debug, " bad gesture: %d points", pts.num()); return false; } // Find edit-level vert near start of pixel trail: Bvert* v = find_vert(pts[0]); if (!v) { err_adv(debug, " can't get starter vertex"); return false; } // 2. Extract edge sequence within tolerance of gest Bedge_list chain; int k = 0; // index of cur position in gesture Bvert* cur = v; // current vertex Bedge* e = 0; while ((e = match_span(cur, pts, k))) { if(!e->is_selected()) chain += e; cur = e->other_vertex(cur); } err_adv(debug, " got %d edges", chain.num()); // Confirm gest is sufficiently close to edge chain // 3. Select the edges WORLD::add_command(new MESH_SELECT_CMD(chain)); return true; }
bool Skin::correct_face(Bface* f, bool& changed) { // // BBBBBBBBBBBBBBB // B /| // B / | // B f / | Change this, where quad face f // B / | is adjacent to 2 boundary edgees... // B / | // B / | // B/- - - - - - o // // BBBBBBBBBBBBBBB // B\ | // B \ | // B \ | ... to this, where neither face of // B \ | the quad is adjacent to more than 1 // B \ | boundary edge. // B \ | // B - - - - - - o // assert(f); // boundary edges have flag == 1, others have flag == 0 uint n = num_edge_flags_set(f); if (n < 2) return true; // not a problem if (n > 2) { // unfixable problem err_adv(debug, " can't fix face with %d boundary edges", n); return false; } // 2 boundary edges; get the non-boundary one: Bedge* e = boundary_connector(f); assert(e); // we want to swap it; only possible if it has 2 faces: if (e->nfaces() != 2) { err_adv(debug, " can't fix edge with %d faces", e->nfaces()); return false; } // swapping won't do any good if its other face has boundary edges too: if (!(num_edge_flags_set(e->f1()) == 0 || num_edge_flags_set(e->f2()) == 0)) { err_adv(debug, " unfixable edge found, giving up"); return false; } // try to swap it: if (e->do_swap()) { err_adv(debug, " swapped edge"); return changed = true; } err_adv(debug, " edge swap failed"); return false; }
inline Bedge_list quad_cell_end_edges(PCell* cell) { // if the cell is a quad (4 sides) and has one neigbhor, // return the side opposite from the neighbor. assert(cell && cell->num_corners() == 4); PCell_list nbrs = cell->nbrs(); if (nbrs.size() != 1) { err_adv(debug, "quad_cell_end_edges: neighbors: %d != 1", nbrs.size()); return Bedge_list(); } // find an edge of the shared boundary. // do it now before messing with flags... assert(!cell->shared_boundary(nbrs[0]).empty()); Bedge* e = cell->shared_boundary(nbrs[0]).front(); assert(e); EdgeStrip boundary = cell->get_boundary(); assert(boundary.num_line_strips() == 1); // iterate around the boundary, setting edge flags to value // k that is incremented whenever we pass a cell corner. int k = 0; PCellCornerVertFilter filter; for (int i=0; i<boundary.num(); i++) { if (filter.accept(boundary.vert(i))) k = (k + 1)%4; boundary.edge(i)->set_flag(k); } // we want the edges with flag == k + 2 mod 4 return boundary.edges().filter( SimplexFlagFilter((e->flag() + 2)%4) ); }
UVpt LoopUV::centroid(CLvert* v) const { assert(v); switch (UVdata::discontinuity_degree(v)) { case 0: { // No discontinuity: UVpt ret; for (int i=0; i<v->degree(); i++) ret += UVdata::get_uv(v->nbr(i), v->e(i)->get_face()); return ret / v->degree(); } case 2: { // Find the 2 discontinuity edges and get the uv values of // their opposite vertices that agree with the current vertex. CUVpt& uv = UVdata::get_uv(v,_face); UVpt ret; for (int i=0; i<v->degree(); i++) { Bedge* e = v->e(i); if (!UVdata::is_continuous(e)) { if (UVdata::lookup(e->f1()) && UVdata::get_uv(v,e->f1()) == uv) ret += UVdata::get_uv(v->nbr(i), e->f1()); else if (UVdata::lookup(e->f2()) && UVdata::get_uv(v,e->f2()) == uv) ret += UVdata::get_uv(v->nbr(i), e->f2()); else assert(0); } } return ret/2; } default: // Treat as a corner vertex return UVdata::get_uv(v, _face); } }
void Lface::allocate_subdiv_elements() { // Generate 4 faces and 3 internal edges // in the subdivision mesh next level down. // NOTE: The specific order that sub-faces are created, // and the order of the vertices used in creating them, // should not be changed. The barycentric coordinate // conversion routines (below) depend on these orderings. // Make this lightweight, so you can call // it when you're not sure if you need to: if (is_set(SUBDIV_ALLOCATED_BIT)) return; set_bit(SUBDIV_ALLOCATED_BIT); assert(lmesh() != nullptr); lmesh()->allocate_subdiv_mesh(); LMESHptr submesh = lmesh()->subdiv_mesh(); assert(submesh != nullptr); // lv3 # // /\ # // /3 \ # // / \ # // / \ # // / child3 \ # // / \ # // / 1 2 \ # // le3 /______________\ le2 # // /\ 2 1 /\ # // /3 \ /3 \ # // / \ center / \ # // / \ child / \ # // / \ / \ # // / child1 \ / child2 \ # // / \3 / \ # // / 1 2 \/ 1 2 \ # // lv1 -------------------------------- lv2 # // le1 # // Make sure subdiv elements have // been allocated around face boundary: lv(1)->allocate_subdiv_vert(); lv(2)->allocate_subdiv_vert(); lv(3)->allocate_subdiv_vert(); le(1)->allocate_subdiv_elements(); le(2)->allocate_subdiv_elements(); le(3)->allocate_subdiv_elements(); Patch* child_patch = _patch ? _patch->get_child() : nullptr; // hook up 4 faces (verifying they're not already there): if (!subdiv_face1()) gen_child_face( lv(1)->subdiv_vertex(), le(1)->subdiv_vertex(), le(3)->subdiv_vertex(), child_patch, submesh); if (!subdiv_face2()) gen_child_face( le(1)->subdiv_vertex(), lv(2)->subdiv_vertex(), le(2)->subdiv_vertex(), child_patch, submesh); if (!subdiv_face3()) gen_child_face( le(3)->subdiv_vertex(), le(2)->subdiv_vertex(), lv(3)->subdiv_vertex(), child_patch, submesh); if (!subdiv_face_center()) gen_child_face( le(2)->subdiv_vertex(), le(3)->subdiv_vertex(), le(1)->subdiv_vertex(), child_patch, submesh, true); // true: face is at center if (is_quad()) { // // o // | . // | . // | . w // | . // sub1 o .----- o. // | . | . // | . | . // | .| . // o ------ o ----- o // v sub2 // // A quad face is one that has a "weak" edge // (shown as the dotted edge labelled 'w' above). // A weak edge is considered to be the internal // diagonal edge of a quad, with this face making // up one half of the quad and the face on the // other side (not shown) making up the other // half. In subdivision we label the subdivision // edges accordingly. I.e. the edge connecting // subdivision vertices sub1 and sub2 should be // labelled weak. Bedge* w = weak_edge(); Bvert* v = other_vertex(w); Bvert* sub1 = ((Ledge*)v->lookup_edge(w->v1()))->subdiv_vertex(); Bvert* sub2 = ((Ledge*)v->lookup_edge(w->v2()))->subdiv_vertex(); sub1->lookup_edge(sub2)->set_bit(Bedge::WEAK_BIT); } // Now that child faces are generated, propagate multi // status (if any) to children le(1)->push_multi(this); le(2)->push_multi(this); le(3)->push_multi(this); // Notify observers: if (_data_list) _data_list->notify_subdiv_gen(); }
bool Bface::local_search( Bsimplex *&end, Wvec &final_bc, CWpt &target, Wpt &reached, Bsimplex *repeater, int iters) { // this is a hack to prevent recursion that goes too deep. // however if that is a problem the real cause should be // tracked down and fixed. if (iters <= 0) return 0; Wvec bc; bool is_on_tri = 0; Wpt nearpt = nearest_pt(target, bc, is_on_tri); Bsimplex* sim = bc2sim(bc); if (!is_on_tri) { if (sim == repeater) // We hit a loop in the recursion, so stop return 0; if (sim != this) { // We're on the boundary of the face if (is_edge(sim)) { Bedge* e = (Bedge*)sim; // Can't cross a border if (!e->is_border()) { // recurse starting from the other face. int good_path = e->other_face(this)->local_search( end, final_bc, target, reached, sim, iters-1); if (good_path == 1) return 1; else if (good_path == -1) return repeater ? true : false; // XXX - changed from -1 : 0 -- should check } else { return repeater ? true : false; // XXX - changed from -1 : 0 -- should check } } else { // Try to follow across a vertex Bface_list near_faces(16); assert(is_vert(sim)); ((Bvert*)sim)->get_faces(near_faces); for (int k = near_faces.size()-1; k>=0; k--) { if (near_faces[k] != this) { int good_path = near_faces[k]->local_search( end, final_bc, target, reached, sim, iters-1); if (good_path == 1) return 1; else if (good_path==-1) return repeater ? true : false; // XXX - changed from -1 : 0 -- should check } } } } } reached = nearpt; end = this; final_bc = bc; return 1; }
int SELECT_WIDGET:: slash_cb(CGESTUREptr& gest, DrawState*& s) { if (_mode==SEL_FACE) //widget is in face selection mode { select_list.clear(); Bface* f = find_face(gest->start(),0.25,MIN_PIX_AREA); // f should be the currently selected face if (f && f->is_selected() && f->is_quad()) { f=f->quad_rep(); //line in screen space coresponding to the slash PIXELline slash(gest->start(),gest->end()); Bedge *e1,*e2,*e3,*e4; Bedge* edge = 0; //get and test the quad edges against the stroke line f->get_quad_edges(e1,e2,e3,e4); if( e1->pix_line().intersect_segs(slash) ) { edge=e1; } else if( e2->pix_line().intersect_segs(slash) ) { edge=e2; } else if( e3->pix_line().intersect_segs(slash) ) { edge=e3; } else if( e4->pix_line().intersect_segs(slash) ) { edge=e4; } else { //error cerr << "ERROR no intersection" << endl; return 1; } //walk the geometry and select faces Bface* fn = f; do { if (!fn->is_selected()) select_list +=fn; assert(edge); //I'm paranoid too assert(edge->f1()!=edge->f2()); //grabs the face on the other side of the edge //even if we are not directly adjacent to this edge fn=fn->other_quad_face(edge); if (fn) //if a valid face than advance the edge pointer { assert(edge!=fn->opposite_quad_edge(edge)); edge = fn->opposite_quad_edge(edge); fn = fn->quad_rep(); //all faces on the selection list are rep faces } else cerr << "No face on the other side of the edge" << endl; } //quit if not a valid face or not a quad while(fn&&(fn->is_quad())&&edge&&(fn!=f)); _mode=SLASH_SEL; //go into pattern editing mode end_face=0; //prepare the 2nd step data pattern=0; for (int i=0; i<MAX_PATTERN_SIZE; i++) pattern_array[i]=1; //fill the default pattern with ones } else cerr << "This is not a quad" << endl; } else if( _mode==SLASH_SEL)//pattern editing mode { //activates upon second slash motion //adds the entire list to the selected group //undo deselects the entire group Bface_list final_list; //copy the face pointers to the final list //using the pattern as a repeating template //and stop at the end face for (int i = 0; i<(end_face ? (end_face) : select_list.num()) ; i++) { if (pattern ? pattern_array[(i%pattern)+1] : 1) final_list+=select_list[i]; } WORLD::add_command(new MESH_SELECT_CMD(final_list)); return cancel_cb(gest,s); } else cerr << "wrong mode " << endl; return 1; }
bool UVdata::get_quad_uvs( CBvert* a, CBvert* b, CBvert* c, CBvert* d, UVpt& uva, UVpt& uvb, UVpt& uvc, UVpt& uvd) { // Pull out the uv-coordinates from the 4 given vertices // that supposedly form a quad. // d ---------- c // | | // | | // | | // | | // | | // | | // a ---------- b // if (!(a && b && c && d)) return false; // Try the diagonal running NE: Bedge* e = a->lookup_edge(c); if (e) { if (!quad_has_uv(e->f1())) return 0; // Get the two faces, trying the diagonal running NE Bface* lower = lookup_face(a,b,c); Bface* upper = lookup_face(a,c,d); // Should never fail, but check anyway: if (!(upper && lower)) return 0; // Get the data and return happy uva = get_uv(a, lower); uvb = get_uv(b, lower); uvc = get_uv(c, lower); uvd = get_uv(d, upper); return 1; } // Try the diagonal the other way: e = b->lookup_edge(d); if (!(e && quad_has_uv(e->f1()))) return 0; // Get the two faces, trying the diagonal running NE Bface* lower = lookup_face(a,b,d); Bface* upper = lookup_face(b,c,d); // Should never fail, but check anyway: if (!(upper && lower)) return 0; // Get the data and return happy uva = get_uv(a, lower); uvb = get_uv(b, lower); uvc = get_uv(c, upper); uvd = get_uv(d, upper); return 1; }
// Like above, but returns the next border vertex: Bvert* next_border_vert_cw() { Bedge* border = next_border_edge_cw(); return border ? border->other_vertex(this) : nullptr; }
Bsimplex* Bface::ndc_walk( CNDCpt& target, CWvec &passed_bc, CNDCpt &nearest, int is_on_tri, bool use_passed_in_params) const { // just like local_search, but in NDC space // // start from this face, move in NDC space // across the mesh to reach the target // // if reached, return the simplex that contains // the target point. // we only move if it will get us closer to the goal. Hence, we // can never wander off forever. // if can't reach it, return 0 NDCpt y (nearest); Wvec bc(passed_bc); if (!use_passed_in_params) { y = nearest_pt_ndc(target, bc, is_on_tri); } Bsimplex* sim = bc2sim(bc); if (is_on_tri) { // target is on this triangle // return the lowest-dimensional // simplex on which it lies return sim; } if (is_edge(sim)) { Bedge* e = (Bedge*)sim; Bface* f = e->is_sil() ? nullptr : e->other_face(this); if (f) { Wvec new_bc; int new_on_tri; NDCpt new_best = f->nearest_pt_ndc(target, new_bc, new_on_tri); if (new_best.dist_sqrd(target) < y.dist_sqrd(target)) return f->ndc_walk(target, new_bc, new_best, new_on_tri, true); else return nullptr; } else { return nullptr; } } // better be a vertex assert(is_vert(sim)); Bvert* v = (Bvert*)sim; if (v->degree(SilEdgeFilter()) > 0) return nullptr; Bface_list nbrs(16); ((Bvert*)sim)->get_faces(nbrs); double dist_sqrd = 1e50; Bface* best = nullptr; Wvec best_bc; NDCpt best_nearest; int best_on_tri = 0; Wvec curr_bc; NDCpt curr_nearest; int curr_on_tri=0; for (Bface_list::size_type k = 0; k < nbrs.size(); k++) { if (nbrs[k] != this) { curr_nearest = nbrs[k]->nearest_pt_ndc(target, curr_bc, curr_on_tri); if (curr_nearest.dist_sqrd(target) < dist_sqrd ) { dist_sqrd = curr_nearest.dist_sqrd(target); best_bc = curr_bc; best_on_tri = curr_on_tri; best_nearest = curr_nearest; best = nbrs[k]; } } } if (dist_sqrd < y.dist_sqrd(target)) { return best->ndc_walk(target, best_bc, best_nearest, best_on_tri, true); } return nullptr; }
void ProxySurface::grow_quad_from_edge(BMESH* m, EdgeStrip* boundary, int i) { // i is the position of the edge in the boundary Bedge* e = boundary->edge(i); assert(e); //make sure is still a boundary edge if not, return... if(e->nfaces() > 1){ return; } Bvert* v2 = boundary->vert(i); Bvert* v1 = boundary->next_vert(i); assert(v1); assert(v2); if(!(UVdata::is_continuous(e))) { cerr << "ProxySurface::grow_quad_from_edge: e is discontinous!!!" << endl; return; } UVpt uv_1, uv_2, uv_3, uv_4; if(!(UVdata::get_uv(v2, uv_2))) { cerr << "ProxySurface::grow_quad_from_edge: v2 vertex does not have UVdata!!!" << endl; return; } if(!(UVdata::get_uv(v1, uv_1))) { cerr << "ProxySurface::grow_quad_from_edge: v1 vertex does not have UVdata!!!" << endl; return; } // constant in u dir -> v line if(uv_1[0] == uv_2[0]){ if(uv_1[1] > uv_2[1]) { uv_3 = UVpt(uv_2[0]+1,uv_2[1]); uv_4 = UVpt(uv_1[0]+1,uv_1[1]); } else { uv_3 = UVpt(uv_2[0]-1,uv_2[1]); uv_4 = UVpt(uv_1[0]-1,uv_1[1]); } } else { assert(uv_1[1] == uv_2[1]); //constant in v dir if(uv_1[0] > uv_2[0]) { uv_3 = UVpt(uv_2[0],uv_2[1]-1); uv_4 = UVpt(uv_1[0],uv_1[1]-1); } else { uv_3 = UVpt(uv_2[0],uv_2[1]+1); uv_4 = UVpt(uv_1[0],uv_1[1]+1); } } // double dist = e->length(); //cerr << "grow quad: " << i << " " << uv_1 << " " << uv_2 << " " << uv_3 << " " << uv_4 << endl; Bvert* v_1 = vertFromUV(uv_1); Bvert* v_2 = vertFromUV(uv_2); Bvert* v_3 = vertFromUV(uv_3); Bvert* v_4 = vertFromUV(uv_4); assert(v_1 && v_2 && v_3 && v_4); //cerr << "grow quad: " << i << " " << v_1->wloc() << " " << v_2->wloc() << " " << v_3->wloc() << " " << v_4->wloc() << endl; m->add_quad(v_1, v_2, v_3, v_4, uv_1, uv_2, uv_3, uv_4, m->patch(0)); UVdata::set(v_1, uv_1); UVdata::set(v_2, uv_2); UVdata::set(v_3, uv_3); UVdata::set(v_4, uv_4); //PixelsData::get_pix(v_1, this); //PixelsData::get_pix(v_2, this); //PixelsData::get_pix(v_3, this); //PixelsData::get_pix(v_4, this); PixelsData::set_pix(v_1, this,v_1->pix()); PixelsData::set_pix(v_2, this,v_2->pix()); PixelsData::set_pix(v_3, this,v_3->pix()); PixelsData::set_pix(v_4, this,v_4->pix()); }