/********************************************************************** * 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; }
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; }
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; }
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; }