geometry_3d.h

Go to the documentation of this file.
00001 /*
00002  * geometry_3d.h
00003  *
00004  * Copyright (C) 2006-2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * primitives for 3D geometry.
00032  */
00033 
00034 #ifndef WAVEPACKET_GEOMETRY_3D_H__
00035 #define WAVEPACKET_GEOMETRY_3D_H__
00036 
00037 // includes --------------------------------------------------------------------
00038 #include "common/common.h"
00039 
00040 #include <math.h>
00041 
00042 
00043 /// \ingroup geometry
00044 /*@{*/
00045 
00046 
00047 /// this enum can be used for some intersection/containment tests
00048 enum eContains {
00049         eContains_Fully         = 0x01,  ///< object A fully contains object B
00050         eContains_Partial       = 0x02,  ///< objects A and B intersect or overlap
00051         eContains_None          = 0x10,  ///< object A and B do not overlap at all
00052 
00053         // any sort of intersection
00054         eContains_HitMask       = 0x03,  ///< full or partial overlap
00055 
00056         // keep this last!
00057         eContains_Invalid       = 0
00058 };
00059 
00060 
00061 /// basic 3D point object.  Unlike 2D points, this is not a template.  It is
00062 /// expected that users of this class are modeling 3D space and needing only
00063 /// modest accuracy, hence floats.
00064 ///
00065 /// \b WARNING: the default constructor does NOT initialize the point to any
00066 /// particular value (such as <tt>(0, 0, 0)</tt> ).  This is by design, so people
00067 /// can allocate large point3d_t arrays without paying a construction cost.
00068 /// Just be aware that this code:
00069 /// \code
00070 ///    point3d_t p;
00071 /// \endcode
00072 /// means that the value of p is undefined, and is probably quite large and
00073 /// random.
00074 struct point3d_t {
00075         // constructors
00076         point3d_t(void) throw() { }
00077         point3d_t(IN float ix, IN float iy, IN float iz) throw() :
00078             x(ix), y(iy), z(iz) { }
00079 
00080         // manipulators
00081         void clear(void) throw() {
00082                         x = y = z = 0.0;
00083                 }
00084 
00085         void set(IN float ix, IN float iy, IN float iz) throw() {
00086                         x = ix;         y = iy;         z = iz;
00087                 }
00088 
00089         void dump(IN const char * title) const throw() {
00090                         DPRINTF("%s (%f, %f, %f)", title, x, y, z);
00091                 }
00092 
00093         void increment(IN const point3d_t& p) throw() {
00094                         x += p.x;
00095                         y += p.y;
00096                         z += p.z;
00097                 }
00098 
00099         void decrement(IN const point3d_t& p) throw() {
00100                         x -= p.x;
00101                         y -= p.y;
00102                         z -= p.z;
00103                 }
00104 
00105         void scale(IN float r) throw() {
00106                         x *= r;
00107                         y *= r;
00108                         z *= r;
00109                 }
00110 
00111         void operator *= (IN float r) throw() { this->scale(r); }
00112 
00113         void operator += (IN const point3d_t& p) throw() {
00114                         increment(p);
00115                 }
00116 
00117         void operator -= (IN const point3d_t& p) throw() {
00118                         decrement(p);
00119                 }
00120 
00121         point3d_t operator - (void) const throw() {
00122                         return point3d_t(-x, -y, -z);
00123                 }
00124 
00125         // data fields
00126         float   x;
00127         float   y;
00128         float   z;
00129 };
00130 
00131 
00132 // operations using points
00133 point3d_t operator * (IN const point3d_t& p, IN float r) throw();
00134 inline point3d_t operator * (IN float r, IN const point3d_t& p) throw() {
00135         return p * r;
00136 }
00137 
00138 inline point3d_t operator + (IN const point3d_t& p, IN const point3d_t& q) throw()
00139 {
00140         return point3d_t(p.x + q.x, p.y + q.y, p.z + q.z);
00141 }
00142 
00143 inline point3d_t operator - (IN const point3d_t& p, IN const point3d_t& q) throw()
00144 {
00145         return point3d_t(p.x - q.x, p.y - q.y, p.z - q.z);
00146 }
00147 
00148 /// get dot product of two points/vectors
00149 inline float dotProduct(IN const point3d_t& p, IN const point3d_t& q) throw()
00150 {
00151         return (p.x * q.x) + (p.y * q.y) + (p.z * q.z);
00152 }
00153 
00154 
00155 inline point3d_t
00156 crossProduct(IN const point3d_t& p, IN const point3d_t& q) throw()
00157 {
00158         point3d_t r;
00159         r.x = p.y * q.z - p.z * q.y;
00160         r.y = p.z * q.x - p.x * q.z;
00161         r.z = p.x * q.y - p.y * q.x;
00162         return r;
00163 }
00164 
00165 
00166 
00167 typedef point3d_t vector3d_t;
00168 
00169 
00170 /// standard 3D axis-aligned rectangle (also called axis-aligned bounding box,
00171 ///     AABB)
00172 struct rect3d_t {
00173         // public enum
00174         enum eConstants {
00175                 eMaxCorners     =  8,
00176                 eMaxEdges       = 12
00177         };
00178 
00179         // manipulators
00180         void clear(void) throw() {
00181                         x0 = y0 = z0 = x1 = y1 = z1 = 0.0;
00182                 }
00183 
00184         void dump(IN const char * title) const throw() {
00185                         DPRINTF("%s (%f, %f, %f) - (%f, %f, %f)",
00186                             title, x0, y0, z0, x1, y1, z1);
00187                 }
00188 
00189         bool isValid(void) const throw() {
00190                         return ((x1 >= x0) && (y1 >= y0) && (z1 >= z0));
00191                 }
00192 
00193         void validate(IN const char * msg = NULL) const throw() {
00194                         if (!this->isValid()) {
00195                                 this->dump("Invalid!");
00196                                 ASSERT(false, "rect validation failed: %s", msg);
00197                         }
00198                 }
00199 
00200         bool containsPoint(IN const point3d_t& p) const throw() {
00201                         return (p.x >= x0 && p.x <= x1 &&
00202                                 p.y >= y0 && p.y <= y1 &&
00203                                 p.z >= z0 && p.z <= z1);
00204                 }
00205 
00206         bool intersectsRect(IN const rect3d_t& r) const throw() {
00207                         if (r.x1 < x0 ||
00208                             r.x0 > x1 ||
00209                             r.y1 < y0 ||
00210                             r.y0 > y1 ||
00211                             r.z1 < z0 ||
00212                             r.z0 > z1)
00213                                 return false;
00214                         return true;
00215                 }
00216 
00217         bool containsRect(IN const rect3d_t& r) const throw() {
00218                         return (r.x0 >= x0 &&
00219                                 r.x1 <= x1 &&
00220                                 r.y0 >= y0 &&
00221                                 r.y1 <= y1 &&
00222                                 r.z0 >= z0 &&
00223                                 r.z1 <= z1);
00224                 }
00225 
00226         void expand(IN const rect3d_t& r) throw() {
00227                         this->validate();
00228                         r.validate();
00229                         if (r.x0 < x0)
00230                                 x0 = r.x0;
00231                         if (r.y0 < y0)
00232                                 y0 = r.y0;
00233                         if (r.z0 < z0)
00234                                 z0 = r.z0;
00235 
00236                         if (r.x1 > x1)
00237                                 x1 = r.x1;
00238                         if (r.y1 > y1)
00239                                 y1 = r.y1;
00240                         if (r.z1 > z1)
00241                                 z1 = r.z1;
00242                 }
00243 
00244         void inflate(IN float r) throw() {
00245                         x0 -= r;        x1 += r;
00246                         y0 -= r;        y1 += r;
00247                         z0 -= r;        z1 += r;
00248                 }
00249 
00250         void setToPoint(IN const point3d_t& p) throw() {
00251                         x0 = x1 = p.x;
00252                         y0 = y1 = p.y;
00253                         z0 = z1 = p.z;
00254                 }
00255 
00256         void includePoint(IN const point3d_t& p) throw() {
00257                         if (p.x < x0)
00258                                 x0 = p.x;
00259                         if (p.x > x1)
00260                                 x1 = p.x;
00261                         if (p.y < y0)
00262                                 y0 = p.y;
00263                         if (p.y > y1)
00264                                 y1 = p.y;
00265                         if (p.z < z0)
00266                                 z0 = p.z;
00267                         if (p.z > z1)
00268                                 z1 = p.z;
00269                 }
00270 
00271         void getBoundingRectForSphere(IN const point3d_t& center,
00272                                 IN float radius) throw() {
00273                         ASSERT(radius >= 0.0, "Bad radius: %f", radius);
00274                         x0 = center.x - radius;
00275                         x1 = center.x + radius;
00276                         y0 = center.y - radius;
00277                         y1 = center.y + radius;
00278                         z0 = center.z - radius;
00279                         z1 = center.z + radius;
00280                 }
00281 
00282         point3d_t getMidpoint(void) const throw() {
00283                         return point3d_t(0.5 * (x0 + x1),
00284                                          0.5 * (y0 + y1),
00285                                          0.5 * (z0 + z1));
00286                 }
00287 
00288         float getDiagonal(void) const throw() {
00289                         float dx = x1 - x0;
00290                         float dy = y1 - y0;
00291                         float dz = z1 - z0;
00292                         float d2 = (dx * dx) + (dy * dy) + (dz * dz);
00293                         return sqrt(d2);
00294                 }
00295 
00296         /// restricts the given point to be within the rectangle
00297         void restrictPoint(IO point3d_t& p) const throw() {
00298                         // this->validate();
00299                         if (p.x < x0)
00300                                 p.x = x0;
00301                         if (p.x > x1)
00302                                 p.x = x1;
00303                         if (p.y < y0)
00304                                 p.y = y0;
00305                         if (p.y > y1)
00306                                 p.y = y1;
00307                         if (p.z < z0)
00308                                 p.z = z0;
00309                         if (p.z > z1)
00310                                 p.z = z1;
00311                 }
00312 
00313         /// given an index 0 <= index <= eMaxCorners, returns the corner point
00314         point3d_t getCorner(IN int index) const throw();
00315 
00316         /// given an index 0 <= index <= eMaxEdges, returns the two edge
00317         ///     endpoints
00318         void getEdge(IN int index,
00319                                 OUT point3d_t& p0,
00320                                 OUT point3d_t& p1) const throw();
00321 
00322         void translate(IN const point3d_t& delta) throw() {
00323                         x0 += delta.x;
00324                         x1 += delta.x;
00325                         y0 += delta.y;
00326                         y1 += delta.y;
00327                         z0 += delta.z;
00328                         z1 += delta.z;
00329                 }
00330 
00331         // data fields
00332         float   x0;
00333         float   y0;
00334         float   z0;
00335         float   x1;
00336         float   y1;
00337         float   z1;
00338 };
00339 
00340 
00341 ////////////////////////////////////////////////////////////////////////////////
00342 //
00343 //      3d helper methods
00344 //
00345 ////////////////////////////////////////////////////////////////////////////////
00346 
00347 // normalize(v) -- normalizes vector, and returns reference to it
00348 const vector3d_t& normalize(IO vector3d_t& v) throw();
00349 
00350 static inline float
00351 getDistance2
00352 (
00353 IN const point3d_t& p0,
00354 IN const point3d_t& p1
00355 )
00356 throw()
00357 {
00358         float dx = p0.x - p1.x;
00359         float dy = p0.y - p1.y;
00360         float dz = p0.z - p1.z;
00361 
00362         return (dx * dx) + (dy * dy) + (dz * dz);
00363 }
00364 
00365 
00366 point3d_t readPoint(IN std::istream& stream);
00367 rect3d_t  readRect(IN std::istream& stream);
00368 
00369 void parsePoint3d(IO std::istream& stream, OUT point3d_t& p);
00370 void parseRect3d(IO std::istream& stream, OUT rect3d_t& r);
00371 
00372 void parsePoint3d(IN const char * string, OUT point3d_t& p);
00373 void parseRect3d(IN const char * string, OUT rect3d_t& r);
00374 
00375 #endif  // WAVEPACKET_GEOMETRY_3D_H__
00376