src/rcrt/primitives/AABB.cpp

Go to the documentation of this file.
00001 #include "AABB.h"
00002 #include <limits>
00003 #include <algorithm>
00004 
00005 using namespace std;
00006 
00007 namespace rcrt
00008 {
00009 
00010 AABB::AABB(SolidObject* parent):Primitive(parent),minP(numeric_limits<float>::infinity()), maxP(-numeric_limits<float>::infinity())
00011 {
00012         center = (minP+maxP.getPosVec3D())*0.5;
00013 }
00014 
00015 
00016 AABB::AABB(const Point3D& min, const Point3D& max, SolidObject* parent):Primitive(parent),minP(numeric_limits<float>::infinity()),
00017 maxP(-numeric_limits<float>::infinity())
00018 {
00019         extend(min);
00020         extend(max);
00021 }
00022 
00023 
00024 AABB::~AABB()
00025 {
00026 }
00027 
00028 
00029 Intersection AABB::intersect(Ray& ray) const
00030 {
00031         float tmin, tmax, tymin, tymax, tzmin, tzmax;
00032         const float& invrdx = ray.invDir().x();
00033         const float& invrdy = ray.invDir().y();
00034         const float& invrdz = ray.invDir().z();
00035         Axis ax = X_AXIS;
00036         if(!isnan(invrdx)){
00037             if (invrdx >= 0)
00038             {
00039                 tmin = (minP.x() - ray.org().x()) * invrdx;
00040                 tmax = (maxP.x() - ray.org().x()) * invrdx;
00041             }else
00042             {
00043                 tmin = (maxP.x() - ray.org().x()) * invrdx;
00044                 tmax = (minP.x() - ray.org().x()) * invrdx;
00045             }
00046         } else {
00047                 tmin = -numeric_limits<float>::infinity();
00048                 tmax = numeric_limits<float>::infinity();
00049         }
00050         
00051         if(!isnan(invrdx)){
00052             if (invrdy >= 0)
00053             {
00054                 tymin = (minP.y() - ray.org().y()) * invrdy;
00055                 tymax = (maxP.y() - ray.org().y()) * invrdy;
00056             }else
00057             {
00058                 tymin = (maxP.y() - ray.org().y()) * invrdy;
00059                 tymax = (minP.y() - ray.org().y()) * invrdy;
00060             }
00061         } else {
00062                 tymin = -numeric_limits<float>::infinity();
00063                 tymax = numeric_limits<float>::infinity();
00064         }
00065 
00066     if ( (tmin > tymax) || (tymin > tmax) ) return Intersection();
00067     if ( tymin > tmin){
00068         ax = Y_AXIS;
00069         tmin = tymin;
00070     }
00071     if ( tymax < tmax) tmax = tymax;
00072 
00073     if(!isnan(invrdz)) {
00074             if (invrdz >= 0)
00075             {
00076                 tzmin = (minP.z() - ray.org().z()) * invrdz;
00077                 tzmax = (maxP.z() - ray.org().z()) * invrdz;
00078             }else
00079             {
00080                 tzmin = (maxP.z() - ray.org().z()) * invrdz;
00081                 tzmax = (minP.z() - ray.org().z()) * invrdz;
00082             }
00083         } else {
00084         tzmin = -numeric_limits<float>::infinity();
00085         tzmax = numeric_limits<float>::infinity();
00086     }
00087 
00088     if ( (tmin > tzmax) || (tzmin > tmax) ) return Intersection();
00089     if ( tzmin > tmin){
00090         ax = Z_AXIS;
00091         tmin = tzmin;
00092     }
00093     if ( tzmax < tmax) tmax = tzmax;
00094 
00095     // check if values are valid
00096     if (tmax < 0 || tmin == -numeric_limits<float>::infinity()
00097                 || tmax == numeric_limits<float>::infinity()) return Intersection();
00098     if (tmin < 0){
00099         tmin = tmax;
00100     }
00101     
00102     //a,b could be calculated better, but this is more efficient and enough for normals
00103     float a,b;
00104     switch(ax){
00105     case X_AXIS:
00106         a = getLength(Y_AXIS)+getLength(Z_AXIS)/2;
00107         b = getLength(Y_AXIS)/2; break;
00108     case Y_AXIS:
00109         a = getLength(Y_AXIS)+getLength(Z_AXIS)/2;
00110         b = getLength(Y_AXIS) + getLength(X_AXIS)/2; break;
00111     default:
00112         a = getLength(Y_AXIS)/2;
00113         b = getLength(Y_AXIS)+getLength(X_AXIS)/2;
00114     }
00115     
00116     return Intersection(tmin, this, ray.atDistance(tmin), a, b);
00117 }
00118 
00119 
00120 const AABB& AABB::getBoundingBox() const
00121 {
00122         return *this;
00123 }
00124 
00125 const Point3D& AABB::getCentroid() const
00126 {
00127         return center;
00128 }
00129 
00130 
00131 void AABB::extend(const AABB& box)
00132 {
00133         extend(box.minP);
00134         extend(box.maxP);
00135 }
00136 
00137 void AABB::extend(const Point3D& p)
00138 {
00139         float xmin = min(p.x(), minP.x());
00140         float xmax = max(p.x(), maxP.x());
00141         float ymin = min(p.y(), minP.y());
00142         float ymax = max(p.y(), maxP.y());
00143         float zmin = min(p.z(), minP.z());
00144         float zmax = max(p.z(), maxP.z());
00145         
00146         minP = Point3D(xmin,ymin,zmin);
00147         maxP = Point3D(xmax,ymax,zmax);
00148 
00149         center = ((minP+maxP.getPosVec3D())*0.5);
00150 }
00151 
00152 float AABB::getLength(Axis a) const
00153 {
00154         switch(a){
00155         case X_AXIS:
00156                 return maxP.x() - minP.x();
00157         case Y_AXIS:
00158                 return maxP.y() - minP.y();
00159         default:
00160                 return maxP.z() - minP.z();
00161         }
00162 }
00163 
00164 Axis AABB::getMainAxis() const
00165 {
00166         float xl = getLength(X_AXIS);
00167         float yl = getLength(Y_AXIS);
00168         float zl = getLength(Z_AXIS);
00169         
00170         if(xl < yl){
00171                 if(yl < zl)
00172                         return Z_AXIS;
00173                 return Y_AXIS;
00174         }
00175         else if(xl < zl)
00176                 return Z_AXIS;
00177         return X_AXIS;
00178                 
00179 }
00180 
00181 float AABB::getMin(Axis a) const
00182 {
00183         switch(a){
00184         case X_AXIS:
00185                 return minP.x();
00186         case Y_AXIS:
00187                 return minP.y();
00188         default:
00189                 return minP.z();
00190         }
00191 }
00192 
00193 float AABB::getMax(Axis a) const
00194 {
00195         switch(a){
00196         case X_AXIS:
00197                 return maxP.x();
00198         case Y_AXIS:
00199                 return maxP.y();
00200         default:
00201                 return maxP.z();
00202         }
00203 }
00204 
00205 const Point3D& AABB::getMaxP() const
00206 {
00207         return maxP;
00208 }
00209 
00210 const Point3D& AABB::getMinP() const
00211 {
00212         return minP;
00213 }
00214 
00215 bool AABB::equals(const AABB& box) const
00216 {
00217         return minP.equals(box.minP) && maxP.equals(box.maxP);
00218 }
00219 
00220 AABB AABB::transformed(const Matrix4D& mat) const
00221 {
00222         AABB box;
00223         box.extend(mat*minP);
00224         box.extend(mat*maxP);
00225         box.extend(mat*Point3D(minP.x(),minP.y(),maxP.z()));
00226         box.extend(mat*Point3D(minP.x(),maxP.y(),minP.z()));
00227         box.extend(mat*Point3D(minP.x(),maxP.y(),maxP.z()));
00228         box.extend(mat*Point3D(maxP.x(),minP.y(),minP.z()));
00229         box.extend(mat*Point3D(maxP.x(),minP.y(),maxP.z()));
00230         box.extend(mat*Point3D(maxP.x(),maxP.y(),minP.z()));
00231         return box;
00232 }
00233 
00234 Vec3D AABB::getSNormal(float a, float b) const
00235 {
00236         return getGNormal(a,b);
00237 }
00238 
00239 Vec3D AABB::getGNormal(float a, float b) const
00240 {
00241         float lX = getLength(X_AXIS);
00242         float lY = getLength(Y_AXIS);
00243         float lZ = getLength(Z_AXIS);
00244         if(a < 0 || b < 0 || a > 2*lY+lZ)
00245                 return Vec3D(1,1,1);
00246         if(a < lY){
00247                 if(b > lY && b < 2*lY)
00248                         return Vec3D(0,0,-1);
00249                 return Vec3D(1,1,1);
00250         } else if(a < lY+lZ){
00251                 float l = 2*lY+2*lX;
00252                 if(b > l)
00253                         return Vec3D(1,1,1);
00254                 l -= lX;
00255                 if(b > l)
00256                         return Vec3D(0,-1,0);
00257                 l -= lY;
00258                 if(b > l)
00259                         return Vec3D(1,0,0);
00260                 l -= lX;
00261                 if(b > l)
00262                         return Vec3D(0,1,0);
00263                 return Vec3D(-1,0,0);
00264         } else if(b >= lY && b <= 2*lY)
00265                 return Vec3D(0,0,1);
00266         return Vec3D(1,1,1);
00267 }
00268 
00269 Point2D AABB::getUV(float a, float b) const
00270 {
00271         return Point2D(a,b);
00272 }
00273 
00274 float AABB::getVolume() const
00275 {
00276         return fabs(maxP[0] - minP[0]) * fabs(maxP[1] - minP[1]) * fabs(maxP[2] - minP[2]);
00277 }
00278 
00279 float AABB::getSurfaceArea() const
00280 {
00281         float a = fabs(maxP[0] - minP[0]);
00282         float b = fabs(maxP[1] - minP[1]);
00283         float c = fabs(maxP[2] - minP[2]);
00284         return 2 * (a*b + a*c + b*c);
00285 }
00286 
00287 bool AABB::isEmpty() const {
00288         return minP == Point3D(std::numeric_limits<float>::infinity()) && maxP == Point3D(-std::numeric_limits<float>::infinity());
00289 }
00290 
00291 void AABB::contract(const AABB& box)
00292 {
00293         minP = Point3D(box.getMinP()[0] > minP[0] ? box.getMinP()[0] : minP[0],
00294                         box.getMinP()[1] > minP[1] ? box.getMinP()[1] : minP[1],
00295                         box.getMinP()[2] > minP[2] ? box.getMinP()[2] : minP[2]);
00296         
00297         maxP = Point3D(box.getMaxP()[0] < maxP[0] ? box.getMaxP()[0] : maxP[0],
00298                                 box.getMaxP()[1] < maxP[1] ? box.getMaxP()[1] : maxP[1],
00299                                 box.getMaxP()[2] < maxP[2] ? box.getMaxP()[2] : maxP[2]);
00300         
00301 }
00302 
00303 void AABB::clipPlane(Axis axis, float plane, AABB& lBox, AABB& rBox) const {
00304         /*if (minP[axis] > plane) {
00305                 rBox = AABB(minP,maxP);
00306                 return;
00307         }
00308         
00309         if (maxP[axis] < plane) {
00310                 lBox = AABB(minP,maxP);
00311                 return;
00312         }
00313         */
00314         Point3D maxLP = maxP; maxLP[axis] = plane;
00315         Point3D minRP = minP; minRP[axis] = plane;
00316         
00317         lBox = AABB(minP,maxLP);
00318         rBox = AABB(minRP, maxP);
00319 }
00320 
00321 }

Generated on Thu Jan 31 19:26:19 2008 for RenderingCompetitionRayTracer by  doxygen 1.5.3