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
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
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
00305
00306
00307
00308
00309
00310
00311
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 }