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

bbox.C

Go to the documentation of this file.
00001 #include "std/support.H"
00002 #include "disp/bbox.H"
00003 #include "disp/gel.H"
00004 #include "disp/ray.H"
00005 #include "disp/view.H"
00006 
00007 using namespace mlib;
00008 
00009 BBOX::BBOX(
00010    CGELptr &g, 
00011    int      recurse
00012    ) :_valid(true)
00013 {
00014    GELptr gel((GEL *)&*g); // sigh.. get_bb isn't const cuz it caches
00015    *this += BBOX(gel->bbox(recurse));
00016 }
00017 
00018 //
00019 // Return the corners of the bounding box in pts
00020 //
00021 bool
00022 BBOX::points(
00023    Wpt_list& pts
00024    ) const 
00025 {
00026    pts.clear();
00027    if (_valid) {
00028       pts.realloc(8);
00029       Wvec d = dim();
00030       Wvec dx(d[0],    0,    0);
00031       Wvec dy(   0, d[1],    0);
00032       Wvec dz(   0,    0, d[2]);
00033       pts += _min;
00034       pts += (_min + dx);
00035       pts += (_min + dy);
00036       pts += (_min + dz);
00037       pts += (_max - dx);
00038       pts += (_max - dy);
00039       pts += (_max - dz);
00040       pts += _max;
00041    }
00042    return _valid;
00043 }
00044 
00045 //
00046 // Does our bounding box intersect with a ray?
00047 //
00048 bool
00049 BBOX::intersects(
00050    CRAYhit   &r, 
00051    CWtransf  &m
00052    ) const
00053 {
00054    if (!_valid) {
00055       err_msg("BBOX::intersects: BBOX is not valid");
00056       return 0;
00057    }
00058 
00059    Wtransf m_inv = m.inverse();
00060    Wpt     p     = m_inv * r.point();
00061    Wvec    d     = m_inv * r.vec();
00062 
00063    // check yz-plane farthest from p in direction d:
00064    if (fabs(d[0]) > 1e-8) {
00065       double qx = (d[0]<0) ? _min[0] : _max[0];
00066       double t = (qx - p[0])/d[0];
00067       Wpt h = p + d*t;
00068       if (_min[1]<=h[1] && _max[1]>=h[1] && _min[2]<=h[2] && _max[2]>=h[2])
00069          return 1;
00070    }
00071    // check xz-plane farthest from p in direction d:
00072    if (fabs(d[1]) > 1e-8) {
00073       double qy = (d[1]<0) ? _min[1] : _max[1];
00074       double t = (qy - p[1])/d[1];
00075       Wpt h = p + d*t;
00076       if (_min[0]<=h[0] && _max[0]>=h[0] && _min[2]<=h[2] && _max[2]>=h[2])
00077          return 1;
00078    }
00079    // check xy-plane farthest from p in direction d:
00080    if (fabs(d[2]) > 1e-8) {
00081       double qz = (d[2]<0) ? _min[2] : _max[2];
00082       double t = (qz - p[2])/d[2];
00083       Wpt h = p + d*t;
00084       if (_min[0]<=h[0] && _max[0]>=h[0] && _min[1]<=h[1] && _max[1]>=h[1])
00085          return 1;
00086    }
00087    return 0;
00088 }
00089 
00090 /////////////////////////////////////////////////////////////////
00091 // BBOX::is_off_screen()
00092 //
00093 //    tests whether the bbox is clearly
00094 //    out of the view frustum
00095 //
00096 //    should be named BBOX::is_definitely_off_screen()
00097 //    because if it returns true, the bbox is definitely
00098 //    offscreen, but if it returns false the bbox may
00099 //    or may not be offscreen.
00100 //
00101 /////////////////////////////////////////////////////////////////
00102 bool      
00103 BBOX::is_off_screen()
00104 {
00105    // bounding box better be valid
00106    if (!valid())
00107       return 0;
00108 
00109    // return true if the bounding box is known to be offscreen.
00110    // to decide this, let A be the smallest cone containing 
00111    // the view  frustum whose tip is at the camera's eye 
00112    // point. let a be the angle of the cone -- i.e., between
00113    // its axis and a line along it.
00114    //
00115    // define a second cone B whose tip is at the camera's
00116    // eye point and that just contains the bounding box.
00117    // let b be the angle defining that cone.
00118    //
00119    // let c be the angle between the camera "at vector" and
00120    // the vector from the eye to the center of the bbox.
00121    //
00122    // then the bbox must be offscreen if:
00123    //
00124    //    a + b < c.
00125    //
00126    // rather than check that inequality directly,
00127    // we foolishly aim for greater efficiency by
00128    // testing the equivalent inequality:
00129    //
00130    //    cos(a + b) > cos(c)
00131    //
00132    // or
00133    //
00134    //    cos(a)cos(b) - sin(a)sin(b) > cos(c)
00135    //
00136    // taking
00137    //
00138    //   s = cos(a),
00139    //   t = cos(b), and
00140    //   u = cos(c),
00141    //
00142    // this becomes
00143    //
00144    //    s*t - sqrt((1 - s^2)(1 - t^2)) > u.
00145    //
00146    // the folowing code checks for this.
00147 
00148    // but first -- return false if eyepoint is
00149    // inside the bounding sphere of this bbox.
00150    // (need this to avoid taking the square root 
00151    //  of a negative number below).
00152    CCAMdataptr &camdata = VIEW::peek_cam_const()->data();
00153    CWpt&            eye = camdata->from();
00154    Wpt                o = center();
00155    Wvec               v = o - eye;
00156    double            R2 = dim().length_sqrd()/4;
00157    double            L2 = v.length_sqrd();
00158    if (L2 <= R2)
00159       return 0;
00160 
00161    // now, t = cos(b) = sqrt(R2/L2)
00162 
00163    // to compute s = cos(a), use:
00164    // s = d/sqrt(x^2 + y^2 + d^2):
00165    double      d = camdata->focal ();   // distance to film plane
00166    double      x = camdata->width ()/2; // semi-width of film plane
00167    double      y = camdata->height()/2; // semi-height of film plane
00168    double   x2y2 = sqr(x) + sqr(y);     // x^2 + y^2
00169    double x2y2d2 = x2y2 + sqr(d);       // x^2 + y^2 + d^2
00170    double   R2L2 = R2/L2;               // R2/L2
00171 
00172    // u = cos(c)
00173    double u = (camdata->at_v() * v)/sqrt(L2);
00174 
00175    // return true if s*t > u + sqrt((1 - s^2)(1 - t^2))
00176    return d*sqrt((1 - R2L2)/x2y2d2) > u + sqrt(R2L2*x2y2/x2y2d2);
00177 }
00178 
00179 BBOX &
00180 BBOX::operator*=(
00181    CWtransf &x
00182    ) 
00183 {
00184    if (!valid()) 
00185       return *this;
00186 
00187    Wpt_list pts(8);
00188    points(pts);     // Get corners of bounding box
00189    pts.xform(x);    // Multiply points by xform
00190 
00191    reset();         // Make box invalid
00192 
00193    update(pts);
00194    return *this;
00195 }
00196 
00197 //
00198 // Add a point to the bounding box
00199 //
00200 BBOX &
00201 BBOX::update(
00202    CWpt &p
00203    )
00204 {
00205    if (!_valid) {
00206       _min = p;
00207       _max = p;
00208       _valid = true;
00209    }
00210    else {
00211       for (int i=0;i<3;i++) {
00212          if (p[i] < _min[i]) _min[i] = p[i];
00213          if (p[i] > _max[i]) _max[i] = p[i];
00214       }
00215    }
00216 
00217    return *this;
00218 }
00219 
00220 BBOX &
00221 BBOX::update(
00222    CWpt_list &pts
00223    )
00224 {
00225    for (int j = 0; j < pts.num(); j++)
00226       update(pts[j]);
00227    return *this;
00228 }
00229 
00230 void
00231 BBOX::ndcz_bounding_box(
00232    CWtransf &obj_to_ndc, 
00233    NDCZpt& min_pt, 
00234    NDCZpt& max_pt
00235    ) const
00236 {
00237    Wpt_list point_list;
00238    points(point_list);
00239 
00240    // convert to ndcz points
00241    ARRAY<NDCZpt> ndcz_list;
00242    int         i;
00243    for (i = 0; i < point_list.num(); i++) {
00244       ndcz_list += NDCZpt(point_list[i], obj_to_ndc);
00245    }
00246 
00247    // init min and max to sentinel values
00248    int coord;
00249    for(coord = 0; coord < 3; coord++) {
00250       min_pt[coord] = 1e9;
00251       max_pt[coord] = -1e9;
00252    }
00253 
00254    // find min and max for each coordinate
00255    for (i = 0; i < ndcz_list.num(); i++) {
00256       for (coord = 0; coord < 3; coord++) {
00257          if (ndcz_list[i][coord] < min_pt[coord])
00258             min_pt[coord] = ndcz_list[i][coord];
00259          else if (ndcz_list[i][coord] > max_pt[coord])
00260             max_pt[coord] = ndcz_list[i][coord];
00261       }
00262    }
00263 }
00264 
00265 // 
00266 // BBOX2D Methods
00267 //
00268 
00269 BBOX2D::BBOX2D(
00270    CGELptr &g, 
00271    int      recurse
00272    ) : _valid(true)
00273 {
00274    GELptr gel((GEL *)&*g);// sigh.. get_bb isn't const cuz it caches
00275    Wpt_list pts;
00276    gel->bbox(recurse).points(pts);
00277    for (int i = 0; i < pts.num(); i++)
00278       update(pts[i]);
00279 }
00280 
00281 BBOX2D &
00282 BBOX2D::update(
00283    CXYpt &p
00284    )
00285 {
00286    if (!_valid) {
00287       _min = p;
00288       _max = p;
00289       _valid = true;
00290    }
00291    else {
00292       for (int i=0;i<2;i++) {
00293          if (p[i] < _min[i]) _min[i] = p[i];
00294          if (p[i] > _max[i]) _max[i] = p[i];
00295       }
00296    }
00297 
00298    return *this;
00299 }
00300 
00301 bool
00302 BBOX::contains(
00303    CWpt &p
00304    ) const 
00305 { 
00306    if (!_valid)
00307       return false;
00308    else
00309       return p[0] >= _min[0] && p[1] >= _min[1] && p[2] >= _min[2] &&
00310              p[0] <= _max[0] && p[1] <= _max[1] && p[2] <= _max[2];
00311 }
00312 
00313 bool
00314 BBOX::overlaps(
00315    CBBOX &bbox
00316    ) const 
00317 { 
00318    if (!_valid)
00319       return false;
00320    else
00321       return (bbox.min()[0] <= max()[0] && bbox.max()[0] >= min()[0] &&
00322               bbox.min()[1] <= max()[1] && bbox.max()[1] >= min()[1] &&
00323               bbox.min()[2] <= max()[2] && bbox.max()[2] >= min()[2]);
00324 }
00325 
00326 
00327 bool
00328 BBOX2D::overlaps(
00329    CBBOX2D &bbox
00330    ) const
00331 {
00332    if (!_valid)
00333       return false;
00334    else
00335       return (bbox.min()[0] <= max()[0] && bbox.max()[0] >= min()[0] &&
00336               bbox.min()[1] <= max()[1] && bbox.max()[1] >= min()[1]);
00337 }
00338 
00339 bool
00340 BBOX2D::contains(
00341    CXYpt &p
00342    ) const 
00343 { 
00344    if (!_valid)
00345       return false;
00346    else
00347       return p[0] >= _min[0] && p[1] >= _min[1] &&
00348              p[0] <= _max[0] && p[1] <= _max[1]; 
00349 }
00350 
00351 double
00352 BBOX2D::dist(
00353    CXYpt   &p
00354    ) const
00355 {
00356    if (!_valid)
00357       return -1;
00358    else {
00359       double dist = 1e9;
00360 
00361       if (contains(p)) {
00362          dist = 0;
00363       } else {
00364          // check distance to top, left, right, bottom edges
00365          //
00366          //      a -------------- b                          
00367          //      |                |                          
00368          //      |                |                          
00369          //      |                |                          
00370          //      |                |                          
00371          //      |                |                          
00372          //      c -------------- d                          
00373          //
00374          // get 4 corners: a, b, c, d
00375          // XXX - should add methods BBOX2D::height(), BBOX2D::width()
00376          // NOTE: for optimized compiles to work, 
00377          //       avoid calling dim()[0] or dim()[1]:
00378          double h = dim()*XYvec(0,1); // height
00379          double w = dim()*XYvec(1,0); // width
00380 
00381          XYpt a = _min + XYvec(0, h);
00382          XYpt b = _max;
00383          XYpt c = _min;
00384          XYpt d = _min + XYvec(w,0);
00385          // XXX - need method in mlib/line.H: Line::dist_to_seg(const P&)
00386          dist = ::min(dist, XYline(a,b).project_to_seg(p).dist(p));
00387          dist = ::min(dist, XYline(a,c).project_to_seg(p).dist(p));
00388          dist = ::min(dist, XYline(c,d).project_to_seg(p).dist(p));
00389          dist = ::min(dist, XYline(b,d).project_to_seg(p).dist(p));
00390       }
00391 
00392       return dist;
00393    }
00394 }
00395 
00396 BBOX2D &
00397 BBOX2D::operator+=(CXYpt_list &pts)
00398 {
00399    for (int i = 0; i < pts.num(); i++)
00400       (void) update(pts[i]);
00401    return *this;
00402 }
00403 
00404 
00405 
00406 
00407 
00408 // 
00409 // BBOXpix Methods
00410 //
00411 
00412 BBOXpix &
00413 BBOXpix::update(CPIXEL &p) {
00414   if (!_valid) {
00415     _min = p;
00416     _max = p;
00417     _valid = true;
00418   } else {
00419     for (int i=0;i<2;i++) {
00420       if (p[i] < _min[i]) _min[i] = p[i];
00421       if (p[i] > _max[i]) _max[i] = p[i];
00422     }
00423   }
00424 
00425   return *this;
00426 }
00427 
00428 bool
00429 BBOXpix::contains(CPIXEL &p) const { 
00430   if (!_valid) {
00431     return false;
00432   } else {
00433     return (p[0] >= _min[0] && p[1] >= _min[1] &&
00434        p[0] <= _max[0] && p[1] <= _max[1]);
00435   }
00436 }
00437 
00438 bool
00439 BBOXpix::overlaps(CBBOXpix &bbox) const { 
00440   if (!_valid){
00441     return false;
00442   } else {
00443     return (bbox.min()[0] <= max()[0] && bbox.max()[0] >= min()[0] &&
00444        bbox.min()[1] <= max()[1] && bbox.max()[1] >= min()[1]);
00445   }
00446 }
00447 
00448 double
00449 BBOXpix::dist(CPIXEL   &p) const {
00450   if (!_valid) return -1;
00451 
00452 
00453   double dist = 1e9;
00454   
00455   if (contains(p)) {
00456     dist = 0.0;
00457   } else {
00458     // check distance to top, left, right, bottom edges
00459     //
00460     //      a -------------- b                          
00461     //      |                |                          
00462     //      |                |                          
00463     //      |                |                          
00464     //      |                |                          
00465     //      |                |                          
00466     //      c -------------- d                          
00467     //
00468     // get 4 corners: a, b, c, d
00469     // XXX - should add methods BBOX2D::height(), BBOX2D::width()
00470     // NOTE: for optimized compiles to work, 
00471     //       avoid calling dim()[0] or dim()[1]:
00472     double h = height(); // height
00473     double w = width(); // width
00474     
00475     PIXEL a = _min + VEXEL(0, h);
00476     PIXEL b = _max;
00477     PIXEL c = _min;
00478     PIXEL d = _min + VEXEL(w,0);
00479     // XXX - need method in mlib/line.H: Line::dist_to_seg(const P&)
00480     dist = ::min(dist, PIXELline(a,b).project_to_seg(p).dist(p));
00481     dist = ::min(dist, PIXELline(a,c).project_to_seg(p).dist(p));
00482     dist = ::min(dist, PIXELline(c,d).project_to_seg(p).dist(p));
00483     dist = ::min(dist, PIXELline(b,d).project_to_seg(p).dist(p));
00484   }
00485   
00486   return dist;
00487 }
00488 
00489 
00490 BBOXpix &
00491 BBOXpix::operator+=(CPIXEL_list &pts) {
00492   for (int i = 0; i < pts.num(); i++)
00493     (void) update(pts[i]);
00494   return *this;
00495 }
00496 

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