00001 #include <esg/geometry/Sphere.h>
00002 #include <esg/mesh/SphereMesh.h>
00003 #include <esg/explorer/POGExplorer.h>
00004 #include <esg/explorer/RadiusExplorer.h>
00005
00006 using namespace esg;
00007
00008 Mesh* Sphere::_mesh(int density) const
00009 {
00010 Mesh* pMesh = (SphereMesh*) new SphereMesh(density);
00011 if (!pMesh) return NULL;
00012 if (_radius != 1.0)
00013 pMesh->scale(_radius, _radius, _radius);
00014 if (_centre.x || _centre.y || _centre.z)
00015 pMesh->translate(_centre);
00016 return pMesh;
00017 }
00018
00019 void Sphere::_duplicate_attributes(const Geometry& src)
00020 {
00021 _radius = ((Sphere&)src)._radius;
00022 _radius2 = _radius * _radius;
00023 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00024 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00025 _centre.set(((Sphere&)src)._centre);
00026 }
00027
00028 void Sphere::_rotateX(float a)
00029 {
00030 Matrix3 trMat;
00031 trMat.rotX(a);
00032 trMat.transform(_centre);
00033 }
00034
00035 void Sphere::_rotateY(float a)
00036 {
00037 Matrix3 trMat;
00038 trMat.rotY(a);
00039 trMat.transform(_centre);
00040 }
00041
00042 void Sphere::_rotateZ(float a)
00043 {
00044 Matrix3 trMat;
00045 trMat.rotZ(a);
00046 trMat.transform(_centre);
00047 }
00048
00049 void Sphere::_rotate(float a, const Vector3& axis)
00050 {
00051 Matrix4 trMat;
00052 trMat.rotationGL(a, axis);
00053 trMat.transform(_centre);
00054 }
00055
00056 void Sphere::_rotate(const Matrix3& rotMat)
00057 {
00058 rotMat.transform(_centre);
00059 }
00060
00061 void Sphere::_translate(float x, float y, float z)
00062 {
00063 _centre.add(Vector3(x, y, z));
00064 }
00065
00066 void Sphere::_transform(const Matrix4& trMat)
00067 {
00068 trMat.transform(_centre);
00069 }
00070
00071 void Sphere::_scale(float s)
00072 {
00073 _centre.scale(s);
00074 _radius *= s;
00075 _radius2 = _radius * _radius;
00076 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00077 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00078 }
00079
00080
00081
00082
00083 Sphere::Sphere()
00084 {
00085 _radius = 1.;
00086 _radius2 = 1.;
00087 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00088 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00089 _centre.set(0., 0., 0.);
00090 }
00091
00092 Sphere::Sphere(const Vector3& c, float r)
00093 {
00094 _radius = r;
00095 _radius2 = r * r;
00096 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00097 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00098 _centre.set(c);
00099 }
00100
00101
00102 Sphere::Sphere(float x, float y, float z, float r)
00103 {
00104 _radius = r;
00105 _radius2 = r * r;
00106 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00107 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00108 _centre.set(x,y,z);
00109 }
00110
00111 Sphere::Sphere(const Geometry& g)
00112 {
00113 _centre.set(g.centroid());
00114 _radius = g.radius(_centre);
00115 _radius2 = _radius * _radius;
00116 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00117 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00118 }
00119
00120 Sphere::Sphere(const Geometry& g1, const Geometry& g2)
00121 {
00122 Vector3 c1(g1.centroid());
00123 Vector3 c2(g2.centroid());
00124 Vector3 v(c2 - c1);
00125 double r1 = g1.radius(c1);
00126 double r2 = g2.radius(c2);
00127 double d = v.length();
00128
00129 if ((d + r2) <= r1) {
00130 _centre.set(c1);
00131 _radius = r1;
00132 _radius2 = r1 * r1;
00133 } else {
00134 if ((d + r1) <= r2) {
00135 _centre.set(c2);
00136 _radius = r2;
00137 _radius2 = r2 * r2;
00138 } else {
00139 c2.scale((1.0 + (r2 - r1) / d) / 2.0);
00140 _centre.set(c1);
00141 _centre.scaleAdd((1.0 + (r1 - r2) / d) / 2.0, c2);
00142 _radius = (r1 + r2 + d) / 2.0;
00143 _radius2 = _radius * _radius;
00144 }
00145 }
00146
00147 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00148 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00149 }
00150
00151 Sphere::Sphere(SceneGraphObject& obj)
00152 {
00153 POGExplorer explorer;
00154 explorer.explore(obj);
00155
00156 _centre.set(explorer.result());
00157
00158 RadiusExplorer explorer2(_centre);
00159 explorer2.explore(obj);
00160
00161 _radius = explorer2.result();
00162 _radius2 = _radius * _radius;
00163 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00164 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00165 }
00166
00167 Sphere::Sphere(List<SceneGraphObject>& list)
00168 {
00169 _centre.set(0,0,0);
00170
00171 unsigned num = 0;
00172 SceneGraphObject* pObject = list.firstItem();
00173 while (pObject) {
00174 POGExplorer pogExplorer;
00175 pogExplorer.explore(*pObject);
00176 _centre.add(pogExplorer.result());
00177 num++;
00178 pObject = list.nextItem();
00179 }
00180
00181 if (num) _centre.scale(1.0/num);
00182
00183 _radius = -MAXFLOAT;
00184
00185 float r;
00186 pObject = list.firstItem();
00187 while (pObject) {
00188 RadiusExplorer radExplorer(_centre);
00189 radExplorer.explore(*pObject);
00190 r = radExplorer.result();
00191 if (r > _radius) _radius = r;
00192 pObject = list.nextItem();
00193 }
00194 _radius2 = _radius * _radius;
00195 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00196 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00197 }
00198
00199 void Sphere::rayIntersection(PointEnv* pPE,
00200 int mask,
00201 const Vector3& origin,
00202 const Vector3& direction,
00203 float maxDist)
00204 {
00205 if (!pPE) {
00206 fprintf(stderr,"Sphere error: No point environment structure defined\n");
00207 return;
00208 }
00209
00210 pPE->mask = ENV_HAVE_NOTHING;
00211
00212 Vector3 v(_centre - origin);
00213 double v2 = v.dot(v);
00214 double& t0 = pPE->distance;
00215
00216 t0 = v.dot(direction);
00217 if (v2 > _epsMinus) {
00218 if (t0 < Geometry::EPS) return;
00219 register double td2 = _radius2 - v2 + (t0*t0);
00220 if (td2 < 0.0) return;
00221
00222 t0 = (v2 < _epsPlus) ? t0 + sqrt(td2) : t0 - sqrt(td2);
00223 } else
00224 t0 += sqrt(_radius2 - v2 + (t0*t0));
00225
00226 if (t0 > maxDist) return;
00227
00228 if (mask & (ENV_WANT_INTERSECTION|ENV_WANT_UV_COORD|ENV_WANT_NORMAL)) {
00229 pPE->intersection.set(direction);
00230 pPE->intersection.scaleAdd(t0, origin);
00231 if (mask & ENV_WANT_UV_COORD) {
00232 Vector3 xyz(pPE->intersection);
00233 xyz.sub(_centre);
00234 double auxV = acos(xyz.z / _radius);
00235 if (xyz.y >= 0.)
00236 pPE->uvCoord.set(acos(xyz.x/(_radius*sin(auxV))) / (2*PI),
00237 auxV / PI);
00238 else
00239 pPE->uvCoord.set((PI+acos(xyz.x/(_radius*sin(auxV)))) / (2*PI),
00240 auxV / PI);
00241 pPE->mask |=
00242 ENV_HAVE_INTERFERENCE|ENV_HAVE_INTERSECTION|ENV_HAVE_DISTANCE|ENV_HAVE_UV_COORD;
00243 } else
00244 pPE->mask |=
00245 ENV_HAVE_INTERFERENCE|ENV_HAVE_INTERSECTION|ENV_HAVE_DISTANCE;
00246 if (mask & ENV_WANT_NORMAL) {
00247 pPE->normal.set(pPE->intersection - _centre);
00248
00249 pPE->normal.normalize();
00250 pPE->normalOrientation = PointEnv::OUTWARDS_NORMAL;
00251 pPE->mask |= ENV_HAVE_NORMAL;
00252 }
00253 } else
00254 pPE->mask |= ENV_HAVE_INTERFERENCE|ENV_HAVE_DISTANCE;
00255 }
00256
00257 bool Sphere::mapToUV(const Vector3& v, Vector2& uv)
00258 {
00259 Vector3 xyz(v);
00260 xyz.sub(_centre);
00261 xyz.normalize();
00262
00263
00264 double aux = xyz.x; xyz.x = xyz.z; xyz.z = aux;
00265
00266 double r = sqrt((xyz.x * xyz.x) + (xyz.y * xyz.y));
00267 double rho = sqrt((r * r) + (xyz.z * xyz.z));
00268 double theta, phi;
00269
00270 if(r == 0.0) {
00271 theta = 0.0;
00272 phi = 0.0;
00273 } else {
00274 phi = (xyz.z == 0.0) ? PI / 2.0 : acos(xyz.z / rho);
00275 theta = (xyz.y == 0.0) ? PI / 2.0 : asin(xyz.y / r) + (PI / 2.0);
00276 }
00277
00278 uv.set(1 - (phi / PI), 1 - (theta / PI));
00279
00280 return true;
00281
00282 #if 0 // funkci mapovani na dve polokoule
00283 Vector3 xyz(v);
00284 xyz.sub(_centre);
00285 xyz.normalize();
00286
00287
00288 double aux = xyz.x; xyz.x = xyz.z; xyz.z = aux;
00289
00290 double r = sqrt((xyz.x * xyz.x) + (xyz.y * xyz.y));
00291 double rho = sqrt((r * r) + (xyz.z * xyz.z));
00292 double theta, phi;
00293
00294 if(r == 0.0) {
00295 theta = 0.0;
00296 phi = 0.0;
00297 } else {
00298 phi = (xyz.z == 0.0) ? PI / 2.0 : acos(xyz.z / rho);
00299 theta = (xyz.y == 0.0) ? PI / 2.0 : asin(xyz.y / r) + (PI / 2.0);
00300 }
00301
00302 uv.set(1 - (phi / PI), 1 - (theta / PI));
00303 return true;
00304 #endif
00305 }
00306
00307 void Sphere::randomSample(int mask, PointEnv& pe, double* pdf)
00308 {
00309 pe.mask = ENV_HAVE_NOTHING;
00310
00311 if (mask & (ENV_WANT_SURFACE_POINT|ENV_WANT_NORMAL|ENV_WANT_UV_COORD)) {
00312 double d;
00313 do {
00314 pe.intersection.set(2. * ESG_DBL_RAND - 1.,
00315 2. * ESG_DBL_RAND - 1.,
00316 2. * ESG_DBL_RAND - 1.);
00317 d = pe.intersection.lengthSquared();
00318 } while (d > 1.);
00319 pe.intersection.scale(_radius/sqrt(d));
00320 pe.intersection.add(_centre);
00321 pe.mask |= ENV_HAVE_SURFACE_POINT;
00322
00323 if ((mask&ENV_WANT_UV_COORD) && mapToUV(pe.intersection, pe.uvCoord))
00324 pe.mask |= ENV_HAVE_UV_COORD;
00325
00326 if (mask & ENV_WANT_NORMAL) {
00327 pe.normal.set(pe.intersection);
00328 pe.normal.normalize();
00329 pe.mask |= ENV_HAVE_NORMAL;
00330 pe.normalOrientation = PointEnv::OUTWARDS_NORMAL;
00331 }
00332 }
00333
00334 if (pdf) *pdf = .25 / (M_PI * _radius2);
00335 }
00336
00337 bool Sphere::randomDirection(const Vector3& pov, Vector3& dir, double* pdf)
00338 {
00339
00340
00341
00342
00343
00344
00345
00346
00347 double wLength;
00348 Vector3 u(0.0, 1.0, 0.0);
00349 Vector3 v;
00350 Vector3 w(_centre);
00351
00352 w.sub(pov);
00353 wLength = w.length();
00354 w.scale(1./wLength);
00355
00356 (fabs(w.x) > fabs(w.y)) ? u.set(0.0, 1.0, 0.0) : u.set(1.0, 0.0, 0.0);
00357
00358 v.cross(w, u); v.normalize();
00359 u.cross(w, v); u.normalize();
00360
00361 double rd = _radius / wLength;
00362 double cosAlpha = ESG_DBL_RAND * (sqrt(1. - rd * rd) - 1.) + 1.;
00363 double phi = ESG_DBL_RAND * 2 * M_PI;
00364 double alpha = acos(cosAlpha);
00365 double sinAlpha = sin(alpha);
00366
00367 Vector3 aux(cos(phi) * sinAlpha, sin(phi) * sinAlpha, cosAlpha);
00368 aux.normalize();
00369
00370 dir.set(aux.x * u.x + aux.y * v.x + aux.z * w.x,
00371 aux.x * u.y + aux.y * v.y + aux.z * w.y,
00372 aux.x * u.z + aux.y * v.z + aux.z * w.z);
00373
00374
00375 if (pdf)
00376 cerr << "Sphere::randomDirection(): PDF is not implemented" << endl;
00377
00378 return true;
00379 }
00380
00381 Interval Sphere::extent(const Vector3& direction) const
00382 {
00383 Interval retInt;
00384 float hlp;
00385
00386 hlp = _centre.dot(direction);
00387 retInt.min = hlp - _radius;
00388 retInt.max = hlp + _radius;
00389 return retInt;
00390 }
00391
00392 Geometry* Sphere::clone(const Matrix4* pTrMat) const
00393 {
00394 Sphere* pRet = new Sphere();
00395 pRet->_duplicate_attributes(*this);
00396 if (pTrMat) pRet->_transform(*pTrMat);
00397 return pRet;
00398 }
00399
00400 Vector3 Sphere::centroid() const
00401 {
00402 return _centre;
00403 }
00404
00405 double Sphere::radius() const
00406 {
00407 return _radius;
00408 }
00409
00410 double Sphere::radius(const Vector3& centroid) const
00411 {
00412 return (((Vector3)(centroid-_centre)).length() + _radius);
00413 }
00414
00415 bool Sphere::separation(Geometry& geom, Vector3* pDir)
00416 {
00417 register double rads = geom.radius() + _radius;
00418 Vector3 c(geom.centroid());
00419 c.sub(_centre);
00420 register double ns = c.normSquared();
00421 if (ns > rads * rads) {
00422 ns = sqrt(ns);
00423 if (pDir) pDir->set(c.x/ns, c.y/ns, c.z/ns);
00424 return true;
00425 }
00426 return false;
00427 }
00428
00429 double Sphere::distance(const Geometry& geom, Vector3* pDir)
00430 {
00431 Vector3 c = geom.centroid();
00432 register double d = _radius + geom.radius(c);
00433 c.sub(_centre);
00434 register double d2 = c.length();
00435 if (pDir) pDir->set(c.x / d2, c.y / d2, c.z / d2);
00436 return (d2 - d);
00437 }
00438
00439 void Sphere::dump(const char* intent, const char* tab)
00440 {
00441 printf("%s geometry Sphere {", intent);
00442 printf("%s %s centre %f %f %f\n", intent, tab, _centre.x, _centre.y, _centre.z);
00443 printf("%s %s radius %f\n", intent, tab, _radius);
00444 printf("%s }", intent);
00445 }
00446
00447
00448 void Sphere::setCentre(const Vector3& centre)
00449 {
00450 _centre.set(centre);
00451 }
00452
00453
00454 void Sphere::setCentre(float x, float y, float z)
00455 {
00456 _centre.set(x,y,z);
00457 }
00458
00459 void Sphere::setRadius(float radius)
00460 {
00461 _radius = radius;
00462 _radius2 = radius * radius;
00463 _epsPlus = (_radius + Geometry::EPS) * (_radius + Geometry::EPS);
00464 _epsMinus = (_radius - Geometry::EPS) * (_radius - Geometry::EPS);
00465 }
00466