Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

bface.C

Go to the documentation of this file.
00001 /**********************************************************************
00002  * bface.C
00003  **********************************************************************/
00004 #include "mesh/patch.H"
00005 #include "mesh/mi.H"
00006 #include "mesh/uv_data.H"
00007 #include "std/config.H"
00008 
00009 using namespace mlib;
00010 
00011 Bface::Bface(Bvert* u, Bvert* v, Bvert* w,
00012              Bedge* e, Bedge* f, Bedge* g) :
00013    _v1(u), _v2(v), _v3(w),
00014    _e1(e), _e2(f), _e3(g),
00015    _area(0),
00016    _patch(0),
00017    _patch_index(-1),
00018    _orient(0),
00019    _ff_stamp(0),
00020    _zx_stamp(0),
00021    _tc(0),
00022    _layer(0)
00023 {
00024    *_e1 += this;
00025    *_e2 += this;
00026    *_e3 += this;
00027 
00028    geometry_changed();
00029 }
00030 
00031 Bface::~Bface()
00032 {
00033    // remove self from global selection list, if needed
00034    if (is_selected()) {
00035       MeshGlobal::deselect(this);
00036    }
00037 
00038    // tell edges to forget:
00039    detach();
00040 
00041    // the patch too
00042    if (_patch && _patch_index >= 0)
00043       _patch->remove(this);
00044 }
00045 
00046 int
00047 Bface::index() const
00048 {
00049    // index in BMESH Bface array:
00050 
00051    if (!_mesh) return -1;
00052    return _mesh->faces().get_index((Bface*)this);
00053 }
00054 
00055 void
00056 Bface::normal_changed()
00057 {
00058    // Shouldn't be called on a Bface.
00059    // Use Bface::geometry_changed() instead.
00060 
00061    assert(0);
00062 }
00063 
00064 void
00065 Bface::geometry_changed()
00066 {
00067    // One of the 3 vertices changed position, which means the
00068    // face normal has been redefined
00069 
00070    _ff_stamp = 0;
00071    clear_bit(VALID_NORMAL_BIT);
00072 
00073    _v1->normal_changed();
00074    _v2->normal_changed();
00075    _v3->normal_changed();
00076 
00077    _e1->normal_changed();
00078    _e2->normal_changed();
00079    _e3->normal_changed();
00080 
00081    Bsimplex::geometry_changed();
00082 }
00083 
00084 bool
00085 Bface::zx_mark() const
00086 { 
00087   bool ret = ( _zx_stamp == VIEW::stamp() );
00088   ((Bface*)this)->_zx_stamp = VIEW::stamp();
00089   return ret;
00090 }
00091 
00092 bool
00093 Bface::zx_query() const
00094 { 
00095    if ( _zx_stamp == VIEW::stamp() ) return true ;
00096    return false;
00097 }
00098 
00099 int 
00100 Bface::front_facing() const
00101 {
00102    // this is just for purposes of visualizing the silhouttes from
00103    // another viewpoint:
00104    static bool ignore_xf = Config::get_var_bool("SILS_IGNORE_MESH_XFORM",false);
00105 
00106    if (_ff_stamp != VIEW::stamp()) {
00107       ((Bface*)this)->_ff_stamp = VIEW::stamp();
00108       int b = ((
00109          (ignore_xf ?
00110           VIEW::peek_cam()->data()->from() :
00111           _mesh->eye_local()
00112             ) - _v1->loc()) * norm()) > 0;
00113       ((Bface*)this)->set_bit(FRONT_FACING_BIT,b);
00114    }
00115    return is_set(FRONT_FACING_BIT);
00116 }
00117 
00118 Bsimplex*
00119 Bface::find_intersect_sim(
00120    CNDCpt& target_pt,
00121    Wpt&    hit_pt) const
00122 {
00123    Bsimplex* ret = ndc_walk(target_pt);
00124    if (is_face(ret)) 
00125       hit_pt =
00126          ((Bface*)ret)->plane_intersect(_mesh->inv_xform()*Wline(target_pt));
00127    else if(is_edge(ret))
00128       hit_pt =
00129          ((Bedge*)ret)->line().intersect(_mesh->inv_xform()*Wline(target_pt));
00130    else if (is_vert(ret))
00131       hit_pt = ((Bvert*)ret)->loc();
00132 
00133    return ret;
00134 }  
00135 
00136 // Return true if pt lie within boundary + epsilon neighborhood of the face.
00137 bool
00138 Bface::contains(CWpt& pt,double threshold) const 
00139 {
00140    // NOTE: Normalize behave in the way that if v is zero, it
00141    // normalize to zero vector
00142    const double dist_threshold=0.00001;
00143    if (plane().dist(pt) > dist_threshold)
00144       return false;
00145 
00146    Wvec vec1 = (pt-v1()->loc()).normalized();
00147    Wvec vec2 = (pt-v2()->loc()).normalized();
00148    Wvec vec3 = (pt-v3()->loc()).normalized();
00149    Wvec ab = (v2()->loc()-v1()->loc()).normalized();
00150    Wvec bc = (v3()->loc()-v2()->loc()).normalized();
00151    Wvec ca = (v1()->loc()-v3()->loc()).normalized();
00152 
00153    Wvec c1 = cross(ab,vec1).normalized();
00154    Wvec c2 = cross(bc,vec2).normalized();
00155    Wvec c3 = cross(ca,vec3).normalized();
00156 
00157    Wvec n = cross(ab,bc).normalized();
00158 
00159    if(c1*n<-threshold) return false;
00160    if(c2*n<-threshold) return false;
00161    if(c3*n<-threshold) return false;
00162 
00163    return true;
00164 }
00165 
00166 
00167 
00168 
00169 Bsimplex*
00170 Bface::ndc_walk(
00171    CNDCpt& target, 
00172    CWvec &passed_bc, 
00173    CNDCpt &nearest,
00174    int is_on_tri, 
00175    bool use_passed_in_params) const
00176 {
00177   // just like local_search, but in NDC space
00178    //
00179    // start from this face, move in NDC space
00180    // across the mesh to reach the target
00181    //
00182    // if reached, return the simplex that contains
00183    // the target point.
00184    // we only move if it will get us closer to the goal.  Hence, we
00185    // can never wander off forever.
00186 
00187    // if can't reach it, return 0
00188 
00189    NDCpt y (nearest);
00190    Wvec  bc(passed_bc);
00191 
00192    if (!use_passed_in_params) {
00193       y = nearest_pt_ndc(target, bc, is_on_tri);
00194    }
00195    Bsimplex* sim   = bc2sim(bc);
00196 
00197    if (is_on_tri) {
00198       // target is on this triangle
00199       // return the lowest-dimensional
00200       // simplex on which it lies
00201       return sim;
00202    }
00203 
00204    if (is_edge(sim)) {
00205       Bedge* e = (Bedge*)sim;
00206       Bface* f = e->is_sil() ? (Bface*)0 : e->other_face(this);
00207       if (f) {
00208          Wvec new_bc;
00209          int  new_on_tri;
00210          NDCpt new_best = f->nearest_pt_ndc(target, new_bc, new_on_tri);
00211          if (new_best.dist_sqrd(target) < y.dist_sqrd(target))
00212             return f->ndc_walk(target, new_bc, new_best, new_on_tri, true); 
00213          else 
00214             return 0;
00215       } else {
00216          return 0;
00217       }
00218    }
00219 
00220    // better be a vertex
00221    assert(is_vert(sim));
00222    Bvert* v = (Bvert*)sim;
00223    if (v->degree(SilEdgeFilter()) > 0)
00224       return 0;
00225 
00226    Bface_list nbrs(16);
00227    ((Bvert*)sim)->get_faces(nbrs);
00228    double dist_sqrd = 1e50;
00229    Bface* best = 0;
00230    Wvec   best_bc;
00231    NDCpt  best_nearest;
00232    int    best_on_tri = 0;
00233    Wvec   curr_bc;
00234    NDCpt  curr_nearest;
00235    int    curr_on_tri=0;
00236 
00237    for (int k = 0; k < nbrs.num(); k++) {
00238       if (nbrs[k] != this) {
00239          curr_nearest = nbrs[k]->nearest_pt_ndc(target, curr_bc, curr_on_tri);
00240          if (curr_nearest.dist_sqrd(target) < dist_sqrd ) {
00241             dist_sqrd = curr_nearest.dist_sqrd(target);
00242             best_bc = curr_bc;
00243             best_on_tri = curr_on_tri;
00244             best_nearest = curr_nearest;
00245             best = nbrs[k];
00246          }
00247       }
00248    }
00249 
00250    if (dist_sqrd < y.dist_sqrd(target)) {
00251       return best->ndc_walk(target, best_bc, best_nearest, best_on_tri, true); 
00252    }
00253 
00254    return 0;
00255 }
00256 
00257 Bface*
00258 Bface::plane_walk(Bedge* cur_edge, CWplane& plane, Bedge*& next_edge) const
00259 {
00260    int i;
00261    assert(cur_edge == 0 || cur_edge->which_side(plane) == 0);
00262 
00263    for (i=1; i<4; i++)
00264       if (e(i) != cur_edge && e(i)->which_side(plane)==0)
00265          break;
00266    
00267    if (i==4)
00268       return 0;
00269 
00270    assert(e(i)->which_side(plane)==0);
00271    
00272    next_edge = e(i);
00273    return e(i)->other_face(this);
00274 }
00275 
00276 bool
00277 Bface::ray_intersect(
00278    CWpt& p,                   // point on ray
00279    CWvec& r,                  // direction of ray
00280    Wpt& hit,                  // returned intersect point
00281    double& depth) const       // distance from hit to p
00282 {
00283    // get points of triangle
00284    CWpt &a=_v1->loc();
00285    CWpt &b=_v2->loc();
00286    CWpt &c=_v3->loc();
00287 
00288    // now find scalar t such that  d = p + rt  is in plane of face...
00289    // can't proceed if dot product is zero
00290    double dot = r * norm();
00291    if(fabs(dot) < 1e-16)
00292       return 0;
00293 
00294    // compute t:
00295    double t = ((a - p) * norm()) / dot;
00296 
00297    // compute point d on ray and in plane of face:
00298    Wpt d = p + (r * t);
00299 
00300    // test if d is inside triangle
00301    Wvec da = d-a;
00302    Wvec ba = b-a;
00303    Wvec db = d-b;
00304    if ((cross(da,ba) * cross(da,c-a) <= 0) &&
00305        (cross(db,ba) * cross(db,c-b) > 0)) {
00306       hit = d;
00307       depth = (hit - p).length();
00308       return 1;
00309    }
00310    return 0;
00311 }
00312 
00313 bool
00314 Bface::view_intersect(
00315    CNDCpt& p,           // Screen point at which to do intersect
00316    Wpt&    nearpt,      // Point on face visually nearest to p
00317    double& dist,        // Distance from nearpt to ray from camera
00318    double& d2d,         // Distance in pixels nearpt to p
00319    Wvec& n              // "normal" at nearpt in world coordinates
00320    ) const
00321 {
00322    // (Bsimplex virtual method):
00323    // Intersection w/ ray from given screen point -- returns the point
00324    // on the Bface that is nearest to the given screen space point.
00325    // Note: the returned "near point" and "normal" are both
00326    //       transformed to world space.
00327 
00328    // Get "eye point" for computing distance.
00329    // Not sure if this is the same as cam->from(),
00330    // but it seems to be the way it's done in other
00331    // intersection code.
00332    Wpt eye = XYpt(p);
00333 
00334    // Make object-space ray:
00335    Wline ray = _mesh->inv_xform()*Wline(p); // ray in object space
00336    Wpt hit;
00337 
00338    // Try for exact intersection:
00339    double d;
00340    if (ray_intersect(ray, hit, d)) {
00341       // Direct hit
00342       nearpt = _mesh->xform()*hit;
00343       dist   = nearpt.dist(eye);
00344       d2d    = PIXEL(nearpt).dist(PIXEL(p));
00345       n      = (_mesh->inv_xform().transpose()*norm()).normalized();
00346       return true;
00347    }
00348 
00349    Wpt    hit1, hit2, hit3;
00350    double d1 = DBL_MAX, d2 = DBL_MAX, d3 = DBL_MAX;
00351    Wvec   n1, n2, n3;
00352    _e1->view_intersect(p, hit1, d, d1, n1);
00353    _e2->view_intersect(p, hit2, d, d2, n2);
00354    _e3->view_intersect(p, hit3, d, d3, n3);
00355 
00356    // Rename so d1 represents closest hit
00357    if (d1 > d2) {
00358       swap(d1, d2);
00359       swap(hit1, hit2);
00360       swap(n1, n2);
00361    }
00362    if (d1 > d3) {
00363       swap(d1, d3);
00364       swap(hit1, hit3);
00365       swap(n1, n3);
00366    }
00367    nearpt = _mesh->xform()*hit1;
00368    dist   = nearpt.dist(eye);
00369    d2d    = PIXEL(nearpt).dist(PIXEL(p));
00370    n      = n1;
00371    return true;
00372 }
00373 
00374 inline Wpt
00375 pt_near_seg(CWpt& a, CWpt& b, CWpt& p, double& t)
00376 {
00377    // mlib version of this is not as good
00378    Wvec v = (b - a);
00379    double vv = v*v;
00380    t = (vv < gEpsZeroMath) ? 0 : clamp(((p - a)*v)/vv,0.0,1.0);
00381    return (a + v*t);
00382 }
00383 
00384 inline NDCpt
00385 pt_near_seg_ndc(CNDCpt& a, CNDCpt& b, CNDCpt& p, double& t)
00386 {
00387    // mlib version of this is not as good
00388    NDCvec v = (b - a);
00389    double vv = v*v;
00390    t = (vv < gEpsZeroMath) ? 0 : clamp(((p - a)*v)/vv,0.0,1.0);
00391    return (a + v*t);
00392 }
00393 
00394 inline void
00395 get_other_face(CBedge* e, CBface* f, Bsimplex_list& ret)
00396 {
00397    assert(e && f && f->contains(e));
00398    if (e->is_weak())
00399       return;
00400    Bface* g = e->other_face(f);
00401    if (!g)
00402       return;
00403    ret += g;
00404    g = g->quad_partner();
00405    if (g)
00406       ret += g;
00407 }
00408 
00409 inline Bsimplex_list
00410 bfa_to_bsa(CBface_list& faces)
00411 {
00412    Bsimplex_list ret(faces.num());
00413    for (int i=0; i<faces.num(); i++)
00414       ret += faces[i];
00415    return ret;
00416 }
00417 
00418 Bsimplex_list
00419 Bface::neighbors() const
00420 {
00421    // XXX - still in progress of figuring out what this should mean
00422 
00423    // try the one-ring faces:
00424 
00425    // XXX - need Bsimplex_list constructor from Bface_list etc.
00426 
00427    return bfa_to_bsa(Bface_list((Bface*)this).one_ring_faces());
00428 
00429    Bsimplex_list ret(9);
00430    ret += _v1;
00431    ret += _v2;
00432    ret += _v3;
00433    ret += _e1;
00434    ret += _e2;
00435    ret += _e3;
00436    get_other_face(_e1, this, ret);
00437    get_other_face(_e2, this, ret);
00438    get_other_face(_e3, this, ret);
00439    return ret;
00440 }
00441 
00442 Bsimplex* 
00443 Bface::bc2sim(CWvec& bc) const 
00444 {
00445    return (
00446       (bc[0]==1) ? (Bsimplex*)_v1 :
00447       (bc[1]==1) ? (Bsimplex*)_v2 :
00448       (bc[2]==1) ? (Bsimplex*)_v3 :
00449       (bc[0]==0) ? (Bsimplex*)_e2 :
00450       (bc[1]==0) ? (Bsimplex*)_e3 :
00451       (bc[2]==0) ? (Bsimplex*)_e1 :
00452       (Bsimplex*)this
00453       );
00454 }
00455 
00456 bool 
00457 Bface::local_search(
00458    Bsimplex            *&end, 
00459    Wvec             &final_bc,
00460    CWpt             &target, 
00461    Wpt              &reached,
00462    Bsimplex         *repeater,
00463    int               iters) 
00464 {
00465    // this is a hack to prevent recursion that goes too deep.
00466    // however if that is a problem the real cause should be
00467    // tracked down and fixed.
00468 
00469    if (iters <= 0)
00470       return 0;
00471 
00472    Wvec      bc;
00473    bool      is_on_tri = 0;
00474    Wpt       nearpt    = nearest_pt(target, bc, is_on_tri);
00475    Bsimplex* sim       = bc2sim(bc);
00476 
00477    if (!is_on_tri) {
00478       
00479       if (sim == repeater) // We hit a loop in the recursion, so stop
00480          return 0;
00481 
00482       if (sim != this) { // We're on the boundary of the face
00483          if (is_edge(sim)) {
00484             Bedge* e = (Bedge*)sim;
00485 
00486             // Can't cross a border
00487             if (!e->is_border()) {
00488 
00489                // recurse starting from the other face.
00490                int good_path = e->other_face(this)->local_search(
00491                   end, final_bc, target, reached, sim, iters-1);
00492                if (good_path == 1)
00493                   return 1;
00494                else if (good_path == -1)
00495                   return repeater ? true : false; // XXX - changed from -1 : 0 -- should check
00496             }
00497 
00498             else {
00499                return repeater ? true : false; // XXX - changed from -1 : 0 -- should check
00500             }
00501          } else {
00502             // Try to follow across a vertex
00503             Bface_list near_faces(16);
00504             assert(is_vert(sim));
00505             ((Bvert*)sim)->get_faces(near_faces);
00506             for (int k = near_faces.num()-1; k>=0; k--) {
00507                if (near_faces[k] != this) {
00508                   int good_path = near_faces[k]->local_search(
00509                            end, final_bc, target, reached, sim, iters-1);
00510                   if (good_path == 1)
00511                      return 1;
00512                   else if (good_path==-1)
00513                      return repeater ? true : false; // XXX - changed from -1 : 0 -- should check
00514                }
00515             }
00516          }
00517       }
00518    }
00519 
00520    reached = nearpt;
00521    end = this;
00522    final_bc = bc;
00523 
00524    return 1;
00525 }
00526 
00527 inline void
00528 snap(Wvec& bc)
00529 {
00530    // bc is a barycentric coord vector
00531    // set near-zero values to 0,
00532    // renormalize
00533    //
00534    // should be a class for barycentric coords
00535    // and this should be a method of the class
00536 
00537    if (fabs(bc[0]) < gEpsZeroMath) bc[0] = 0;
00538    if (fabs(bc[1]) < gEpsZeroMath) bc[1] = 0;
00539    if (fabs(bc[2]) < gEpsZeroMath) bc[2] = 0;
00540 
00541    double sum = bc[0] + bc[1] + bc[2];
00542 
00543    bc /= sum;
00544 }
00545 
00546 Wpt 
00547 Bface::nearest_pt(CWpt& p, Wvec &bc, bool &is_on_tri) const 
00548 {
00549    // returns the point on this face that is closest to p
00550    // also returns the barycentric coords of the near point.
00551 
00552    // get barycentric coords:
00553    project_barycentric(p, bc);
00554    
00555    // to account for numerical errors, snap
00556    // near-zero values to 0 and renormalize
00557    snap(bc);
00558 
00559    Wpt ret;
00560    if (bc[0] < 0 || bc[1] < 0 || bc[2] < 0) {
00561       // projected point is outside the triangle.
00562       // find closest point to an edge:
00563       is_on_tri = 0;
00564       double t1, t2, t3;
00565       CWpt& a = _v1->loc();
00566       CWpt& b = _v2->loc();
00567       CWpt& c = _v3->loc();
00568       Wpt p1 = pt_near_seg(a,b,p,t1);
00569       Wpt p2 = pt_near_seg(b,c,p,t2);
00570       Wpt p3 = pt_near_seg(c,a,p,t3);
00571       double d1 = (p1 - p).length_sqrd();
00572       double d2 = (p2 - p).length_sqrd();
00573       double d3 = (p3 - p).length_sqrd();
00574 
00575       if (d1 < d2) {
00576          if (d1 < d3) {
00577             bc.set(1-t1,t1,0);
00578             return p1;
00579          }
00580          bc.set(t3,0,1-t3);
00581          return p3;
00582       }
00583       if (d2 < d3) {
00584          bc.set(0,1-t2,t2);
00585          return p2;
00586       }
00587       bc.set(t3,0,1-t3);
00588       return p3;
00589    }
00590 
00591    is_on_tri = 1;
00592    bc2pos(bc, ret);
00593       
00594    return ret;
00595 }
00596 
00597 inline double
00598 signed_area_ndc(CNDCpt& a, CNDCpt& b, CNDCpt& c)
00599 {
00600    return 0.5 * det(b-a,c-a);
00601 }
00602 
00603 NDCpt 
00604 Bface::nearest_pt_ndc(CNDCpt& p, Wvec &bc, int &is_on_tri) const 
00605 {
00606    // Bsimplex virtual method
00607 
00608    // same as above, but operates in NDC space
00609 
00610    // get barycentric coords:
00611    NDCpt a = _v1->ndc();
00612    NDCpt b = _v2->ndc();
00613    NDCpt c = _v3->ndc();
00614    double A = signed_area_ndc(a, b, c);
00615    double u = signed_area_ndc(p, b, c) / A;
00616    double v = signed_area_ndc(a, p, c) / A;
00617    bc.set(u, v, 1 - u - v);
00618    
00619    // to account for numerical errors, snap
00620    // near-zero values to 0 and renormalize
00621    snap(bc);
00622 
00623    if (bc[0] < 0 || bc[1] < 0 || bc[2] < 0) {
00624       // p is outside the triangle.
00625       // find closest point to an edge:
00626       is_on_tri = 0;
00627       double t1, t2, t3;
00628 
00629       NDCpt p1 = pt_near_seg_ndc(a,b,p,t1);
00630       NDCpt p2 = pt_near_seg_ndc(b,c,p,t2);
00631       NDCpt p3 = pt_near_seg_ndc(c,a,p,t3);
00632 
00633       double d1 = p.dist_sqrd(p1);
00634       double d2 = p.dist_sqrd(p2);
00635       double d3 = p.dist_sqrd(p3);
00636 
00637       if (d1 < d2) {
00638          if (d1 < d3) {
00639             bc.set(1-t1,t1,0);
00640             return p1;
00641          }
00642          bc.set(t3,0,1-t3);
00643          return p3;
00644       }
00645       if (d2 < d3) {
00646          bc.set(0,1-t2,t2);
00647          return p2;
00648       }
00649       bc.set(t3,0,1-t3);
00650       return p3;
00651    }
00652 
00653    is_on_tri = 1;
00654    return (a*bc[0]) + (b*bc[1]) + (c*bc[2]);
00655 }
00656 
00657 // Similar to above, but returns the hit point 
00658 // both in local and barycentric coords:
00659 Wpt
00660 Bface::near_pt(CNDCpt& ndc, Wvec& hit_bc) const
00661 {
00662    // XXX - failure is not an option?
00663    return Bsimplex::nearest_pt(plane_intersect(nearest_pt_ndc(ndc)), hit_bc);
00664 }
00665 
00666 int 
00667 Bface::detach() 
00668 {
00669    // tell edges to forget about this face
00670    int ret = 1;
00671 
00672    if (_e1) ret = (*_e1 -= this) && ret;
00673    if (_e2) ret = (*_e2 -= this) && ret;
00674    if (_e3) ret = (*_e3 -= this) && ret;
00675 
00676    _e1 = _e2 = _e3 = 0;
00677 
00678    return ret;
00679 }
00680 
00681 void  
00682 Bface::reverse() 
00683 {
00684    // do it:
00685    swap(_v2,_v3);
00686    swap(_e1,_e3);
00687    if (_tc)
00688       swap(tex_coord(2),tex_coord(3));
00689 
00690    // tell patch tri strips are invalid:
00691    if (_patch)
00692       _patch->triangulation_changed();
00693    _orient = 0;
00694 
00695    geometry_changed();
00696 }
00697 
00698 void 
00699 Bface::make_primary()
00700 {
00701    clear_bit(SECONDARY_BIT); 
00702    geometry_changed();
00703 }
00704 
00705 void 
00706 Bface::make_secondary() 
00707 {
00708    set_bit(SECONDARY_BIT, 1); 
00709    geometry_changed();
00710 }
00711 
00712 bool 
00713 Bface::check() const
00714 {
00715    if (!(_v1 && _v2 && _v3 && _e1 && _e2 && _e3))
00716       return false;
00717 
00718    return ((_v1->lookup_edge(_v2) ==_e1) &&
00719            (_v2->lookup_edge(_v3) ==_e2) &&
00720            (_v3->lookup_edge(_v1) ==_e3));
00721 }
00722 
00723 bool 
00724 Bface::redef2(Bedge *a, Bedge *b)
00725 {
00726    static bool debug = Config::get_var_bool("DEBUG_MESH_OPS",false);
00727 
00728    // redefine this face, replacing a with b
00729    // update the old edge to forget this face,
00730    // and the new edge to remember it.
00731 
00732    // preconditions:
00733    //   a is an edge of this face.
00734    //   face does not already contain b.
00735 
00736    if (!contains(a)) {
00737       err_adv(debug, "Bface::redef2: error: face doesn't contain a");
00738       return false;
00739    }
00740    if (contains(b)) {
00741       err_adv(debug, "Bface::redef2: error: face already contains b");
00742       return false;
00743    }
00744 
00745    *a -= this;
00746 
00747    if      (a == _e1)   _e1 = b;
00748    else if (a == _e2)   _e2 = b;
00749    else if (a == _e3)   _e3 = b;
00750    else                 assert(0);
00751 
00752    *b += this;
00753 
00754    geometry_changed();
00755 
00756    return true;
00757 }
00758 
00759 bool
00760 Bface::redef2(Bvert *a, Bvert *b)
00761 {
00762    // Redefine this face, replacing vert a with vert b.
00763 
00764    // Different from Bface::redefine() below: here we assume
00765    // the edges are also being redefined to switch from
00766    // vert a to vert b, so we don't shed our current edges
00767    // and try to find our new ones.
00768 
00769    // precondition:
00770    //    a is a vertex of this face.
00771    //    b is not a vertex of this face.
00772 
00773    static bool debug = Config::get_var_bool("DEBUG_MESH_OPS",false);
00774    if (!contains(a)) {
00775       err_adv(debug, "Bface::redef2: error: vert to be replaced not found");
00776       return false;
00777    }
00778    if (contains(b)) {
00779       err_adv(debug, "Bface::redef2: error: new vert already in face");
00780       return false;
00781    }
00782 
00783    if      (_v1 == a)   _v1 = b;
00784    else if (_v2 == a)   _v2 = b;
00785    else if (_v3 == a)   _v3 = b;
00786    else                 assert(0);
00787 
00788    // tell patch strips are invalid:
00789    if (_patch)
00790       _patch->triangulation_changed();
00791    _orient = 0;
00792 
00793    // invalidate cached state in this face
00794    // and neighboring simplices:
00795    geometry_changed();
00796 
00797    return true;
00798 }
00799 
00800 int
00801 Bface::redefine(Bvert *v, Bvert *u)
00802 {
00803    // redefine the face, replacing vertex v with u
00804 
00805    // precondition:
00806    //    v is a vertex of this face.
00807    //    u is not a vertex of this face.
00808    //    this face has already detached from its edges.
00809    //    new edges have already been created appropriately.
00810    //    new face will not duplicate an existing face
00811 
00812    static bool debug = Config::get_var_bool("DEBUG_MESH_OPS",false);
00813 
00814    if (!contains(v)) {
00815       err_adv(debug, "Bface::redefine: error: old vert not found");
00816       return 0;
00817    }
00818 
00819    if (contains(u)) {
00820       err_adv(debug, "Bface::redefine: error: new vert already in face");
00821       return 0;
00822    }
00823 
00824    if      (_v1 == v)   _v1 = u;
00825    else if (_v2 == v)   _v2 = u;
00826    else if (_v3 == v)   _v3 = u;
00827    else                 assert(0);
00828 
00829    assert(!lookup_face(_v1, _v2, _v3));
00830 
00831    Bedge* e1 = _v1->lookup_edge(_v2);
00832    Bedge* e2 = _v2->lookup_edge(_v3);
00833    Bedge* e3 = _v3->lookup_edge(_v1);
00834 
00835    if (!(e1 && e2 && e3)) {
00836       err_adv(debug, "Bface::redefine: error: 1 or more edges not defined");
00837       return 0;
00838    }
00839 
00840    // coast is clear -- do it
00841    _e1 = e1;
00842    _e2 = e2;
00843    _e3 = e3;
00844 
00845    *_e1 += this;
00846    *_e2 += this;
00847    *_e3 += this;
00848 
00849    // tell patch strips are invalid:
00850    if (_patch)
00851       _patch->triangulation_changed();
00852    _orient = 0;
00853 
00854    // invalidate cached state in this face
00855    // and neighboring simplices:
00856    geometry_changed();
00857 
00858    return 1;
00859 }
00860 
00861 int
00862 Bface::redefine(
00863    Bvert *u, Bvert *nu,
00864    Bvert *v, Bvert *nv)
00865 {
00866    // redefine the face, replacing vertices u and v with nu and nv
00867 
00868    // precondition:
00869    //    u,v are vertices of this face.
00870    //    this face has already detached from its edges.
00871    //    new edges have already been created appropriately.
00872    //    new face will not duplicate an existing face
00873 
00874    if (!contains(u) || !contains(v))
00875       return 0;
00876 
00877    if      (u == _v1)   _v1 = nu;
00878    else if (u == _v2)   _v2 = nu;
00879    else if (u == _v3)   _v3 = nu;
00880    else                 return 0;
00881 
00882    if      (v == _v1)   _v1 = nv;
00883    else if (v == _v2)   _v2 = nv;
00884    else if (v == _v3)   _v3 = nv;
00885    else                 return 0;
00886 
00887    Bedge* e1 = _v1->lookup_edge(_v2);
00888    Bedge* e2 = _v2->lookup_edge(_v3);
00889    Bedge* e3 = _v3->lookup_edge(_v1);
00890 
00891    if (!e1 || !e2 || !e3 ||
00892       lookup_face(_v1, _v2, _v3)) {
00893       return 0;
00894    }
00895       
00896    // coast is clear -- do it
00897    _e1 = e1;
00898    _e2 = e2;
00899    _e3 = e3;
00900 
00901    *_e1 += this;
00902    *_e2 += this;
00903    *_e3 += this;
00904 
00905    // tell patch strips are invalid:
00906    if (_patch)
00907       _patch->triangulation_changed();
00908    _orient = 0;
00909 
00910    // invalidate cached state in this face
00911    // and neighboring simplices:
00912    geometry_changed();
00913 
00914    return 1;
00915 }
00916 
00917 CWvec&
00918 Bface::vert_normal(CBvert* v, Wvec& n) const
00919 {
00920    // for gouraud shading: return appropriate 
00921    // normal to use at a vertex of this face 
00922 
00923    assert(this->contains(v));
00924 
00925    if(!v->is_crease()) {
00926       n = v->norm();
00927       return n;
00928    }
00929 
00930    // take average of face normals in star of v,
00931    // using faces which can be reached from this
00932    // face without crossing a crease edge
00933 
00934    n = weighted_vnorm(this, v); // add weighted normal from this face
00935    int count = 1;       // count of faces processed
00936 
00937    // wind around v in clockwise direction
00938    // but don't cross a crease edge
00939    CBface* f = this;
00940    Bedge* e = edge_from_vert(v);
00941    for (; e&&!e->is_crease() && (f=e->other_face(f)); e=f->edge_from_vert(v)) {
00942       n += weighted_vnorm(f, v);
00943       if (++count > v->degree()) {
00944          // this should never happen, but it does
00945          // happen on effed up models
00946          // (i.e. when "3rd faces" get added)
00947          break;
00948       }
00949    }
00950 
00951    // wind around v in counter-clockwise direction;
00952    // as before, don't cross a crease edge
00953    f = this;
00954    e = edge_before_vert(v);
00955    for(; e&&!e->is_crease()&&(f=e->other_face(f)); e=f->edge_before_vert(v)) {
00956       n += weighted_vnorm(f, v);
00957       if(++count > v->degree())
00958          break;
00959    }
00960 
00961    n = n.normalized();
00962    return n;
00963 }
00964 
00965 bool
00966 Bface::get_quad_verts(Bvert*& a, Bvert*& b, Bvert*& c, Bvert*& d) const
00967 {
00968    //  Return CCW verts a, b, c, d as in the picture, orienting
00969    //  things so that the weak edge runs NE as shown:
00970    //
00971    //    d ---------- c = w->v2()              ^      
00972    //    |          / |                        |       
00973    //    |        /   |                        |       
00974    //    |    w /     |       tan1        tan2 |       
00975    //    |    /       |    -------->           |       
00976    //    |  /     f   |                        |       
00977    //    |/           |                                
00978    //    a ---------- b                                
00979    //     = w->v1()
00980    //
00981    if (!is_quad())
00982       return 0;
00983 
00984    Bedge* w = weak_edge();
00985    Bface* f = w->ccw_face(w->v2());
00986    a = w->v1();
00987    b = f->next_vert_ccw(a);
00988    c = w->v2();
00989    d = f->quad_vert();
00990 
00991    return true;
00992 }
00993 
00994 
00995 
00996 bool 
00997 Bface::get_quad_verts(Bvert_list& verts) const 
00998 {
00999    verts.clear();
01000    Bvert *v1=0, *v2=0, *v3=0, *v4=0;
01001    if (!get_quad_verts(v1,v2,v3,v4))
01002       return 0;
01003    verts += v1;
01004    verts += v2;
01005    verts += v3;
01006    verts += v4;
01007    return 1;
01008 
01009 }
01010 bool
01011 Bface::get_quad_pts(Wpt& a, Wpt& b, Wpt& c, Wpt& d) const 
01012 {
01013    Bvert *v1=0, *v2=0, *v3=0, *v4=0;
01014    if (!get_quad_verts(v1,v2,v3,v4))
01015       return 0;
01016    a = v1->loc();
01017    b = v2->loc();
01018    c = v3->loc();
01019    d = v4->loc();
01020    return 1;
01021 }
01022 
01023 bool 
01024 Bface::get_quad_edges(Bedge*& a, Bedge*& b, Bedge*& c, Bedge*& d) const
01025 {
01026    Bvert *v1=0, *v2=0, *v3=0, *v4=0;
01027    if (!get_quad_verts(v1,v2,v3,v4))
01028       return 0;
01029 
01030    assert(v1&&v2&&v3&&v4);
01031 
01032    a=v1->lookup_edge(v2);
01033    b=v2->lookup_edge(v3);
01034    c=v3->lookup_edge(v4);
01035    d=v4->lookup_edge(v1);
01036 
01037    assert(a&&b&&c&&d);
01038    return 1;
01039 
01040 }
01041 bool 
01042 Bface::get_quad_edges(Bedge_list& edges)                          const
01043 {
01044   edges.clear();
01045    Bedge *e1=0, *e2=0, *e3=0, *e4=0;
01046    if (!get_quad_edges(e1,e2,e3,e4))
01047       return 0;
01048    edges += e1;
01049    edges += e2;
01050    edges += e3;
01051    edges += e4;
01052    return 1;
01053 }
01054 
01055 
01056 
01057 
01058 Wvec
01059 Bface::quad_tan1() const 
01060 {
01061    // Based on the 4 verts in standard orientation as above,
01062    // return the tangent vector running right:
01063    Wpt a, b, c, d;
01064    get_quad_pts(a,b,c,d);
01065 
01066    Wvec t = ((b - a) + (c - d))*0.5;
01067    return t.orthogonalized(quad_norm()).normalized();
01068 }
01069 
01070 Wvec
01071 Bface::quad_tan2() const 
01072 {
01073    // Based on the 4 verts in standard orientation as above,
01074    // return the tangent vector running up
01075    Wpt a, b, c, d;
01076    get_quad_pts(a,b,c,d);
01077 
01078    Wvec t = ((d - a) + (c - b))*0.5;
01079    return t.orthogonalized(quad_norm()).normalized();
01080 }
01081 
01082 double
01083 Bface::quad_dim1() const
01084 {
01085    // Based on the 4 verts in standard orientation as above,
01086    // return the average of the two horizontal edge lengths
01087    Wpt a, b, c, d;
01088    get_quad_pts(a,b,c,d);
01089 
01090    return (b.dist(a) + c.dist(d))/2;
01091 }
01092 
01093 double
01094 Bface::quad_dim2() const
01095 {
01096    // Based on the 4 verts in standard orientation as above,
01097    // return the average of the two vertical edge lengths
01098    Wpt a, b, c, d;
01099    get_quad_pts(a,b,c,d);
01100 
01101    return (b.dist(c) + a.dist(d))*0.5;
01102 }
01103 
01104 UVpt
01105 Bface::quad_bc_to_uv(CWvec& bc) const
01106 {
01107    // We got some barycentric coords WRT this face (a quad),
01108    // and now we want to convert them to uv-coords WRT to
01109    // the 4 quad vertices in standard order.
01110 
01111    //
01112    //    d ---------- c                               
01113    //    |          / |                                
01114    //    |        /   |                                
01115    //    |      /     |                                
01116    //    |    /       |                                
01117    //    |  /         |                                
01118    //    |/           |                                
01119    //    a ---------- b                                
01120    //
01121    //   STANDARD QUAD ORDER
01122    
01123    Bvert *a=0, *b=0, *c=0, *d=0;
01124    if (!get_quad_verts(a, b, c, d)) {
01125       err_msg("Bface::quad_bc_to_uv: Error: can't get quad verts");
01126       return UVpt();
01127    }
01128 
01129    // Barycentric coords are given WRT to vertices v1, v2, v3.
01130    // We want them WRT:
01131    //   a, b, c (lower face), or
01132    //   a, c, d (upper face).
01133    //
01134    // k = 0, 1, or 2 according to whether a = v1, v2, or v3.
01135    int k = vindex(a) - 1;
01136    if (k < 0 || k > 2) {
01137       err_msg("Bface::quad_bc_to_uv: Error: can't get oriented");
01138       return UVpt();
01139    }
01140    if (contains(b)) {
01141       // We are the lower face.
01142       return UVpt(1 - bc[k], bc[(k + 2)%3]);
01143    } else if (contains(d)) {
01144       // We are the upper face.
01145       return UVpt(bc[(k + 1)%3], 1 - bc[k]);
01146    } else {
01147       // Should not happen
01148       err_msg("Bface::quad_bc_to_uv: Error: can't get oriented");
01149       return UVpt();
01150    }
01151 }
01152 
01153 Wpt
01154 Bface::quad_uv2loc(CUVpt& uv) const
01155 {
01156    // Maps the given uv coordinate (WRT the quad) to a Wpt:
01157    //
01158    //
01159    //    d ---------- c                               
01160    //    |          / |                                
01161    //    |        /   |                                
01162    //    |      /     |                                
01163    //    |    /       |                                
01164    //    |  /         |                                
01165    //    |/           |                                
01166    //    a ---------- b                                
01167    //
01168    //   STANDARD QUAD ORDER
01169    
01170    Bvert *a=0, *b=0, *c=0, *d=0;
01171    if (!get_quad_verts(a, b, c, d)) {
01172       err_msg("Bface::quad_uv2loc: Error: can't get quad verts");
01173       return Wpt();
01174    }
01175 
01176    // ensure coordinates are interior to quad
01177    double u = clamp(uv[0], 0.0, 1.0);
01178    double v = clamp(uv[1], 0.0, 1.0);
01179 
01180    // lower triangle
01181    if (v <= u) {
01182       double w = ((u == 0) ? 0.0 : (v/u));
01183       return interp(interp(a->loc(), b->loc(), u),
01184                     interp(a->loc(), c->loc(), u), w);
01185    } else {
01186       double w = ((u == 1) ? 1.0 : ((v - u)/(1 - u)));
01187       return interp(interp(a->loc(), c->loc(), u),
01188                     interp(d->loc(), c->loc(), u), w);
01189    }
01190 }
01191 
01192 /************************************************************
01193  * Bface_list
01194  ************************************************************/
01195 
01196 void
01197 Bface_list::clear_vert_flags() const
01198 {   
01199    // Clear the flag of each vertex of each face
01200 
01201    for (int i=0; i<_num; i++)
01202       for (int j=1; j<4; j++)
01203          _array[i]->v(j)->clear_flag();
01204 }
01205 
01206 void
01207 Bface_list::clear_edge_flags() const
01208 {   
01209    // Clear the flag of each edge of each face:
01210    for (int i=0; i<_num; i++)
01211       for (int j=1; j<4; j++)
01212          _array[i]->e(j)->clear_flag();
01213 }
01214 
01215 Bvert_list 
01216 Bface_list::get_verts() const
01217 {
01218    // Extract a list of the verts found in the given faces.
01219 
01220    // Get clean slate
01221    clear_vert_flags();
01222 
01223    // Put verts into output array uniquely:
01224    Bvert_list ret(_num);       // pre-allocate plenty
01225    for (int i=0; i<_num; i++) {
01226       for (int j=1; j<4; j++) {
01227          Bvert* v = _array[i]->v(j);
01228          if (!v) {
01229             err_msg("Bface_list::get_verts: null vert");
01230          } else if (v->flag() == 0) {
01231             v->set_flag(1);
01232             ret += v;
01233          }
01234       }
01235    }
01236    return ret;
01237 }
01238 
01239 Bedge_list 
01240 Bface_list::get_edges() const
01241 {
01242    // Extract a list of the edges found in the given faces.
01243 
01244    // Get clean slate
01245    clear_edge_flags();
01246 
01247    // Put edges into output array uniquely:
01248    Bedge_list ret(_num*2);       // pre-allocate plenty
01249    for (int i=0; i<_num; i++) {
01250       for (int j=1; j<4; j++) {
01251          Bedge* e = _array[i]->e(j);
01252          if (e->flag() == 0) {
01253             e->set_flag(1);
01254             ret += e;
01255          }
01256       }
01257    }
01258    return ret;
01259 }
01260 
01261 Wvec
01262 Bface_list::avg_normal() const
01263 {
01264    // Returns the average of the face normals
01265    Wvec ret;
01266    for (int i=0; i<_num; i++)
01267       ret += _array[i]->norm();
01268    return ret.normalized();
01269 }
01270 
01271 double
01272 Bface_list::max_norm_deviation(CWvec& n) const
01273 {
01274    // Returns the maximum deviation, in radians, of a normal from the
01275    // value passed in
01276 
01277    double ret = 0;
01278    for (int i=0; i<_num; i++)
01279       ret = max(ret, n.angle(_array[i]->norm()));
01280    return ret;
01281 }
01282 
01283 double 
01284 Bface_list::volume() const 
01285 {
01286    // Returns the sum of the "volume elements" for each face.
01287    // Really only makes sense for a list of faces forming a
01288    // closed surface; though if the faces form a nearly-closed
01289    // surface it can tell you if they are oriented mostly
01290    // inside-out or not. (Negative volume == inside out.)
01291    // Uses the divergence theorem.
01292 
01293    double ret = 0;
01294    for (int k=0; k<_num; k++)
01295       ret += _array[k]->volume_el();
01296    return ret;
01297 }
01298 
01299 void
01300 Bface_list::mark_faces() const
01301 {
01302    // Set the flag of each face to 1, and clear the flags of
01303    // each face around the boundary of this set of faces.
01304 
01305    // Clear vertex, edge, and face flags within a 1-neighborhood
01306    // of any vertex of this set of faces:
01307    get_verts().clear_flag02();
01308 
01309    // Set face flags to 1:
01310    set_flags(1);
01311 }
01312 
01313 Bface_list
01314 Bface_list::exterior_faces() const 
01315 {
01316    // Like the one-ring, but doesn't include faces of this set:
01317 
01318    Bface_list ret = one_ring_faces();
01319    mark_faces();
01320    return ret.filter(SimplexFlagFilter(0));
01321 }
01322 
01323 inline Bface*
01324 check_partner(Bface* f)
01325 {
01326    // helper function used in quad_complete_faces() below
01327 
01328    if (!(f && f->is_quad()))
01329       return 0;
01330    Bface* p = f->quad_partner();
01331    return p->flag() ? 0 : p;
01332 }
01333 
01334 Bface_list
01335 Bface_list::quad_complete_faces() const
01336 {
01337    // If the list contains any "quad" faces but not their partners,
01338    // returns the "completed" list, containing the missing partners:
01339 
01340    mark_faces();
01341    Bface* p=0;
01342    Bface_list ret = *this;
01343    for (int i=0; i<_num; i++)
01344       if ((p = check_partner(_array[i])))
01345          ret.add(p);
01346    return ret;
01347 }
01348 
01349 Bface_list
01350 Bface_list::reachable_faces(Bface* f, CSimplexFilter& pass)
01351 {
01352    // Returns the list of faces reachable from f, crossing
01353    // only edges accepted by the filter. It sets needed
01354    // flags (on the entire mesh) then calls grow_connected().
01355 
01356    Bface_list ret;
01357 
01358    if (!(f && f->mesh()))
01359       return ret;
01360 
01361    // Ensure all reachable face flags are set to 1:
01362 
01363    // XXX -
01364    //   touches every face in the mesh; a better
01365    //   implementation would just touch reachable ones
01366    //   (or is that impossible to implement?)
01367    f->mesh()->faces().set_flags(1);
01368 
01369    ret.grow_connected(f, pass);
01370    return ret;
01371 }
01372 
01373 bool
01374 Bface_list::grow_connected(Bface* f, CSimplexFilter& pass)
01375 {
01376    // Collect all reachable faces whose flag == 1, starting at f,
01377    // crossing only edges that are accepted by the given filter.
01378 
01379    if (!(f && f->flag() == 1))
01380       return false;
01381 
01382    f->set_flag(2);
01383    add(f);
01384 
01385    // check each neighboring edge:
01386    for (int i=1; i<4; i++) {
01387       Bedge* e = f->e(i);
01388       if (pass.accept(e)) {
01389          // check each adjacent face
01390          // (includes this, but that will be a no-op):
01391          for (int j=1; j<=e->num_all_faces(); j++)
01392             grow_connected(e->f(j), pass);
01393       }
01394    }
01395 
01396    return true;
01397 }
01398 
01399 bool
01400 Bface_list::is_connected() const
01401 {
01402    // Returns true if the faces form a single connected component:
01403    // Note: two faces that share a vertex but not an edge are
01404    //       NOT connected.
01405 
01406    // reject if empty or not all from one mesh:
01407    if (mesh() == NULL)
01408       return false;
01409 
01410    // Find all faces connected to the first triangle.
01411    // if the number found is the number in the entire list,
01412    // the whole list is connected.
01413 
01414    // Mark internal faces with flag = 1,
01415    // clear flags in the 1-ring around these faces:
01416    mark_faces();
01417                                                                                 
01418    // Find the component that contains the first face.
01419    // The search will not go outside this Bface_list,
01420    // because every neighboring outside face has flag == 0
01421    // and will therefore be ignored.
01422    Bface_list comp1(_num);
01423    comp1.grow_connected(first());
01424 
01425    bool debug = Config::get_var_bool("DEBUG_BFACE_LIST_IS_CONNECTED", false);
01426 
01427    err_adv(debug, "Bface_list::is_connected:");
01428    err_adv(debug, "  nfaces: %d, comp 1: %d, connected: %s",
01429            _num, comp1.num(), ((comp1.num() == _num) ? "yes" : "no"));
01430 
01431    // Return true iff that component is the whole Bface_list:
01432    return comp1.num() == _num;
01433 }
01434 
01435 bool
01436 Bface_list::is_disk() const
01437 {
01438    // Returns true if the set is connected, the boundary is a simple
01439    // loop, and the faces form a 2-manifold (WRT faces of this set):
01440 
01441    return (is_connected() &&
01442            get_boundary().num_line_strips() == 1 &&
01443            is_2_manifold());
01444 }
01445 
01446 EdgeStrip
01447 Bface_list::get_boundary() const
01448 {
01449    // Returns the boundary of this set of faces.
01450    // I.e., returns an edge strip describing chains of edges
01451    // that wind CCW around the faces in this list.
01452 
01453    // Mark internal faces with flag = 1,
01454    // neighboring faces outside the list with flag = 0:
01455    mark_faces();
01456 
01457    EdgeStrip ret;
01458    ret.build_ccw_boundaries(get_edges(), SimplexFlagFilter(1));
01459    return ret;
01460 }
01461 
01462 Bedge_list 
01463 Bface_list::boundary_edges() const 
01464 {
01465    return get_boundary().edges();
01466 }
01467 
01468 Bedge_list 
01469 Bface_list::interior_edges() const 
01470 {
01471    // Return list of edges that are not adjacent to any external face.
01472 
01473    // mark internal faces w/ flag 1, external faces with flag 0:
01474    mark_faces(); 
01475    return get_edges().filter(!BoundaryEdgeFilter(SimplexFlagFilter(1)));
01476 }
01477 
01478 Bvert_list 
01479 Bface_list::interior_verts() const 
01480 {
01481    // Return list vertices that are not adjacent to any external face.
01482 
01483    // mark internal faces w/ flag 1, external faces with flag 0:
01484    mark_faces(); 
01485    return get_verts().filter(VertFaceDegreeFilter(0, SimplexFlagFilter(0)));
01486 }
01487 
01488 bool
01489 Bface_list::is_consistently_oriented() const
01490 {
01491    // Returns true if no edge *interior* to this set of faces 
01492    // has 2 adjacent faces with inconsistent orientation:
01493 
01494    SimplexFlagFilter    me(1);                  // accepts my faces (flag = 1)
01495    BoundaryEdgeFilter   boundary(me);           // accepts my boundary edges
01496    NotFilter            interior(boundary);     // accepts my interior edges
01497    ConsistentEdgeFilter consistent;
01498    NotFilter            inconsistent(consistent); // accepts inconsistent edges
01499 
01500    // Mark internal faces with flag = 1,
01501    // neighboring faces outside the list with flag = 0:
01502    mark_faces();
01503 
01504    if (Config::get_var_bool("DEBUG_INFLATE_ALL",false)) {
01505       err_msg("Total faces: %d", _num);
01506       err_msg("Total edges: %d", get_edges().num());
01507       err_msg("Boundary edges: %d", get_edges().filter(boundary).num());
01508       err_msg("Interior edges: %d", get_edges().filter(!boundary).num());
01509       err_msg("Inconsistent edges: %d", get_edges().filter(inconsistent).num());
01510    }
01511 
01512    return get_edges().filter(interior + inconsistent).empty();
01513 }
01514 
01515 
01516 bool
01517 Bface_list::is_2_manifold() const
01518 {
01519    // Returns true if every contained edge is adjacent to no more than
01520    // 2 faces of *this* face set:
01521 
01522    // Mark these faces 1, all adjacent ones 0
01523    mark_faces();
01524 
01525    // Returns true if no edge is adjacent to more than 2 of *these* faces
01526    return get_edges().all_satisfy(ManifoldEdgeFilter(SimplexFlagFilter(1)));
01527 }
01528 
01529 bool 
01530 Bface_list::can_push_layer() const
01531 {
01532    // Reports whether it valid to call push_layer() on this face set.
01533    //
01534    // Preliminary version.
01535 
01536    // If the region is already entirely secondary,
01537    // our job is done, so report "success":
01538    if (is_all_secondary())
01539       return true;
01540 
01541    return (!empty() && same_mesh());
01542 }
01543 
01544 inline void
01545 demote(Bface* f)
01546 {
01547    // Used by Bface_list::push_layer() below.
01548    // If any adjacent edge has its flag set,
01549    // then demote this face WRT that edge.
01550 
01551    if (!f) return;
01552    if (f->e1()->flag()) f->e1()->demote(f);
01553    if (f->e2()->flag()) f->e2()->demote(f);
01554    if (f->e3()->flag()) f->e3()->demote(f);
01555 }
01556 
01557 bool 
01558 Bface_list::push_layer(bool push_boundary) const
01559 {
01560    // Given a set of faces from a single mesh, mark the
01561    // faces as a separate "layer" of the mesh, with
01562    // lower priority than the primary, manifold layer:
01563 
01564    if (!can_push_layer()) {
01565       err_msg("Bface_list::push_layer: invalid operation");
01566       return false;
01567    }
01568 
01569    // If the region is already entirely secondary,
01570    // our job is done, so report "success":
01571    if (is_all_secondary())
01572       return true;
01573 
01574    // Mark all faces non-primary.
01575    // (Bface virtual method sets bit Bface::SECONDARY_BIT;
01576    //  in Lface it's propagated to lower subdiv levels.)
01577    make_secondary();
01578 
01579    // XXX - hack; still trying to work out the correct policy...
01580    if (push_boundary) {
01581 
01582       // Distinguish boundary edges by setting their flags to 1
01583       // while all other flags are 0.
01584       EdgeStrip bdry = get_boundary();
01585 
01586       // pass the word down the subdiv hierarchy
01587       // that uv coords are splitting
01588       UVdata::split(bdry);
01589 
01590       // Now visit boundary edges and ensure faces of this list
01591       // do not occupy primary _f1 or _f2 slots in each edge.
01592 
01593       get_edges().clear_flags();
01594 //   bdry.edges().filter(InteriorEdgeFilter()).set_flags();
01595       bdry.edges().set_flags();
01596 
01597       // See inlined demote() above
01598       for (int i=0; i<num(); i++)
01599          demote(_array[i]);
01600 
01601    }
01602 
01603    // Notify mesh to rebuild tri-strips, check topology etc.
01604    assert(mesh());
01605    mesh()->changed();
01606 
01607    return true;
01608 }
01609 
01610 bool 
01611 Bface_list::can_unpush_layer() const
01612 {
01613    // Reports whether unpush_layer() can successfully be called for
01614    // this face set.
01615 
01616    // If the region is already entirely primary,
01617    // our job is done, so report "success":
01618    if (is_all_primary())
01619       return true;
01620 
01621    static bool debug = Config::get_var_bool("DEBUG_PUSH_FACES",false);
01622    if (debug) {
01623       bool b = boundary_edges().all_satisfy(CanPromoteEdgeFilter());
01624       cerr << "Bface_list::can_unpush_layer: " << endl
01625            << "   " << num() << " faces, "
01626            << (same_mesh() ? "same mesh" : "different meshes") << ", "
01627            << (is_2_manifold() ? "" : "non-") << "manifold, "
01628            << "boundary: " << (b ? "good" : "bad")
01629            << " (" << boundary_edges().num() << " edges)"
01630            << endl;
01631       Bedge_list bad_edges = boundary_edges().filter(!CanPromoteEdgeFilter());
01632       cerr << bad_edges.num() << " bad edges" << endl;
01633       if (!b) {
01634          MeshGlobal::select(bad_edges);
01635       }
01636    }
01637    return (!empty() && same_mesh() &&
01638            is_2_manifold() && 
01639            boundary_edges().all_satisfy(CanPromoteEdgeFilter()));
01640 }
01641 
01642 inline void
01643 promote(Bface* f)
01644 {
01645    // Used by Bface_list::unpush_layer() below.
01646    // If any adjacent edge has its flag set,
01647    // then promote this face WRT that edge.
01648 
01649    if (!f) return;
01650    if (f->e1()->flag()) f->e1()->promote(f);
01651    if (f->e2()->flag()) f->e2()->promote(f);
01652    if (f->e3()->flag()) f->e3()->promote(f);
01653 }
01654 
01655 bool 
01656 Bface_list::unpush_layer(bool unpush_boundary) const
01657 {
01658    // Given a set of faces from a single mesh,
01659    // restore the faces to "primary" status.
01660 
01661    if (!can_unpush_layer()) {
01662       err_msg("Bface_list::unpush_layer: invalid operation");
01663       return false;
01664    }
01665 
01666    // If the region is already entirely primary,
01667    // our job is done, so report "success":
01668    if (is_all_primary())
01669       return true;
01670 
01671    // Mark all faces primary
01672    // (virtual method propagates change to lower subdiv levels)
01673    make_primary();
01674 
01675    if (unpush_boundary) {
01676       // Ensure all edge flags are clear except the boundary ones.
01677       EdgeStrip bdry = get_boundary();
01678       get_edges().clear_flags();
01679       bdry.edges().set_flags();
01680 
01681       // See inlined promote() above
01682       for (int i=0; i<num(); i++)
01683          promote(_array[i]);
01684    }
01685 
01686    // Notify mesh to rebuild tri-strips, check topology etc.
01687    assert(mesh());
01688    mesh()->changed();
01689 
01690    return true;
01691 }
01692 
01693 /* end of file bface.C */

Generated on Mon Sep 18 11:39:28 2006 for jot by  doxygen 1.4.4