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
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
00144
00145
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
00159 if (ln == 0.0) {
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);
00167 d = fabs(RC.dot(n));
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
00181
00182
00183 double dc = _cap1Normal.dot(direction);
00184 double dw = _cap1Normal.dot(origin) + _cap1Point.dot(_cap1Normal);
00185
00186 if (dc == 0.0) {
00187 if (dw >= 0.0) return;
00188 } else {
00189 t = -dw / dc;
00190 if (dc >= 0.0) {
00191 if (t < t_in) return;
00192 if (t > t_in && t < t_out) t_out = t;
00193 } else {
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
00203 dc = _cap2Normal.dot(direction);
00204 dw = _cap2Normal.dot(origin) + _cap2Point.dot(_cap2Normal);
00205
00206 if (dc == 0.0) {
00207 if (dw >= 0.0) return;
00208 } else {
00209 t = -dw / dc;
00210 if (dc >= 0.0) {
00211 if (t < t_in) return;
00212 if (t > t_in && t < t_out) t_out = t;
00213 } else {
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:
00273 {
00274 double e = _cap1Point.dot(direction);
00275 return Interval(e - _radius, e + _radius);
00276 }
00277 case 1:
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
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
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
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
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
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
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 }