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

points.C

Go to the documentation of this file.
00001 /*!
00002  *  \file points.C
00003  *  \brief Contains the definitions of various static constants for the
00004  *  coordinate system classes.  Also contains the implementation of various
00005  *  non-inlined functions for these classes.
00006  *
00007  */
00008 
00009 #include "mlib/points.H"
00010 
00011 using namespace mlib;
00012 
00013 CWtransf mlib::Identity;
00014 
00015 CWvec mlib::Wvec::_null_vec(0,0,0);
00016 CWvec mlib::Wvec::_x_axis(1,0,0);
00017 CWvec mlib::Wvec::_y_axis(0,1,0);
00018 CWvec mlib::Wvec::_z_axis(0,0,1);
00019 
00020 CWpt  mlib::Wpt::_origin;
00021 
00022 CXYvec mlib::XYvec::_null_vec(0,0);
00023 CXYvec mlib::XYvec::_x_axis(1,0);
00024 CXYvec mlib::XYvec::_y_axis(0,1);
00025 
00026 CXYpt mlib::XYpt::_origin;
00027 
00028 CNDCZvec mlib::NDCZvec::_null_vec(0,0,0);
00029 CNDCZvec mlib::NDCZvec::_x_axis(1,0,0);
00030 CNDCZvec mlib::NDCZvec::_y_axis(0,1,0);
00031 CNDCZvec mlib::NDCZvec::_z_axis(0,0,1);
00032 
00033 CNDCZpt mlib::NDCZpt::_origin;
00034 
00035 CNDCvec mlib::NDCvec::_null_vec(0,0);
00036 CNDCvec mlib::NDCvec::_x_axis(1,0);
00037 CNDCvec mlib::NDCvec::_y_axis(0,1);
00038 
00039 CNDCpt mlib::NDCpt::_origin;
00040 
00041 CVEXEL mlib::VEXEL::_null_vec(0,0);
00042 CVEXEL mlib::VEXEL::_x_axis(1,0);
00043 CVEXEL mlib::VEXEL::_y_axis(0,1);
00044 
00045 CPIXEL mlib::PIXEL::_origin;
00046 
00047 CUVvec mlib::UVvec::_null_vec(0,0);
00048 CUVvec mlib::UVvec::_u_dir(1,0);
00049 CUVvec mlib::UVvec::_v_dir(0,1);
00050 
00051 CUVpt mlib::UVpt::_origin;
00052 
00053 // -------- inlined conversion between coordinates ------ 
00054 
00055 /* World */
00056 
00057 mlib::Wpt::Wpt(
00058    CXYpt &x, 
00059    CWpt  &pt
00060    ) 
00061 {
00062    *this = XYtoW_1(x, pt);
00063 }
00064 
00065 mlib::Wpt::Wpt(
00066    CXYpt  &x,
00067    double  d
00068    )
00069 {
00070    *this = XYtoW_2(x, d);
00071 }
00072 
00073 mlib::Wpt::Wpt(CNDCZpt &p)
00074 { 
00075    Wpt ndc;
00076    ndc[0] = p[0];
00077    ndc[1] = p[1];
00078    ndc[2] = p[2];
00079 
00080    *this = VIEW_NDC_TRANS().inverse() * ndc;
00081 }
00082 
00083 mlib::Wpt::Wpt(CXYpt &x)
00084 {
00085    *this = XYtoW_3(x);
00086 }
00087 
00088 mlib::Wvec::Wvec(CNDCZvec& v, CWtransf& obj_to_ndc_der_inv)
00089 {
00090    // converts an ndcz vector to 
00091    // wvec using the supplied matrix
00092    // obj_to_ndc_der_inv = obj_to_ndc.derivative().inverse, where
00093    // obj_to_ndc is the object to ndcz space transform
00094 
00095    Wvec temp(v[0],v[1],v[2]); 
00096    *this = obj_to_ndc_der_inv * temp;
00097 
00098 }
00099 
00100 mlib::Wvec::Wvec(CXYpt &x)
00101 {
00102    *this = XYtoWvec(x);
00103 }
00104 
00105 bool 
00106 mlib::Wpt::in_frustum() const
00107 {
00108    return NDCZpt(*this).in_frustum();
00109 }
00110 
00111 mlib::Wvec::Wvec(CWpt &p, CVEXEL &v)
00112 {
00113    Wpt  p2(PIXEL(p)+v, p);
00114    *this = p2 - p;
00115 }
00116 
00117 /* XY */
00118 
00119 mlib::XYpt::XYpt(CWpt &w) 
00120 {
00121    *this = WtoXY(w);
00122 }
00123 
00124 mlib::XYpt::XYpt(CNDCpt &n) 
00125 {
00126    double aspect = VIEW_ASPECT();
00127    if (aspect > 1) {
00128       _x =   n[0] / aspect;
00129       _y =   n[1];
00130    } else {
00131       _x =   n[0];
00132       _y =   n[1] * aspect;
00133    }
00134 }
00135 
00136 mlib::XYvec::XYvec(CNDCvec &n) 
00137 {
00138    double aspect = VIEW_ASPECT();
00139    if (aspect > 1) {
00140       _x =   n[0] / aspect;
00141       _y =   n[1];
00142    } else {
00143       _x =   n[0];
00144       _y =   n[1] * aspect;
00145    }
00146 }
00147 
00148 mlib::XYpt::XYpt(CPIXEL &p) 
00149 {
00150    NDCpt  corner;
00151    int    w, h; VIEW_SIZE  (w, h);
00152    double zoom; VIEW_PIXELS(zoom, corner);
00153    XYpt   botleft(corner);
00154 
00155    _x = 2 * (p[0]/w -1); // first map pixel to 
00156    _y = 2 * (p[1]/h -1); // (-1,1) range;
00157    // next we scale pt to the current film plane zoom range
00158    // and offset it by the current film plane offset.
00159    // (NOTE: we assume that the default camera displays 
00160    //        2.0 coordinate units ranging from -1,1.
00161    //        Thus, the zoom factor is 2.0/max(hei,wid).)
00162    _x = (1/zoom) *_x - botleft[0];
00163    _y = (1/zoom) *_y - botleft[1];
00164 }
00165 
00166 mlib::XYvec::XYvec(CVEXEL &v) 
00167 {
00168    int w, h;
00169    VIEW_SIZE(w, h);
00170    _x = 2*v[0]/w;
00171    _y = 2*v[1]/h;
00172 }
00173 
00174 /* NDC */
00175 
00176 bool
00177 mlib::NDCZpt::in_frustum() const
00178 {
00179    // z-coord has to be in [0,1]:
00180    // XXX - Actually, not sure if this accounts for the
00181    //       clipping planes.
00182   if (!in_interval(_z, 0.0, 1.0)) { 
00183     return 0;
00184   }
00185   
00186   // double a = VIEW_ASPECT(); // swine!
00187 
00188   int w,h; VIEW_SIZE(w,h);
00189   double a = (double)h/(double)w;
00190    if (a > 1) {
00191       // Tall window
00192       return  (in_interval(_y, -a, a) && in_interval(_x, -1.0, 1.0));
00193    } else {
00194       // Wide window
00195       assert(a > 1e-6);
00196       a = 1/a;
00197       return (in_interval(_x, -a, a) && in_interval(_y, -1.0, 1.0));
00198       
00199    }
00200 }
00201 
00202 
00203 mlib::NDCpt::NDCpt(CXYpt &x) 
00204 {
00205    double aspect = VIEW_ASPECT();
00206    if (aspect > 1) {
00207       _x =   x[0] * aspect;
00208       _y =   x[1];
00209    } else {
00210       assert(aspect > 1e-6);
00211       _x =   x[0];
00212       _y =   x[1] / aspect;
00213    }
00214 }
00215 
00216 mlib::NDCvec::NDCvec(CXYvec &x) 
00217 {
00218    double aspect = VIEW_ASPECT();
00219    if (aspect > 1) {
00220       _x =   x[0] * aspect;
00221       _y =   x[1];
00222    } else {
00223       _x =   x[0];
00224       _y =   x[1] / aspect;
00225    }
00226 }
00227 
00228 mlib::NDCpt::NDCpt(CWpt &w) 
00229 {
00230    *this = NDCZpt(w);
00231 }
00232 
00233 mlib::NDCvec::NDCvec(CVEXEL &v) 
00234 {
00235    int w, h;
00236    VIEW_SIZE(w, h);
00237 
00238    double aspect = VIEW_ASPECT();
00239    if (aspect > 1) {
00240       _x = 2*v[0]*aspect/w;
00241       _y = 2*v[1]/h;
00242    } else {
00243       _x = 2*v[0]/w;
00244       _y = 2*v[1]/(aspect*h);
00245    }
00246 }
00247 
00248 /* NDCZ */
00249 
00250 mlib::NDCZpt::NDCZpt(CWpt &p)
00251 {
00252    Wpt ndc = VIEW_NDC_TRANS() * p;
00253 
00254    _x = ndc[0];
00255    _y = ndc[1];
00256    _z = ndc[2];
00257 }
00258 
00259 mlib::NDCZpt::NDCZpt(CWpt& o, CWtransf& PM)
00260 {
00261    // converts an object space point to 
00262    // NDCZ using the supplied matrix
00263    // PM = P * M, where
00264    //
00265    //   P is the camera NDC projection matrix,
00266    //   M is the object to world transform.
00267 
00268    Wpt ndc = PM * o;
00269 
00270    _x = ndc[0];
00271    _y = ndc[1];
00272    _z = ndc[2];
00273 }
00274 
00275 mlib::NDCZpt::NDCZpt(CXYpt &x) 
00276 {
00277    _z = 0;
00278    double aspect = VIEW_ASPECT();
00279    if (aspect > 1) {
00280       _x = x[0]*aspect;
00281       _y = x[1];
00282    } else {
00283       _x = x[0];
00284       _y = x[1]/aspect;
00285    }
00286 }
00287 
00288 mlib::NDCZpt::NDCZpt(CNDCpt &p)
00289 {
00290   _x = p[0];
00291   _y = p[1];
00292   _z = 0;
00293 }
00294 
00295 mlib::NDCZpt::NDCZpt(CPIXEL &p) 
00296 {
00297    int w, h;
00298    _z = 0;
00299    VIEW_SIZE(w, h);
00300    double aspect = VIEW_ASPECT();
00301    if (aspect > 1 ) {
00302       _x = (2*p[0]/w - 1) * aspect;
00303       _y = (2*p[1]/h - 1);
00304    } else {
00305       _x = (2*p[0]/w - 1);
00306       _y = (2*p[1]/h - 1) / aspect;
00307    }
00308 }
00309 
00310 mlib::NDCZvec::NDCZvec(CNDCvec &v)
00311 {
00312   _x = v[0];
00313   _y = v[1];
00314   _z = 0;
00315 }
00316 
00317 mlib::NDCZvec::NDCZvec(CXYvec &x) 
00318 {
00319    _z = 0;
00320    double aspect = VIEW_ASPECT();
00321    if (aspect > 1) {
00322       _x = x[0]*aspect;
00323       _y = x[1];
00324    } else {
00325       _x = x[0];
00326       _y = x[1]/aspect;
00327    }
00328 }
00329 
00330 mlib::NDCZvec::NDCZvec(CVEXEL &v) 
00331 {
00332    int w, h;
00333    _z = 0;
00334    VIEW_SIZE(w, h);
00335    double aspect = VIEW_ASPECT();
00336    if (aspect > 1) {
00337       _x = 2*v[0]*aspect/w;
00338       _y = 2*v[1]/h;
00339    } else {
00340       _x = 2*v[0]/w;
00341       _y = 2*v[1]/(aspect*h);
00342    }
00343 }
00344 
00345 mlib::NDCZvec::NDCZvec(CWvec&v, CWtransf& obj_to_ndc_der)
00346 {
00347    // converts an object space vector to 
00348    // NDCZ using the supplied matrix
00349    // obj_to_ndc_der = obj_to_ndc.derivative(), where
00350    // obj_to_ndc is the object to ndcz space transform
00351 
00352    Wvec temp = obj_to_ndc_der * v;
00353    _x = temp[0]; _y = temp[1]; _z = temp[2];
00354 }
00355 
00356 NDCZvec
00357 mlib::normal_to_ndcz(CWpt& p, CWvec& world_normal)
00358 {
00359    Wvec temp = VIEW_NDC_TRANS().derivative(p) * world_normal;
00360    return NDCZvec(temp[0], temp[1], temp[2]);
00361 }
00362 
00363 /* NDCZpt_list */
00364 
00365 NDCZvec
00366 mlib::NDCZpt_list::tan(int i) const 
00367 {
00368    NDCZpt *ar = _array;
00369    const int n=num()-1;
00370    if (i<0 || i>n || n<1) return NDCZvec();
00371    if (i==0) return (ar[1]-ar[  0]).normalized();
00372    if (i==n) return (ar[n]-ar[n-1]).normalized();
00373    return ((ar[i+1]-ar[i]).normalized() + (ar[i]-ar[i-1]).normalized()).normalized();
00374 }
00375 
00376 
00377 NDCZpt       
00378 mlib::NDCZpt_list::interpolate(double s, NDCZvec *tan, int*segp, double*tp) const
00379 {
00380    int seg;
00381    double t;
00382    interpolate_length(s, seg, t);
00383    const NDCZvec v = _array[seg+1]-_array[seg];
00384    if (tan)  *tan  = v.normalized();
00385    if (segp) *segp = seg;
00386    if (tp)   *tp   = t;
00387 
00388    return _array[seg]+v*t;
00389 }
00390 
00391 void         
00392 mlib::NDCZpt_list::interpolate_length(double s, int &seg, double &t) const
00393 {
00394    // Assume update_length() has been called.  Note if
00395    // there are 0 or 1 points, _length will be 0, we
00396    // return early.  Note also, generally returns 0<=t<1,
00397    // except at the extreme right, returns t=1;
00398 
00399    // It turns out that when we ASSUME we make an ass of
00400    // everybody.  Not updating the partial length array
00401    // remains a common mistake... so we check for it
00402    // here. This check will not catch all cases where the
00403    // partial length array is out of date, but it will catch
00404    // many of them
00405    if (_partial_length.num() != _num) {
00406       cerr << "NDCZpt_list::interpolate_length: "
00407            << "Warning: partial lengths are out of date."
00408            << endl;
00409       // You know you're bad when you cast away the const:
00410       ((NDCZpt_list*)this)->update_length();
00411    }
00412 
00413    const double val = s*length();
00414    if (val <= 0) { 
00415       seg = 0; 
00416       t   = 0; 
00417       return; 
00418    }
00419    if (val >= length()) { 
00420       seg = _num-2; 
00421       t = 1; 
00422       return; 
00423    }
00424 
00425    int l=0, r=_num-1, m;
00426    while ((m = (l+r) >> 1) != l) {
00427       if (val < _partial_length[m])       
00428          r = m;
00429       else l = m;
00430    }
00431    seg = m;
00432    t = (val-_partial_length[m])/(_partial_length[m+1]-_partial_length[m]);
00433 }
00434 
00435 NDCpt_list& 
00436 mlib::NDCpt_list::operator=(CPIXEL_list& P) 
00437 {
00438    clear();
00439    for (int i=0; i<P.num(); i++)
00440       add(NDCpt(P[i]));
00441    update_length();
00442    return *this;
00443 }
00444 
00445 NDCpt_list& 
00446 mlib::NDCpt_list::operator=(CXYpt_list& X) 
00447 {
00448    clear();
00449    for (int i=0; i<X.num(); i++)
00450       add(NDCpt(X[i]));
00451    update_length();
00452    return *this;
00453 }
00454 
00455 NDCpt_list& 
00456 mlib::NDCpt_list::operator=(CNDCZpt_list& N) 
00457 {
00458    clear();
00459    for (int i=0; i<N.num(); i++)
00460       add(NDCpt(N[i]));
00461    update_length();
00462    return *this;
00463 }
00464 
00465 /* Pixel */
00466 mlib::VEXEL::VEXEL(CNDCvec &n) 
00467 {
00468    int w, h;
00469    VIEW_SIZE(w, h);
00470    double aspect = VIEW_ASPECT();
00471    if (aspect > 1) {
00472       _x = n[0]/(aspect/w)/2;
00473       _y = n[1]*h/2;
00474    } else {
00475       _x = n[0]*w/2;
00476       _y = n[1]*(aspect*h)/2;
00477    }
00478 }
00479 
00480 
00481 mlib::VEXEL::VEXEL(CWpt &wp, CWvec &wv) 
00482 {
00483    PIXEL p1(wp), p2(wp + wv);
00484    *this = p2 - p1;
00485 }
00486 
00487 mlib::PIXEL::PIXEL(CXYpt &x) 
00488 {
00489    NDCpt  corner;
00490    int    w,h;  VIEW_SIZE  (w, h);
00491    double zoom; VIEW_PIXELS(zoom, corner);
00492    XYpt   botleft(corner);
00493 
00494    // First map XY coordinate to (-w/2,-h/2) -> (w/2,h/2)
00495    _x = w/2*(x[0] + botleft[0]);
00496    _y = h/2*(x[1] + botleft[1]);
00497 
00498    // then scale by zoom factor and offset to be 0->(w,h)
00499    _x = _x*zoom + w;
00500    _y = _y*zoom + h;
00501 }
00502 
00503 
00504 mlib::VEXEL::VEXEL(CXYvec &x) 
00505 {
00506    int w, h; VIEW_SIZE(w, h);
00507 
00508    _x = x[0]*w/2.;
00509    _y = x[1]*h/2.;
00510 }
00511 
00512 PIXEL_list&
00513 mlib::PIXEL_list::operator=(CWpt_list& X) 
00514 {
00515    clear();
00516    for (int i=0; i<X.num(); i++)
00517       add(PIXEL(X[i]));
00518    update_length();
00519    return *this;
00520 }
00521 
00522 PIXEL_list&
00523 mlib::PIXEL_list::operator=(CXYpt_list& X) 
00524 {
00525    clear();
00526    for (int i=0; i<X.num(); i++)
00527       add(PIXEL(X[i]));
00528    update_length();
00529    return *this;
00530 }
00531 
00532 PIXEL_list&
00533 mlib::PIXEL_list::operator=(CNDCpt_list& N) 
00534 {
00535    clear();
00536    for (int i=0; i<N.num(); i++)
00537       add(PIXEL(N[i]));
00538    update_length();
00539    return *this;
00540 }
00541 
00542 PIXEL_list&
00543 mlib::PIXEL_list::operator=(CNDCZpt_list& N) 
00544 {
00545    clear();
00546    for (int i=0; i<N.num(); i++)
00547       add(PIXEL(N[i]));
00548    update_length();
00549    return *this;
00550 }
00551 
00552 bool 
00553 mlib::Wpt_list::project(XYpt_list& ret) const
00554 {
00555    // Project to an XYpt_list, provided all points lie in the
00556    // view frustum. Assumes Wpts are not in "object space."
00557 
00558    // Clear it
00559    ret.clear();
00560 
00561    // If there are no points,
00562    // there's no point in continuing...
00563    if (empty())
00564       return 1; // "success"
00565 
00566    // Resize the output list now (Note: _num != 0):
00567    ret.realloc(_num);
00568 
00569    // Fill it up w/ projected points, 
00570    // ensuring all points lie in the frustum:
00571    for (int k=0; k<_num; k++) {
00572       NDCZpt ndcz = NDCZpt(_array[k]);
00573       if (!ndcz.in_frustum()) {
00574          ret.clear();
00575          return 0;      // failure
00576       }
00577       ret.add(NDCpt(ndcz));
00578    }
00579    return 1;    // success
00580 }
00581 
00582 bool 
00583 mlib::Wpt_list::project(PIXEL_list& ret) const
00584 {
00585    // Project to a PIXEL_list, provided all points lie in the
00586    // view frustum. Assumes Wpts are not in "object space."
00587 
00588    XYpt_list xy_list;
00589    if (!project(xy_list))
00590       return 0;
00591    ret = xy_list;
00592    return 1;
00593 }
00594 
00595 int
00596 mlib::Wpt_list::closest_vertex(CPIXEL& p) const
00597 {
00598    // Returns index of the *vertex* of the polyline
00599    // that is closest to the given screen-space point
00600    // (distance measured in PIXELs). Skips vertices
00601    // that lie outside the view frustum. Returns -1 if
00602    // no vertices lie in the frustum.
00603 
00604    int ret = -1; // return value: index of closest vertex
00605    double min_d=0;
00606    for (int i=0; i<_num; i++) {
00607       // skip points not in the view frustum
00608       if (_array[i].in_frustum()) {
00609          double d = PIXEL(_array[i]).dist(p);
00610          if (ret < 0 || d < min_d) {
00611             min_d = d;
00612             ret = i;
00613          }
00614       }
00615    }
00616    return ret;
00617 }
00618 
00619 bool 
00620 mlib::Wpt_list::get_best_fit_plane(Wplane& P) const
00621 {
00622    // Return the best-fit plane.
00623    // 
00624    //    Newell's algorithm,
00625    //    from Graphics Gems III,
00626    //    Vol. 5, pp 231-232
00627 
00628    // If less than 3 points let the caller deal with it:
00629    if (_num < 3)
00630       return 0;
00631 
00632    // Find vector N, normal of "best-fit" plane
00633    Wvec N;
00634    for (int k=0; k<_num; k++) {
00635       Wpt i = _array[k];
00636       Wpt j = _array[(k+1)%_num];
00637       N += Wvec(
00638          (i[1] - j[1])*(i[2] + j[2]),
00639          (i[2] - j[2])*(i[0] + j[0]),
00640          (i[0] - j[0])*(i[1] + j[1])
00641          );
00642    }
00643    N = N.normalized();
00644 
00645    // If it's not working out let the caller deal w/ it:
00646    if (N.is_null())
00647       return 0;
00648 
00649    // The best-fit plane:
00650    P = Wplane(average(), N);
00651 
00652    return 1;
00653 }
00654 
00655 
00656 bool
00657 mlib::Wpt_list::get_plane(Wplane &P, double len_scale) const
00658 {
00659    // Return the best-fit plane if the fit is good.
00660    // Parameter 'len_scale' is multiplied by the length
00661    // of the polyline to yield a threshold. The fit is
00662    // considered good if every point lies within the
00663    // threshold distance from the plane.
00664 
00665    P = Wplane(); // clear it
00666 
00667    // Try to compute the best-fit plane
00668    Wplane ret;
00669    if (!get_best_fit_plane(ret))
00670       return 0;
00671 
00672    // We now return 'true' if the points lie close to the plane.
00673    //
00674    // "Close" is defined relative to the length of the
00675    // polyline. We need the partial lengths to be updated.
00676    if (_num != _partial_length.num()) {
00677       cerr << "Wpt_list::get_plane: Error: lengths are not updated" << endl;
00678       return 0;
00679    }
00680    double thresh = length()*len_scale;
00681    for (int k=0; k<_num; k++)
00682       if (ret.dist(_array[k]) > thresh)
00683          return 0;
00684 
00685    // It's good. Now record the plane:
00686    P = ret;
00687 
00688    return 1;
00689 }
00690 
00691 /* end of file points.C */

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