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

zcross_path.C

Go to the documentation of this file.
00001 /**********************************************************************
00002  * zcross_path.C:
00003  **********************************************************************/
00004 
00005 
00006 #include "bmesh.H"
00007 #include "stripcb.H"
00008 
00009 /**********************************************************************
00010  * ZcrossPath:
00011  **********************************************************************/
00012 void
00013 ZcrossPath::get_g(Bface * f , double g[], int& ex1, int&  ex2)
00014 {
00015    int i;
00016    Wvec v1;
00017    for ( i=0; i < 3; i++ ) {
00018       g[i] = (_eye - f->v(i+1)->loc()).normalized() * f->vert_normal(f->v(i+1), v1);
00019       if ( g[i] == 0 ) {
00020          //cerr << "g = 0! setting to -1e-8\n";
00021          g[i] = -1e-8;    // sinful but convenient
00022       }
00023    }
00024 
00025    if ( g[0] > 0 ) {
00026       if( g[1] > 0 ){
00027          ex1 = 1; ex2 = 2;
00028       } else if( g[2] > 0 ){
00029          ex1 = 0; ex2 = 1;
00030       } else {
00031          ex1 = 0; ex2 = 2;
00032       }
00033    } else { //g0 < 0
00034       if( g[1] < 0 ){
00035          ex1 = 1; ex2 = 2;
00036       } else if( g[2] < 0 ){
00037          ex1 = 0; ex2 = 1;
00038       } else {
00039          ex1 = 0; ex2 = 2;
00040       }
00041    }
00042 }
00043 
00044 bool
00045 ZcrossPath::has_sil(Bface * f)
00046 {
00047 
00048    if ( f->zx_query() )
00049       return false;
00050    f->zx_mark();
00051 
00052    int i;
00053    double g[3];
00054    Wvec v1;
00055    for ( i=0; i < 3; i++ ) {
00056       g[i] = ( _eye - f->v(i+1)->loc() ).normalized() * f->vert_normal(f->v(i+1), v1);
00057       if ( g[i] == 0 ) {
00058          //cerr << "g = 0! setting to -1e-8\n";
00059          g[i] = -1e-8;      // sinful but convenient
00060       }
00061 
00062    }
00063 
00064    // if a zero crossing is on the face, it crosses two edges
00065    // so we only need to check from one vertex
00066    // >=, <= for rare case that a vertex g = 0.0
00067 
00068    if ( ( g[0] > 0 && ( g[1] < 0 || g[2] < 0 ) ) ||
00069         ( g[0] < 0 && ( g[1] > 0 || g[2] > 0 ) ) )
00070       return true;
00071 
00072    return false;
00073 }
00074 
00075 void
00076 ZcrossPath::build(CBface_list& list )
00077 {
00078    int k;
00079    for (k = 0 ; k < list.num(); k++)
00080       if ( has_sil(list[k]))
00081          start_sil(list[k]);
00082 }
00083 
00084 void
00085 ZcrossPath::start_sil(Bface *f )
00086 {
00087 
00088    /*
00089     *
00090     *  the face class accessor to vertices, edges, etc 
00091     *  f->v() , f->e(), etc. all take a point from 1 to 3
00092     *  this is a huge pain when you are trying to move around
00093     *  the triangle, so i store my values , - g , ex1, ex2, 
00094     *  in the 0 to 2 range 
00095     *
00096     */
00097 
00098 
00099 
00100    /* the call to has_sil returns if mesh has been looked at
00101     * and ALWAYS marks it as such. be careful..
00102     *
00103     *  this should really be called sil_marked(); or something
00104     */
00105    if (!has_sil(f))
00106       return; //f has been zx_checked this frame
00107 
00108 
00109    double g[3]; //
00110    int ex1, ex2 , nex1, nex2; //indices of cross edges, in 0-2;
00111    //ex1  is vertex 1 of edge 1 ( and index to edge )
00112    //nex1 is vertex 2 of edge 1
00113    bool bgrad;
00114 
00115    get_g(f, g, ex1, ex2 ); //calculates g values, and where
00116 
00117    Bface *f1;
00118    Bface *f2;
00119 
00120    Bface *iter_f; //iterator for mesh traversal;
00121    nex1 = (ex1+1)%3;
00122    nex2 = (ex2+1)%3;
00123 
00124    // new iterators for mesh traversal
00125    Bvert * svrt[3];
00126    double sg[3];
00127 
00128    //never check across a crease boundary ()
00129    //it's a discontinuity in the isosurface
00130 
00131    f1 = ( f->e(ex1+1)->is_crease()) ? NULL : f->nbr(ex1+1);
00132    f2 = ( f->e(ex2+1)->is_crease()) ? NULL : f->nbr(ex2+1);
00133 
00134 
00135    //case 1 - we search and close the loop
00136    //case 2 - we do not close loop -> so search backward, fix
00137 
00138    double alph1 = -g[ex1] / (g[nex1] - g[ex1]);
00139    Wpt pt1 = interp ( f->v(ex1+1)->loc(), f->v(nex1+1)->loc(), alph1);
00140 
00141    double alph2 = -g[ex2] / (g[nex2] - g[ex2]);
00142    Wpt pt2 = interp ( f->v(ex2+1)->loc(), f->v(nex2+1)->loc(), alph2);
00143 
00144 
00145    // gradient test;
00146    int gmax = ( g[0] > g[1] ) ? 0 : 1;
00147    gmax = ( g[2] > g[gmax] ) ? 2 : gmax;
00148 
00149    Wvec v_iso = pt1 - pt2;
00150    Wvec v_max = f->v(gmax+1)->loc() - pt2;
00151    Wvec v_grad = v_max.orthogonalized(v_iso);
00152    bgrad = ( ( _eye - pt2 ) * v_grad  > 0 ) ;
00153 
00154    //we always move clockwise
00155    // more specifically, if gradient is up, we always
00156    // check in the same direction
00157 
00158    // you only have to check once
00159 
00160    if ( cross( v_grad , f->norm()) * v_iso > 0 ) {
00161       swap ( pt1, pt2);
00162       swap ( alph1, alph2);
00163       swap ( f1, f2);
00164       swap ( ex1, ex2 );
00165       swap ( nex1, nex2);
00166    }
00167 
00168    //if everything switches, so does bgrad!
00169 
00170    //vert is the front ( according to gradient ) vertex on the list
00171    //we were going to use it for visibility, but at the moment it's
00172    //useless.
00173 
00174    // store our own barycentric coordinate
00175 
00176    Wvec bc;
00177    bc[ex2] = 1.0-alph2;
00178    bc[nex2] = alph2;
00179 
00180 
00181    //start search on f1
00182 
00183 
00184 
00185    int cstart = num(); // index start of this chain (for case 2 );
00186 
00187    iter_f = f;
00188    add_seg ( f , pt2, f->v(ex2+1), bgrad, f);
00189 
00190    if (f1) {
00191 
00192       svrt  [0]   = f->v(ex2+1) ;     //initialize cache values
00193       sg    [0]   = g[ex2];        //for sil_search
00194       svrt  [1]   = f->v(nex2+1);     //skee-daddle
00195       sg    [1]   = g[nex2];
00196 
00197       //we start at f, having already added the previous point
00198       while ( iter_f ) {
00199 
00200          iter_f = sil_walk_search(iter_f, svrt, sg);
00201 
00202          if ( iter_f == f ) {  //closed loop
00203 
00204             if ( !( _segs[cstart].p()  == _segs.last().p() ) ) {
00205                //cerr << "XXX ZcrossPath::start_sil():: points are not equal" << endl;
00206                //                 Wpt a = _segs[cstart].p();
00207                //                 Wpt b = _segs.last().p();
00208                //cerr << "diff:" << (a-b).length() << endl;
00209                _segs.last().p() = _segs[cstart].p() ;
00210             }
00211             _segs.last().setf( NULL );
00212             _segs.last().set_end(); 
00213             _segs.last().set_bary(f2);
00214 
00215             return;
00216          }
00217 
00218       }
00219    } else {
00220       add_seg ( NULL , pt1, f->v(ex1+1), bgrad, f);
00221    }
00222 
00223    //if we are this far, we have a section of
00224    //silhouette in the forward direction, ( it may only cross one triangle tho )
00225    //which ran across a discontinuity
00226 
00227    //now check for the stretch in the opposite direction
00228 
00229    int chain2start = num(); // index of start of next chain
00230 
00231    if ( !f2 )
00232       return; // first face in reverse direction is NULL, we are done.
00233 
00234    //find second chain, which needs to be reversed
00235    //starts at pt2;
00236 
00237 
00238    iter_f  = f2;
00239    add_seg ( f2 , pt2, f->v(ex2+1), bgrad, f2);
00240 
00241    svrt[0] = f->v(ex2+1) ;     //initialize cached values
00242    sg[0]  = g[ex2];  //for sil_search
00243    svrt[1] = f->v(nex2+1);
00244    sg[1]  = g[nex2];
00245 
00246    while ( iter_f ) {
00247       iter_f = sil_walk_search ( iter_f, svrt, sg );
00248    }
00249    int chain2end = num();
00250    // second chain is found in wrong order, so we flip it
00251 
00252 
00253    // reversal code
00254 
00255 
00256    int chain2num = (chain2end - chain2start) -1 ;
00257    if ( chain2num < 0 )
00258       return;
00259 
00260    _segs.insert(cstart, chain2num);
00261    int last_ind = num()-1;
00262 
00263    int j=0;
00264    for ( ; j < chain2num ; j++ ) {
00265       _segs[last_ind-j].setf( _segs[last_ind-(j+1)].f() );      //shift the faces over by one
00266       //AND any per-face values
00267       _segs[last_ind-j].setg(_segs[last_ind-(j+1)].g());        //grad associates with face
00268       _segs[last_ind-j].set_bary(_segs[last_ind-j].f());        //recalc barycentric
00269    }
00270    for ( j=0; j < chain2num ; j++) {
00271       _segs[cstart+j] = _segs.pop();
00272    }
00273 
00274    _segs.pop(); //last point was the duplicate
00275 
00276    return;
00277 }
00278 
00279 Bface*
00280 ZcrossPath::sil_search(Bface *last, Bface * f)
00281 {
00282    return last;
00283 }
00284 
00285 Bface*
00286 ZcrossPath::sil_walk_search ( Bface *f, Bvert * vrt[3], double g[3] )
00287 {
00288 
00289    //this walks along the mesh finding the leading edge of the silhouette
00290 
00291    //previous entry must exist in the seglist
00292    //"starter" edge with a face equal to this one
00293 
00294    assert ( f == _segs.last().f() );
00295 
00296    f->zx_mark();
00297 
00298    Wvec dummy_vec;
00299 
00300    // we have arrived from the last face, which shares two vertices with this face
00301    // get the non-cached values and store in the third array index
00302 
00303    vrt[2] = f->other_vertex ( vrt[0], vrt[1] );
00304    g[2]   = (_eye - vrt[2]->loc()).normalized() * f->vert_normal(vrt[2], dummy_vec);
00305    if ( g[2] == 0 )
00306       g[2] = -1e-8;    // sinful but convenient
00307 
00308    // get last point
00309    Wpt last_pt = last();
00310 
00311    // find crossing edge
00312 
00313    int cross_vrt   = ( g[2] > 0 ) ? ((g[0] < 0)? 0:1) : ((g[0] > 0)? 0:1);
00314    double alph     = -g[2] / ( g[cross_vrt]-g[2] );
00315    // interpolate new point on edge
00316 
00317    Wpt new_pt = interp ( vrt[2]->loc(), vrt[cross_vrt]->loc(), alph );
00318 
00319    int gmax = ( g[0] > g[1] ) ? 0 : 1 ;
00320    gmax = ( g[2] > gmax ) ? 2  : gmax;
00321 
00322 
00323    Wvec v_iso ( last_pt - new_pt ) ;
00324    Wvec v_max = vrt[gmax]->loc() - new_pt;
00325    Wvec v_grad = v_max.orthogonalized(v_iso);
00326    bool bgrad = ( (_eye - new_pt) * v_grad > 0 );
00327 
00328    //this gradient is measured for this point and
00329    //the point before - so update the last point.
00330 
00331    _segs.last().setg(bgrad);
00332 
00333    //
00334 
00335    Bface * next_f = f->opposite_face(vrt[1-cross_vrt]);
00336    Wvec bc(0,0,0);
00337 
00338    if ( !next_f || f->shared_edge(next_f)->is_crease() ) {
00339       bc[f->vindex(vrt[2])-1]      = 1.0-alph;
00340       bc[f->vindex(vrt[cross_vrt])-1] = alph;
00341       add_seg (NULL  , new_pt, vrt[2], bgrad, f );
00342       next_f = NULL; //adding a proper null terminator
00343    } else {
00344       bc[next_f->vindex(vrt[2])-1]   = 1.0-alph;
00345       bc[next_f->vindex(vrt[cross_vrt])-1] = alph;
00346       add_seg (next_f, new_pt, vrt[2], bgrad, next_f); //adding bgrad here is bogus, but we correct
00347       //on the next seg
00348    }
00349 
00350    //update the state for the next iteration
00351    vrt[1-cross_vrt] = vrt[2];
00352    g[1-cross_vrt] = g[2];
00353    vrt[2] = NULL;
00354    g[2] = 0;
00355    return next_f;
00356 }
00357 
00358 
00359 Bface*
00360 ZcrossPath::sil_finish(Bface *last, Bface * f)
00361 {
00362    return f;
00363 }
00364 
00365 /* end of file zcross_list.C */

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