[2582] | 1 | // =================================================================== |
---|
| 2 | // $Id: sbbox.h $ |
---|
| 3 | // |
---|
| 4 | // sbbox.h |
---|
| 5 | // |
---|
| 6 | // Class: SBBox |
---|
| 7 | // |
---|
| 8 | // REPLACEMENT_STRING |
---|
| 9 | // |
---|
| 10 | // Copyright by Vlastimil Havran, 2007 - email to "vhavran AT seznam.cz" |
---|
| 11 | // Initial coding by Vlasta Havran, December 2005 |
---|
| 12 | |
---|
| 13 | #ifndef __SBBOX_H__ |
---|
| 14 | #define __SBBOX_H__ |
---|
| 15 | |
---|
| 16 | // ANSI C++ headers |
---|
| 17 | #include <cassert> |
---|
| 18 | #include <iostream> |
---|
| 19 | #include <ostream> |
---|
| 20 | |
---|
| 21 | // GOLEM headers |
---|
| 22 | #include "configh.h" |
---|
| 23 | #include "common.h" |
---|
| 24 | #include "AxisAlignedBox3.h" |
---|
| 25 | #include "SimpleRay.h" |
---|
| 26 | #include "Vector3.h" |
---|
| 27 | |
---|
| 28 | namespace GtpVisibilityPreprocessor { |
---|
| 29 | |
---|
| 30 | // Forward declarations |
---|
| 31 | |
---|
| 32 | // -------------------------------------------------------- |
---|
| 33 | // The definition of the bounding box having 24 Bytes only |
---|
| 34 | struct SBBox |
---|
| 35 | { |
---|
| 36 | public: |
---|
| 37 | SBBox() {} |
---|
| 38 | SBBox(const Vector3 &a, const Vector3 &b) { |
---|
| 39 | pp[0] = a; pp[1] = b; |
---|
| 40 | } |
---|
| 41 | // member functions |
---|
| 42 | const Vector3& Min() const { return pp[0]; } |
---|
| 43 | const Vector3& Max() const { return pp[1]; } |
---|
| 44 | Vector3& Min() { return pp[0]; } |
---|
| 45 | Vector3& Max() { return pp[1]; } |
---|
| 46 | const float& Min(int i) const { return pp[0][i]; } |
---|
| 47 | const float& Max(int i) const { return pp[1][i]; } |
---|
| 48 | float& Min(int i) { return pp[0][i]; } |
---|
| 49 | float& Max(int i) { return pp[1][i]; } |
---|
| 50 | |
---|
| 51 | // Access to individual components, maybe it is not a good idea |
---|
| 52 | const float& MinX() const { return pp[0].x; } |
---|
| 53 | const float& MaxX() const { return pp[1].x; } |
---|
| 54 | float& MinX() { return pp[0].x; } |
---|
| 55 | float& MaxX() { return pp[1].x; } |
---|
| 56 | const float& MinY() const { return pp[0].y; } |
---|
| 57 | const float& MaxY() const { return pp[1].y; } |
---|
| 58 | float& MinY() { return pp[0].y; } |
---|
| 59 | float& MaxY() { return pp[1].y; } |
---|
| 60 | const float& MinZ() const { return pp[0].z; } |
---|
| 61 | const float& MaxZ() const { return pp[1].z; } |
---|
| 62 | float& MinZ() { return pp[0].z; } |
---|
| 63 | float& MaxZ() { return pp[1].z; } |
---|
| 64 | |
---|
| 65 | void SetMin(float x, float y, float z) { |
---|
| 66 | pp[0].x=x; pp[0].y=y; pp[0].z=z; } |
---|
| 67 | void SetMax(float x, float y, float z) { |
---|
| 68 | pp[1].x=x; pp[1].y=y; pp[1].z=z; } |
---|
| 69 | |
---|
| 70 | // initialization to the non existing bounding box |
---|
| 71 | inline void Initialize() { |
---|
| 72 | pp[0] = Vector3(MAXFLOAT); |
---|
| 73 | pp[1] = Vector3(-MAXFLOAT); |
---|
| 74 | } |
---|
| 75 | inline void Convert(const AxisAlignedBox3 &b) { |
---|
| 76 | pp[0] = b.Min(); |
---|
| 77 | pp[1] = b.Max(); |
---|
| 78 | } |
---|
| 79 | Vector3 Diagonal() const { return pp[1] - pp[0];} |
---|
| 80 | |
---|
| 81 | // Compute the center of the box |
---|
| 82 | void ComputeCentroid(Vector3 &c) const { |
---|
| 83 | c.x = (pp[0].x + pp[1].x)*0.5f; |
---|
| 84 | c.y = (pp[0].y + pp[1].y)*0.5f; |
---|
| 85 | c.z = (pp[0].z + pp[1].z)*0.5f; |
---|
| 86 | } |
---|
| 87 | |
---|
| 88 | // Compute half of surface area of the box |
---|
| 89 | float SA2() const { |
---|
| 90 | float t1 = (pp[1].x-pp[0].x); |
---|
| 91 | float t2 = (pp[1].y-pp[0].y); |
---|
| 92 | float t3 = (pp[1].z-pp[0].z); |
---|
| 93 | return t1*t2 + t2*t3 + t1*t3; |
---|
| 94 | } |
---|
| 95 | // Compute volume of the box |
---|
| 96 | float GetVolume() const { |
---|
| 97 | return (pp[1].x-pp[0].x)*(pp[1].y-pp[0].y)*(pp[1].z-pp[0].z); |
---|
| 98 | } |
---|
| 99 | |
---|
| 100 | void SetMin(int axis, const float value) { |
---|
| 101 | pp[0][axis] = value; |
---|
| 102 | } |
---|
| 103 | void SetMax(int axis, const float value) { |
---|
| 104 | pp[1][axis] = value; |
---|
| 105 | } |
---|
| 106 | // Write acess to min and max |
---|
| 107 | void SetMin(const Vector3& bmin) { pp[0] = bmin;} |
---|
| 108 | void SetMax(const Vector3& bmax) { pp[1] = bmax;} |
---|
| 109 | |
---|
| 110 | // Decrease box by given splitting plane |
---|
| 111 | void Reduce(int axis, int right, float value) { |
---|
| 112 | if ( (value >= pp[0][axis]) && (value <= pp[1][axis]) ) { |
---|
| 113 | if (right) |
---|
| 114 | pp[0][axis] = value; |
---|
| 115 | else |
---|
| 116 | pp[1][axis] = value; |
---|
| 117 | } |
---|
| 118 | } |
---|
| 119 | inline void Include(const AxisAlignedBox3 &bbox); |
---|
| 120 | inline void Include(const SBBox &bbox); |
---|
| 121 | inline bool RayIntersect(const SimpleRay &r, |
---|
| 122 | float &tmin, |
---|
| 123 | float &tmax) const; |
---|
| 124 | |
---|
| 125 | inline void ComputeMaxT(const SimpleRay &r, |
---|
| 126 | float &tmax) const; |
---|
| 127 | inline void ComputeMinT(const SimpleRay &r, |
---|
| 128 | float &tmin) const; |
---|
| 129 | |
---|
| 130 | // Query functions |
---|
| 131 | |
---|
| 132 | // Includes returns true if this box includes box b (completely) |
---|
| 133 | bool Includes(const SBBox &b) const; |
---|
| 134 | bool Includes(const SBBox &b, float eps) const; |
---|
| 135 | |
---|
| 136 | // Returns false if the box 'b' is fully contained in 'this', see the code |
---|
| 137 | inline bool ExcludesPartially(const SBBox &b) const; |
---|
| 138 | |
---|
| 139 | // Returs true if this box includes a point |
---|
| 140 | inline bool Includes(const Vector3 &vec) const; |
---|
| 141 | |
---|
| 142 | // Includes returns true if this box includes box b including boundary |
---|
| 143 | inline bool IncludesS(const Vector3 &vec) const; |
---|
| 144 | |
---|
| 145 | inline bool IncludesS(const Vector3 &vec, float eps) const; |
---|
| 146 | |
---|
| 147 | inline bool Equal(const SBBox &b, float eps = 0.f) const; |
---|
| 148 | |
---|
| 149 | // Test if the box is really sensefull |
---|
| 150 | bool IsCorrect(); |
---|
| 151 | |
---|
| 152 | // Overlap returns 1 if the two axis-aligned boxes overlap .. only strongly |
---|
| 153 | friend inline bool OverlapS(const SBBox &, const SBBox &); |
---|
| 154 | |
---|
| 155 | protected: |
---|
| 156 | // pp[0] is minimum, pp[1] is maximum |
---|
| 157 | Vector3 pp[2]; |
---|
| 158 | }; |
---|
| 159 | |
---|
| 160 | // -------------------------------------------------------- |
---|
| 161 | // Inline functions |
---|
| 162 | |
---|
| 163 | inline void |
---|
| 164 | SBBox::Include(const AxisAlignedBox3 &bbox) |
---|
| 165 | { |
---|
| 166 | Minimize(pp[0], bbox.Min()); |
---|
| 167 | Maximize(pp[1], bbox.Max()); |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | inline void |
---|
| 171 | SBBox::Include(const SBBox &bbox) |
---|
| 172 | { |
---|
| 173 | Minimize(pp[0], bbox.pp[0]); |
---|
| 174 | Maximize(pp[1], bbox.pp[1]); |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | inline bool |
---|
| 178 | SBBox::Equal(const SBBox &b, float eps) const |
---|
| 179 | { |
---|
| 180 | if ( (!EpsilonEqual(pp[0].x, b.pp[0].x, eps)) || |
---|
| 181 | (!EpsilonEqual(pp[0].y, b.pp[0].y, eps)) || |
---|
| 182 | (!EpsilonEqual(pp[0].z, b.pp[0].z, eps)) || |
---|
| 183 | (!EpsilonEqual(pp[1].x, b.pp[1].x, eps)) || |
---|
| 184 | (!EpsilonEqual(pp[1].y, b.pp[1].y, eps)) || |
---|
| 185 | (!EpsilonEqual(pp[1].z, b.pp[1].z, eps)) ) |
---|
| 186 | return false; // they are not equal |
---|
| 187 | return true; |
---|
| 188 | } |
---|
| 189 | |
---|
| 190 | inline bool |
---|
| 191 | SBBox::IsCorrect() |
---|
| 192 | { |
---|
| 193 | if ( (pp[0].x > pp[1].x) || |
---|
| 194 | (pp[0].y > pp[1].y) || |
---|
| 195 | (pp[0].z > pp[1].z) ) |
---|
| 196 | return false; // box is not formed |
---|
| 197 | return true; |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | inline bool |
---|
| 201 | OverlapS(const SBBox &x, const SBBox &y) |
---|
| 202 | { |
---|
| 203 | if (x.pp[1].x <= y.pp[0].x || |
---|
| 204 | x.pp[0].x >= y.pp[1].x || |
---|
| 205 | x.pp[1].y <= y.pp[0].y || |
---|
| 206 | x.pp[0].y >= y.pp[1].y || |
---|
| 207 | x.pp[1].z <= y.pp[0].z || |
---|
| 208 | x.pp[0].z >= y.pp[1].z) { |
---|
| 209 | return false; |
---|
| 210 | } |
---|
| 211 | return true; |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | // Returns true if the boxes are either disjoint or only |
---|
| 215 | // share a single face ! |
---|
| 216 | inline bool |
---|
| 217 | SBBox::ExcludesPartially(const SBBox &b) const |
---|
| 218 | { |
---|
| 219 | if (b.pp[1].x <= pp[0].x || |
---|
| 220 | b.pp[1].y <= pp[0].y || |
---|
| 221 | b.pp[1].z <= pp[0].z || |
---|
| 222 | b.pp[0].x >= pp[1].x || |
---|
| 223 | b.pp[0].y >= pp[1].y || |
---|
| 224 | b.pp[0].z >= pp[1].z) |
---|
| 225 | // box 'b' is not fully contained in 'this', also true when neighboring faces |
---|
| 226 | return true; |
---|
| 227 | return false; // box 'b' contained in this box |
---|
| 228 | } |
---|
| 229 | |
---|
| 230 | inline bool |
---|
| 231 | SBBox::Includes(const Vector3 &vec) const |
---|
| 232 | { |
---|
| 233 | if (vec.x < pp[0].x || |
---|
| 234 | vec.x > pp[1].x || |
---|
| 235 | vec.y < pp[0].y || |
---|
| 236 | vec.y > pp[1].y || |
---|
| 237 | vec.z < pp[0].z || |
---|
| 238 | vec.z > pp[1].z) { |
---|
| 239 | return false; |
---|
| 240 | } |
---|
| 241 | return true; |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | inline bool |
---|
| 245 | SBBox::IncludesS(const Vector3 &vec) const |
---|
| 246 | { |
---|
| 247 | if (vec.x <= pp[0].x || |
---|
| 248 | vec.x >= pp[1].x || |
---|
| 249 | vec.y <= pp[0].y || |
---|
| 250 | vec.y >= pp[1].y || |
---|
| 251 | vec.z <= pp[0].z || |
---|
| 252 | vec.z >= pp[1].z) { |
---|
| 253 | return false; |
---|
| 254 | } |
---|
| 255 | return true; |
---|
| 256 | } |
---|
| 257 | |
---|
| 258 | inline bool |
---|
| 259 | SBBox::IncludesS(const Vector3 &vec, float eps) const |
---|
| 260 | { |
---|
| 261 | if (vec.x <= (pp[0].x-eps) || |
---|
| 262 | vec.x >= (pp[1].x+eps) || |
---|
| 263 | vec.y <= (pp[0].y-eps) || |
---|
| 264 | vec.y >= (pp[1].y+eps) || |
---|
| 265 | vec.z <= (pp[0].z-eps) || |
---|
| 266 | vec.z >= (pp[1].z+eps) ) { |
---|
| 267 | return false; // outside |
---|
| 268 | } |
---|
| 269 | return true; // point inside |
---|
| 270 | } |
---|
| 271 | |
---|
| 272 | // Function describing the box |
---|
| 273 | extern void |
---|
| 274 | Describe(const SBBox &b, std::ostream &app, int indent); |
---|
| 275 | |
---|
| 276 | // Function describing the box |
---|
| 277 | extern void |
---|
| 278 | DescribeXYZ(const SBBox &b, std::ostream &app, int indent); |
---|
| 279 | |
---|
| 280 | #if 1 |
---|
| 281 | // The implementation I, the first version implemented by Vlastimil |
---|
| 282 | // Havran, without looking into the literature |
---|
| 283 | inline bool |
---|
| 284 | SBBox::RayIntersect(const SimpleRay &ray, |
---|
| 285 | float &tmin, float &tmax) const |
---|
| 286 | { |
---|
| 287 | float interval_min = tmin; |
---|
| 288 | float interval_max = tmax; |
---|
| 289 | |
---|
| 290 | const Vector3 &rayLoc = ray.mOrigin; |
---|
| 291 | const Vector3 &rayDir = ray.mDirection; |
---|
| 292 | |
---|
| 293 | float t0, t1; |
---|
| 294 | if (rayDir.x > 0) { |
---|
| 295 | t0 = (pp[0].x - rayLoc.x) / rayDir.x; |
---|
| 296 | t1 = (pp[1].x - rayLoc.x) / rayDir.x; |
---|
| 297 | } |
---|
| 298 | else { |
---|
| 299 | t0 = (pp[1].x - rayLoc.x) / rayDir.x; |
---|
| 300 | t1 = (pp[0].x - rayLoc.x) / rayDir.x; |
---|
| 301 | } |
---|
| 302 | assert(t0 <= t1); |
---|
| 303 | if (t0 > interval_min) |
---|
| 304 | interval_min = t0; |
---|
| 305 | if (t1 < interval_max) |
---|
| 306 | interval_max = t1; |
---|
| 307 | if (interval_min > interval_max) |
---|
| 308 | return false; |
---|
| 309 | |
---|
| 310 | if (rayDir.y > 0) { |
---|
| 311 | t0 = (pp[0].y - rayLoc.y) / rayDir.y; |
---|
| 312 | t1 = (pp[1].y - rayLoc.y) / rayDir.y; |
---|
| 313 | } |
---|
| 314 | else { |
---|
| 315 | t0 = (pp[1].y - rayLoc.y) / rayDir.y; |
---|
| 316 | t1 = (pp[0].y - rayLoc.y) / rayDir.y; |
---|
| 317 | } |
---|
| 318 | assert(t0 <= t1); |
---|
| 319 | if (t0 > interval_min) |
---|
| 320 | interval_min = t0; |
---|
| 321 | if (t1 < interval_max) |
---|
| 322 | interval_max = t1; |
---|
| 323 | if (interval_min > interval_max) |
---|
| 324 | return false; |
---|
| 325 | |
---|
| 326 | if (rayDir.z > 0) { |
---|
| 327 | t0 = (pp[0].z - rayLoc.z) / rayDir.z; |
---|
| 328 | t1 = (pp[1].z - rayLoc.z) / rayDir.z; |
---|
| 329 | } |
---|
| 330 | else { |
---|
| 331 | t0 = (pp[1].z - rayLoc.z) / rayDir.z; |
---|
| 332 | t1 = (pp[0].z - rayLoc.z) / rayDir.z; |
---|
| 333 | } |
---|
| 334 | assert(t0 <= t1); |
---|
| 335 | if (t0 > interval_min) |
---|
| 336 | interval_min = t0; |
---|
| 337 | if (t1 < interval_max) |
---|
| 338 | interval_max = t1; |
---|
| 339 | |
---|
| 340 | // return true if the box is intersected |
---|
| 341 | // return false if not intersected by ray |
---|
| 342 | if ( (interval_max > 0.0f) && |
---|
| 343 | (interval_min <= interval_max) ) { |
---|
| 344 | // yes, intersected, update tmin and tmax for current node |
---|
| 345 | tmin = interval_min; |
---|
| 346 | tmax = interval_max; |
---|
| 347 | return true; // intersected |
---|
| 348 | } |
---|
| 349 | return false; // not intersected |
---|
| 350 | } |
---|
| 351 | #endif |
---|
| 352 | |
---|
| 353 | #if 1 |
---|
| 354 | // Here we compute exit signed distance along the ray |
---|
| 355 | // from the box |
---|
| 356 | inline void |
---|
| 357 | SBBox::ComputeMaxT(const SimpleRay &ray, |
---|
| 358 | float &tmax) const |
---|
| 359 | { |
---|
| 360 | float interval_max = tmax; |
---|
| 361 | |
---|
| 362 | const Vector3 &rayLoc = ray.mOrigin; |
---|
| 363 | const Vector3 &rayDir = ray.mDirection; |
---|
| 364 | |
---|
| 365 | float t; |
---|
| 366 | assert(pp[1].x >= pp[0].x); |
---|
| 367 | if (rayDir.x > 0) |
---|
| 368 | t = (pp[1].x - rayLoc.x) / rayDir.x; |
---|
| 369 | else |
---|
| 370 | t = (pp[0].x - rayLoc.x) / rayDir.x; |
---|
| 371 | if (t > interval_max) |
---|
| 372 | interval_max = t; |
---|
| 373 | assert(pp[1].y >= pp[0].y); |
---|
| 374 | if (rayDir.y > 0) |
---|
| 375 | t = (pp[1].y - rayLoc.y) / rayDir.y; |
---|
| 376 | else |
---|
| 377 | t = (pp[0].y - rayLoc.y) / rayDir.y; |
---|
| 378 | if (t > interval_max) |
---|
| 379 | interval_max = t; |
---|
| 380 | assert(pp[1].z >= pp[0].z); |
---|
| 381 | if (rayDir.z > 0) |
---|
| 382 | t = (pp[1].z - rayLoc.z) / rayDir.z; |
---|
| 383 | else |
---|
| 384 | t = (pp[0].z - rayLoc.z) / rayDir.z; |
---|
| 385 | if (t > interval_max) |
---|
| 386 | interval_max = t; |
---|
| 387 | } |
---|
| 388 | #endif |
---|
| 389 | |
---|
| 390 | #if 1 |
---|
| 391 | // Here we compute entry signed distance along the ray |
---|
| 392 | // into the box |
---|
| 393 | inline void |
---|
| 394 | SBBox::ComputeMinT(const SimpleRay &ray, |
---|
| 395 | float &tmin) const |
---|
| 396 | { |
---|
| 397 | float interval_min = tmin; |
---|
| 398 | |
---|
| 399 | const Vector3 &rayLoc = ray.mOrigin; |
---|
| 400 | const Vector3 &rayDir = ray.mDirection; |
---|
| 401 | |
---|
| 402 | float t; |
---|
| 403 | assert(pp[1].x >= pp[0].x); |
---|
| 404 | if (rayDir.x > 0) |
---|
| 405 | t = (pp[0].x - rayLoc.x) / rayDir.x; |
---|
| 406 | else |
---|
| 407 | t = (pp[1].x - rayLoc.x) / rayDir.x; |
---|
| 408 | if (t < interval_min) |
---|
| 409 | interval_min = t; |
---|
| 410 | assert(pp[1].y >= pp[0].y); |
---|
| 411 | if (rayDir.y > 0) |
---|
| 412 | t = (pp[0].y - rayLoc.y) / rayDir.y; |
---|
| 413 | else |
---|
| 414 | t = (pp[1].y - rayLoc.y) / rayDir.y; |
---|
| 415 | if (t < interval_min) |
---|
| 416 | interval_min = t; |
---|
| 417 | assert(pp[1].z >= pp[0].z); |
---|
| 418 | if (rayDir.z > 0) |
---|
| 419 | t = (pp[0].z - rayLoc.z) / rayDir.z; |
---|
| 420 | else |
---|
| 421 | t = (pp[1].z - rayLoc.z) / rayDir.z; |
---|
| 422 | if (t < interval_min) |
---|
| 423 | interval_min = t; |
---|
| 424 | } |
---|
| 425 | #endif |
---|
| 426 | |
---|
| 427 | } |
---|
| 428 | |
---|
| 429 | #endif // __SBBOX_H__ |
---|