Cylinder.cc

Go to the documentation of this file.
00001 #include <esg/geometry/Cylinder.h>
00002 #include <esg/geometry/Sphere.h>
00003 
00004 using namespace esg;
00005 
00006 void Cylinder::_duplicate_attributes(const Geometry& src)
00007 {
00008     Geometry::_duplicate_attributes(src);
00009     _radius = ((Cylinder&)src)._radius;
00010     _radiusSqr = ((Cylinder&)src)._radiusSqr;
00011     _cap1Point.set(((Cylinder&)src)._cap1Point);
00012     _cap1Normal.set(((Cylinder&)src)._cap1Normal);
00013     _cap2Point.set(((Cylinder&)src)._cap2Point);
00014     _cap2Normal.set(((Cylinder&)src)._cap2Normal);
00015     _axis.set(((Cylinder&)src)._axis);
00016 }
00017 
00018 void Cylinder::_rotateX(float a)
00019 {
00020     Matrix3 trMat;
00021     trMat.rotX(a);
00022     trMat.transform(_cap1Point);
00023     trMat.transform(_cap1Normal);
00024     trMat.transform(_cap2Point);
00025     trMat.transform(_cap2Normal);
00026     trMat.transform(_axis);
00027 }
00028 
00029 void Cylinder::_rotateY(float a)
00030 {
00031     Matrix3 trMat;
00032     trMat.rotY(a);
00033     trMat.transform(_cap1Point);
00034     trMat.transform(_cap1Normal);
00035     trMat.transform(_cap2Point);
00036     trMat.transform(_cap2Normal);
00037     trMat.transform(_axis);
00038 }
00039 
00040 void Cylinder::_rotateZ(float a)
00041 {
00042     Matrix3 trMat;
00043     trMat.rotZ(a);
00044     trMat.transform(_cap1Point);
00045     trMat.transform(_cap1Normal);
00046     trMat.transform(_cap2Point);
00047     trMat.transform(_cap2Normal);
00048     trMat.transform(_axis);
00049 }
00050 
00051 void Cylinder::_rotate(float a, const Vector3& axis)
00052 {
00053     Matrix4 trMat;
00054     trMat.rotationGL(a, axis);
00055     trMat.transform(_cap1Point);
00056     trMat.transform(_cap1Normal);
00057     trMat.transform(_cap2Point);
00058     trMat.transform(_cap2Normal);
00059     trMat.transform(_axis);
00060 }
00061 
00062 void Cylinder::_rotate(const Matrix3& rMat)
00063 {
00064     rMat.transform(_cap1Point);
00065     rMat.transform(_cap1Normal);
00066     rMat.transform(_cap2Point);
00067     rMat.transform(_cap2Normal);
00068     rMat.transform(_axis);
00069 }
00070 
00071 void Cylinder::_translate(float x, float y, float z)
00072 {
00073     _cap1Point.add(Vector3(x, y, z));
00074     _cap2Point.add(Vector3(x, y, z));
00075 }
00076 
00077 void Cylinder::_transform(const Matrix4& trMat)
00078 {
00079     Matrix3 rMat;
00080     Vector3 tVec;
00081     double sc = trMat.get(rMat, tVec);
00082     trMat.transform(_cap1Point);
00083     trMat.transform(_cap2Point);
00084     rMat.transform(_cap1Normal);
00085     rMat.transform(_cap2Normal);
00086     _axis.set(_cap2Point);
00087     _axis.sub(_cap1Point);
00088     _axis.normalize();
00089     if (sc != 1.0) {
00090         _radius *= sc;
00091         _radiusSqr = _radius * _radius;
00092     }
00093 }
00094 
00095 void Cylinder::_scale(float s)
00096 {
00097     _cap1Point.scale(s);
00098     _cap2Point.scale(s);
00099     _radius *= s;
00100     _radiusSqr = _radius * _radius;
00101 }
00102 
00103 
00104 //----- public ------
00105 
00106 Cylinder::Cylinder()
00107     : _radius(1.0),
00108       _radiusSqr(1.0),
00109       _cap1Point(0.0, 0.0, 0.0),
00110       _cap1Normal(0.0, -1.0, 0.0),
00111       _cap2Point(0.0, 1.0, 0.0),
00112       _cap2Normal(0.0, 1.0, 0.0),
00113       _axis(0.0, 1.0, 0.0)
00114 {
00115 }
00116 
00117 Cylinder::Cylinder(const Vector3& point1,
00118                    const Vector3& normal1,
00119                    const Vector3& point2,
00120                    const Vector3& normal2,
00121                    double         radius)
00122     : _radius(radius),
00123       _radiusSqr(radius * radius),
00124       _cap1Point(point1),
00125       _cap1Normal(normal1),
00126       _cap2Point(point2),
00127       _cap2Normal(normal2)
00128 {
00129     _axis.set(_cap2Point);
00130     _axis.sub(_cap1Point);
00131     _axis.normalize();
00132 }
00133 
00134 void Cylinder::rayIntersection(PointEnv*      pPE,
00135                                int            mask,
00136                                const Vector3& origin,
00137                                const Vector3& direction,
00138                                float          maxD) 
00139 {
00140     pPE->mask = ENV_HAVE_NOTHING;
00141     
00142     /*
00143      * Algorithm reference:
00144      *    Heckbert P. S., Graphics Gems IV, Academic Press Professional,
00145      *    London, 1994, p. 356-365
00146      */
00147     
00148     static Vector3 RC, D, O, n;
00149     double  d, t, s;
00150     double  t_in =   MAXDOUBLE;
00151     double  t_out = -MAXDOUBLE;
00152 
00153     RC.set(origin);
00154     RC.sub(_cap1Point);
00155     n.cross(direction, _axis);
00156     double ln = n.length();
00157 
00158     // get intersection with cylinder
00159     if (ln == 0.0) { // ray is parallel to cylinder
00160         d = RC.dot(_axis);
00161         D.set(_axis);
00162         D.scaleAdd(-d, RC);
00163         d = D.length();
00164         if (d > _radius) return;
00165     } else {
00166         n.scale(1.0/ln); // normalize
00167         d = fabs(RC.dot(n)); // shortest distance
00168         if (d > _radius) return;
00169         O.cross(RC, _axis);
00170         t = -O.dot(n) / ln;
00171         O.cross(n, _axis);
00172         O.normalize();
00173         s = fabs(sqrt(_radiusSqr - d * d) / direction.dot(O));
00174         t_in  = t - s;
00175         t_out = t + s;
00176     }
00177 
00178     int surface = 0;
00179 
00180     // clip intersections by end-cap planes
00181     
00182     /*  Intersect the ray with the bottom end-cap plane.                */
00183     double dc = _cap1Normal.dot(direction);
00184     double dw = _cap1Normal.dot(origin) + _cap1Point.dot(_cap1Normal);
00185 
00186     if  (dc == 0.0) { // If parallel to bottom plane
00187         if (dw >= 0.0) return;
00188     } else {
00189         t  = -dw / dc;
00190         if (dc >= 0.0) {                            /* If far plane     */
00191             if (t < t_in) return;
00192             if (t > t_in && t < t_out) t_out = t;
00193         } else {                                    /* If near plane    */
00194             if (t > t_out) return;
00195             if (t > t_in && t < t_out) {
00196                 t_in = t;
00197                 surface = 1;
00198             }
00199         }
00200     }
00201 
00202     /* Intersect the ray with the top end-cap plane.                    */
00203     dc = _cap2Normal.dot(direction);
00204     dw = _cap2Normal.dot(origin) + _cap2Point.dot(_cap2Normal);
00205 
00206     if  (dc == 0.0) {           // If parallel to top plane
00207         if (dw >= 0.0) return;
00208     } else {
00209         t  = -dw / dc;
00210         if (dc >= 0.0) {                            /* If far plane     */
00211             if (t < t_in) return;
00212             if (t > t_in && t < t_out) t_out = t;
00213         } else {                                    /* If near plane    */
00214             if (t > t_out) return;
00215             if (t > t_in && t < t_out) {
00216                 t_in = t;
00217                 surface = 2;
00218             }
00219         }
00220     }
00221 
00222     if (t_in > t_out) return;
00223 
00224     if (mask & ENV_WANT_INTERSECTION) {
00225         pPE->intersection.set(direction);
00226         pPE->intersection.scaleAdd(t_in, origin);
00227         pPE->mask |= ENV_HAVE_INTERFERENCE | ENV_HAVE_INTERSECTION;
00228     } else
00229         pPE->mask |= ENV_HAVE_INTERFERENCE;
00230 
00231     if (mask & ENV_WANT_NORMAL) {
00232         switch (surface) {
00233             case 1: pPE->normal.set(_cap1Normal); break;
00234             case 2: pPE->normal.set(_cap2Normal); break;
00235             default:
00236                 {
00237                     double d1 = pPE->intersection.dot(_axis);
00238                     double d2 = _cap1Point.dot(_axis);
00239                     Vector3 v(_axis);
00240                     v.scale(d2 - d1);
00241                     v.add(_cap1Point);
00242                     pPE->normal.set(pPE->intersection);
00243                     pPE->normal.sub(v);
00244                     pPE->normal.normalize();
00245                 }
00246         }
00247         pPE->normalOrientation = PointEnv::OUTWARDS_NORMAL;
00248         pPE->mask |= ENV_HAVE_NORMAL;
00249     }
00250     
00251     if (mask & ENV_WANT_DISTANCE) {
00252         pPE->distance = t_in;
00253         pPE->mask |= ENV_HAVE_DISTANCE;
00254     }
00255 }
00256 
00257 bool Cylinder::mapToUV(const Vector3& v, Vector2& uv)
00258 {
00259     cerr << "Cylinder::mapToUV(): Not implemented" << endl;
00260     return false;
00261 }
00262 
00263 void Cylinder::randomSample(int mask, PointEnv& pe, double* pdf)
00264 {
00265     pe.mask = ENV_HAVE_NOTHING;
00266     cerr << "Cylinder::randomSample(): Not implemented" << endl;
00267 }
00268 
00269 Interval Cylinder::extent(const Vector3& direction) const
00270 {
00271     switch ((int) direction.dot(_axis)) {
00272         case 0: // perpendicular to axis
00273             {
00274                 double e = _cap1Point.dot(direction);
00275                 return Interval(e - _radius, e + _radius);
00276             }
00277         case 1:  // parellel to axis
00278         case -1:
00279             {
00280                 double e1 = _cap1Point.length();
00281                 double e2 = _cap2Point.length();
00282                 return ((e1 < e2)
00283                         ? Interval(e1, e2)
00284                         : Interval(e2, e1));
00285             }
00286         default:
00287             {
00288                 double e1 = _cap1Point.length();
00289                 double e2 = _cap2Point.length();
00290                 return ((e1 < e2)
00291                         ? Interval(e1 - _radius, e2 + _radius)
00292                         : Interval(e2 - _radius, e1 + _radius));
00293             }
00294     }
00295 }
00296 
00297 Vector3 Cylinder::centroid(void) const
00298 {
00299     Vector3 c(_cap1Point);
00300     c.add(_cap2Point);
00301     c.scale(0.5);
00302     return c;
00303 }
00304 
00305 double Cylinder::radius(const Vector3& centroid) const
00306 {
00307     Vector3 v(_cap1Point);
00308     v.sub(centroid);
00309     double r1 = v.length();
00310     v.set(_cap2Point);
00311     v.sub(centroid);
00312     double r2 = v.length();
00313     return ((r1 > r2) ? r1 + _radius : r2 + _radius);
00314 }
00315 
00316 double Cylinder::radius(void) const
00317 {
00318     Vector3 v(_cap1Point);
00319     v.sub(_cap2Point);
00320     double l = v.length()/2.0;
00321     return sqrt(l*l + _radiusSqr);
00322 }
00323 
00324 Geometry* Cylinder::clone(const Matrix4* pTrMat) const
00325 {
00326     Cylinder* pRet = new Cylinder();
00327     pRet->_duplicate_attributes(*this);
00328     if (pTrMat) pRet->_transform(*pTrMat);
00329     return pRet;
00330 }
00331 
00332 bool Cylinder::separation(Geometry& geom, Vector3*  pDir)
00333 {
00334     Interval myInt(_cap1Point.dot(_axis), _cap2Point.dot(_axis));
00335     Interval gInt(geom.extent(_axis));
00336 
00337     // separation by the end-cap planes
00338     if (myInt.min > myInt.max) {
00339         double a = myInt.min;
00340         myInt.min = myInt.max;
00341         myInt.max = a;
00342     }
00343     if (gInt.min > myInt.max || gInt.max < myInt.min) {
00344         if (pDir) pDir->set(_axis);
00345         return true;
00346     }
00347 
00348     // separation by the "pipe"
00349     Vector3 v(geom.centroid());
00350     v.sub(_cap1Point);
00351     v.normalize();
00352     Vector3 aux;
00353     aux.cross(_axis, v);
00354     aux.normalize();
00355     v.cross(aux, _axis);
00356     v.normalize();
00357     gInt = geom.extent(v);
00358     double d = _cap1Point.dot(v);
00359     if (gInt.min > d + _radius || gInt.max < d - _radius) {
00360         if (pDir) pDir->set(_axis);
00361         return true;
00362     }
00363 
00364     // no gap found
00365     return false;
00366 }
00367 
00368 double Cylinder::distance(const Geometry& geom, Vector3*  pDir)
00369 {
00370     Interval myInt(_cap1Point.dot(_axis), _cap2Point.dot(_axis));
00371     Interval gInt(geom.extent(_axis));
00372     double   d;
00373     double   ret = -MAXDOUBLE;
00374 
00375     // distance of the end-cap planes
00376     if (myInt.min > myInt.max) {
00377         double a = myInt.min;
00378         myInt.min = myInt.max;
00379         myInt.max = a;
00380     }
00381     d = gInt.min - myInt.max;
00382     if (d > ret) {
00383         ret = d;
00384         if (pDir) pDir->set(_axis);
00385     }
00386     d = myInt.min - gInt.max;
00387     if (d > ret) {
00388         ret = d;
00389         if (pDir) pDir->set(_axis);
00390     }
00391 
00392     // distance of the "pipe"
00393     Vector3 v(geom.centroid());
00394     v.sub(_cap1Point);
00395     v.normalize();
00396     Vector3 aux;
00397     aux.cross(_axis, v);
00398     aux.normalize();
00399     v.cross(aux, _axis);
00400     v.normalize();
00401     gInt = geom.extent(v);
00402     double md = _cap1Point.dot(v);
00403     
00404     d = gInt.min - (md + _radius);
00405     if (d > ret) {
00406         ret = d;
00407         if (pDir) pDir->set(v);
00408     }
00409     d = (md - _radius) - gInt.max;
00410     if (d > ret) {
00411         ret = d;
00412         if (pDir) pDir->set(v);
00413     }
00414 
00415 
00416     // distance of bounding spheres
00417     v.set(_cap1Point);
00418     v.sub(_cap2Point);
00419     double l = v.length()/2.0;
00420     Sphere bs(centroid(), radius());
00421     d = bs.distance(geom, &v);
00422     if (d > ret) {
00423         ret = d;
00424         if (pDir) pDir->set(v);
00425     }
00426 
00427     return ret;
00428 }
00429 
00430 void Cylinder::dump(const char* intent, const char* tab)
00431 {
00432 }

Generated on Wed Jun 28 12:24:29 2006 for esg by  doxygen 1.4.6