Main Page   Modules   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Containment.h

Go to the documentation of this file.
00001 /************************************************************** ggt-head beg
00002  *
00003  * GGT: Generic Graphics Toolkit
00004  *
00005  * Original Authors:
00006  *   Allen Bierbaum
00007  *
00008  * -----------------------------------------------------------------
00009  * File:          $RCSfile: Containment.h,v $
00010  * Date modified: $Date: 2003/01/14 20:51:25 $
00011  * Version:       $Revision: 1.14 $
00012  * -----------------------------------------------------------------
00013  *
00014  *********************************************************** ggt-head end */
00015 /*************************************************************** ggt-cpr beg
00016 *
00017 * GGT: The Generic Graphics Toolkit
00018 * Copyright (C) 2001,2002 Allen Bierbaum
00019 *
00020 * This library is free software; you can redistribute it and/or
00021 * modify it under the terms of the GNU Lesser General Public
00022 * License as published by the Free Software Foundation; either
00023 * version 2.1 of the License, or (at your option) any later version.
00024 *
00025 * This library is distributed in the hope that it will be useful,
00026 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00028 * Lesser General Public License for more details.
00029 *
00030 * You should have received a copy of the GNU Lesser General Public
00031 * License along with this library; if not, write to the Free Software
00032 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00033 *
00034  ************************************************************ ggt-cpr end */
00035 #ifndef _GMTL_CONTAINMENT_H_
00036 #define _GMTL_CONTAINMENT_H_
00037 
00038 // new stuff
00039 #include <vector>
00040 #include <gmtl/Sphere.h>
00041 #include <gmtl/AABox.h>
00042 #include <gmtl/VecOps.h>
00043 
00044 // old stuff
00045 //#include <gmtl/OOBox.h>
00046 //#include <gmtl/AABox.h>
00047 //#include <gmtl/Fit/GaussPointsFit.h>
00048 //#include <gmtl/matVecFuncs.h>
00049 //#include <gmtl/Quat.h>
00050 
00051 namespace gmtl
00052 {
00053 
00054 //-----------------------------------------------------------------------------
00055 // Sphere
00056 //-----------------------------------------------------------------------------
00057 
00067 template< class DATA_TYPE >
00068 bool isInVolume( const Sphere<DATA_TYPE>& container,
00069                  const Point<DATA_TYPE, 3>& pt )
00070 {
00071    // The point is inside the sphere if the vector computed from the center of
00072    // the sphere to the point has a magnitude less than or equal to the radius
00073    // of the sphere.
00074    // |pt - center| <= radius
00075    return ( length(pt - container.mCenter) <= container.mRadius );
00076 }
00077 
00087 template< class DATA_TYPE >
00088 bool isInVolume( const Sphere<DATA_TYPE>& container,
00089                  const Sphere<DATA_TYPE>& sphere )
00090 {
00091    // the sphere is inside container if the distance between the centers of the
00092    // spheres plus the radius of the inner sphere is less than or equal to the
00093    // radius of the containing sphere.
00094    // |sphere.center - container.center| + sphere.radius <= container.radius
00095    return ( length(sphere.mCenter - container.mCenter) + sphere.mRadius
00096             <= container.mRadius );
00097 }
00098 
00105 template< class DATA_TYPE >
00106 void extendVolume( Sphere<DATA_TYPE>& container,
00107                    const Point<DATA_TYPE, 3>& pt )
00108 {
00109    // check if we already contain the point
00110    if ( isInVolume( container, pt ) )
00111    {
00112       return;
00113    }
00114 
00115    // make a vector pointing from the center of the sphere to pt. this is the
00116    // direction in which we need to move the sphere's center
00117    Vec<DATA_TYPE, 3> dir = pt - container.mCenter;
00118    DATA_TYPE len = normalize( dir );
00119 
00120    // compute what the new radius should be
00121    DATA_TYPE newRadius =  (len + container.mRadius) * DATA_TYPE(0.5);
00122 
00123    // compute the new center for the sphere
00124    Point<DATA_TYPE, 3> newCenter = container.mCenter +
00125                                    (dir * (newRadius - container.mRadius));
00126 
00127    // modify container to its new values
00128    container.mCenter = newCenter;
00129    container.mRadius = newRadius;
00130 }
00131 
00138 template< class DATA_TYPE >
00139 void extendVolume( Sphere<DATA_TYPE>& container,
00140                    const Sphere<DATA_TYPE>& sphere )
00141 {
00142    // check if we already contain the sphere
00143    if ( isInVolume( container, sphere ) )
00144    {
00145       return;
00146    }
00147 
00148    // make a vector pointing from the center of container to sphere. this is the
00149    // direction in which we need to move container's center
00150    Vec<DATA_TYPE, 3> dir = sphere.mCenter - container.mCenter;
00151    DATA_TYPE len = normalize( dir );
00152 
00153    // compute what the new radius should be
00154    DATA_TYPE newRadius = (len + sphere.mRadius + container.mRadius) *
00155                          DATA_TYPE(0.5);
00156 
00157    // compute the new center for container
00158    Point<DATA_TYPE, 3> newCenter = container.mCenter +
00159                                    (dir * (newRadius - container.mRadius));
00160 
00161    // modify container to its new values
00162    container.mCenter = newCenter;
00163    container.mRadius = newRadius;
00164 }
00165 
00176 template< class DATA_TYPE >
00177 void makeVolume( Sphere<DATA_TYPE>& container,
00178                  const std::vector< Point<DATA_TYPE, 3> >& pts )
00179 {
00180    gmtlASSERT( pts.size() > 0  && "pts must contain at least 1 point" );
00181 
00182    // Implementation based on the Sphere Centered at Average of Points algorithm
00183    // found in "3D Game Engine Design" by Devud G, Eberly (pg. 27)
00184    typename std::vector< Point<DATA_TYPE, 3> >::const_iterator itr = pts.begin();
00185 
00186    // compute the average of the points as the center
00187    Point<DATA_TYPE, 3> sum = *itr;
00188    ++itr;
00189    while ( itr != pts.end() )
00190    {
00191       sum += *itr;
00192       ++itr;
00193    }
00194    container.mCenter = sum / pts.size();
00195 
00196    // compute the distance from the computed center to point furthest from that
00197    // center as the radius
00198    DATA_TYPE radiusSqr(0);
00199    for ( itr = pts.begin(); itr != pts.end(); ++itr )
00200    {
00201       float len = lengthSquared( *itr - container.mCenter );
00202       if ( len > radiusSqr )
00203          radiusSqr = len;
00204    }
00205 
00206    container.mRadius = Math::sqrt( radiusSqr );
00207 }
00208 
00209 /*
00210 template< class DATA_TYPE >
00211 void makeVolume( Sphere<DATA_TYPE>& container,
00212                  const std::vector< Point<DATA_TYPE, 3> >& pts )
00213 {
00214    gmtlASSERT( pts.size() > 1  && "pts must contain at least 2 points" );
00215 
00216    // make a sphere around the first 2 points and then extend the sphere by each
00217    // point thereafter. we could probably be smarter about this ...
00218    std::vector< Point<DATA_TYPE, 3> >::const_iterator itr = pts.begin();
00219 
00220    // make the initial sphere
00221    const Point<DATA_TYPE, 3>& first = *itr;
00222    ++itr;
00223    const Point<DATA_TYPE, 3>& second = *itr;
00224    ++itr;
00225    const Vec<DATA_TYPE, 3> dir = second - first;
00226    container.mRadius = length(dir) * DATA_TYPE(0.5);
00227    container.mCenter = first + (dir * container.mRadius);
00228 
00229    // iterate through the remaining points and extend the container to fit each
00230    // point. yay code reuse!
00231    while ( itr != pts.end() )
00232    {
00233       extendVolume( container, *itr );
00234       ++itr;
00235    }
00236 }
00237 */
00248 /*
00249 template< class DATA_TYPE >
00250 void makeVolume( Sphere<DATA_TYPE>& container,
00251                  const std::vector< Sphere<DATA_TYPE> >& spheres )
00252 {
00253    gmtlASSERT( spheres.size() > 1  && "spheres must contain at least 2 points" );
00254 
00255    // make a sphere around the first 2 points and then extend the sphere by each
00256    // point thereafter. we could probably be smarter about this ...
00257    std::vector< Sphere<DATA_TYPE> >::const_iterator itr = spheres.begin();
00258 
00259    // make the initial sphere
00260    const Sphere<DATA_TYPE>& first = *itr;
00261    ++itr;
00262    const Sphere<DATA_TYPE>& second = *itr;
00263    ++itr;
00264    const Vec<DATA_TYPE, 3> dir = second.mCenter - first.mCenter;
00265    container.mRadius = (length(dir) + first.mRadius + second.mRadius) *
00266                        DATA_TYPE(0.5);
00267    container.mCenter = first.mCenter +
00268                        (dir * (container.mRadius - first.mRadius));
00269 
00270    // iterate through the remaining points and extend the container to fit each
00271    // point. yay code reuse!
00272    while ( itr != spheres.end() )
00273    {
00274       extendVolume( container, *itr );
00275       ++itr;
00276    }
00277 }
00278 */
00288 template< class DATA_TYPE >
00289 bool isOnVolume( const Sphere<DATA_TYPE>& container,
00290                  const Point<DATA_TYPE, 3>& pt )
00291 {
00292    // |center - pt| - radius == 0
00293    return ( length(container.mCenter - pt) - container.mRadius == 0 );
00294 }
00295 
00306 template< class DATA_TYPE >
00307 bool isOnVolume( const Sphere<DATA_TYPE>& container,
00308                  const Point<DATA_TYPE, 3>& pt,
00309                  const DATA_TYPE& tol )
00310 {
00311    gmtlASSERT( tol >= 0 && "tolerance must be positive" );
00312 
00313    // abs( |center-pt| - radius ) < tol
00314    return ( Math::abs( length(container.mCenter - pt) - container.mRadius )
00315             <= tol );
00316 }
00317 
00318 //-----------------------------------------------------------------------------
00319 // AABox
00320 //-----------------------------------------------------------------------------
00321 
00331 template< class DATA_TYPE >
00332 bool isInVolume(const AABox<DATA_TYPE>& container,
00333                 const Point<DATA_TYPE, 3>& pt)
00334 {
00335    if (! container.isEmpty())
00336    {
00337       return ( pt[0] >= container.mMin[0] &&
00338                pt[1] >= container.mMin[1] &&
00339                pt[2] >= container.mMin[2] &&
00340                pt[0] <= container.mMax[0] &&
00341                pt[1] <= container.mMax[1] &&
00342                pt[2] <= container.mMax[2]);
00343    }
00344    else
00345    {
00346       return false;
00347    }
00348 }
00349 
00359 template< class DATA_TYPE >
00360 bool isInVolume(const AABox<DATA_TYPE>& container,
00361                 const AABox<DATA_TYPE>& box)
00362 {
00363    // Empty boxes don't overlap
00364    if (container.isEmpty() || box.isEmpty())
00365    {
00366       return false;
00367    }
00368 
00369    // Test that the boxes are not overlapping on any axis
00370    if (container.mMax[0] < box.mMin[0] || container.mMin[0] > box.mMax[0] ||
00371        container.mMax[1] < box.mMin[1] || container.mMin[1] > box.mMax[1] ||
00372        container.mMax[2] < box.mMin[2] || container.mMin[2] > box.mMax[2])
00373    {
00374       return false;
00375    }
00376    else
00377    {
00378       return true;
00379    }
00380 }
00381 
00388 template< class DATA_TYPE >
00389 void extendVolume(AABox<DATA_TYPE>& container,
00390                   const Point<DATA_TYPE, 3>& pt)
00391 {
00392    if (! container.isEmpty())
00393    {
00394       // X coord
00395       if (pt[0] > container.mMax[0])
00396       {
00397          container.mMax[0] = pt[0];
00398       }
00399       else if (pt[0] < container.mMin[0])
00400       {
00401          container.mMin[0] = pt[0];
00402       }
00403 
00404       // Y coord
00405       if (pt[1] > container.mMax[1])
00406       {
00407          container.mMax[1] = pt[1];
00408       }
00409       else if (pt[1] < container.mMin[1])
00410       {
00411          container.mMin[1] = pt[1];
00412       }
00413 
00414       // Z coord
00415       if (pt[2] > container.mMax[2])
00416       {
00417          container.mMax[2] = pt[2];
00418       }
00419       else if (pt[2] < container.mMin[2])
00420       {
00421          container.mMin[2] = pt[2];
00422       }
00423    }
00424    else
00425    {
00426       // Make a box with essentially zero volume at the point
00427       container.setMin(pt);
00428       container.setMax(pt);
00429       container.setEmpty(false);
00430    }
00431 }
00432 
00439 template< class DATA_TYPE >
00440 void extendVolume(AABox<DATA_TYPE>& container,
00441                   const AABox<DATA_TYPE>& box)
00442 {
00443    // Can't extend by an empty box
00444    if (box.isEmpty())
00445    {
00446       return;
00447    }
00448 
00449    // An empty container is extended to be the box
00450    if (container.isEmpty())
00451    {
00452       container = box;
00453    }
00454 
00455    // Just extend by the corners of the box
00456    extendVolume(container, box.getMin());
00457    extendVolume(container, box.getMax());
00458 }
00459 
00465 template< class DATA_TYPE >
00466 void makeVolume(AABox<DATA_TYPE>& box, const Sphere<DATA_TYPE>& sph)
00467 {
00468    const gmtl::Point<DATA_TYPE, 3>& center = sph.getCenter();
00469    const DATA_TYPE& radius = sph.getRadius();
00470 
00471    // Calculate the min and max points for the box
00472    gmtl::Point<DATA_TYPE, 3> min_pt(center[0] - radius,
00473                                     center[1] - radius,
00474                                     center[2] - radius);
00475    gmtl::Point<DATA_TYPE, 3> max_pt(center[0] + radius,
00476                                     center[1] + radius,
00477                                     center[2] + radius);
00478 
00479    box.setMin(min_pt);
00480    box.setMax(max_pt);
00481    box.setEmpty(radius == DATA_TYPE(0));
00482 }
00483 
00484 /*
00485 //------------------------------------------------------------------------------
00486 // Begin old GMTL code
00487 //------------------------------------------------------------------------------
00488 inline void computeContainment( AABox& box, const std::vector<gmtl::Point3>& points,
00489                          Point3& minPt, Point3& maxPt )
00490 //void MgcContAlignedBox (int iQuantity, const MgcVector3* akPoint,
00491 //    MgcVector3& rkMin, MgcVector3& rkMax)
00492 {
00493    if (points.empty())
00494       return;
00495 
00496    minPt = points[0];
00497    maxPt = minPt;
00498 
00499    for (unsigned i = 1; i < points.size(); i++)
00500    {
00501       if ( points[i][Xelt] < minPt[Xelt] )
00502          minPt[Xelt] = points[i][Xelt];
00503       else if ( points[i][Xelt] > maxPt[Xelt] )
00504          maxPt[Xelt] = points[i][Xelt];
00505 
00506       if ( points[i][Yelt] < minPt[Yelt] )
00507          minPt[Yelt] = points[i][Yelt];
00508       else if ( points[i][Yelt] > maxPt[Yelt] )
00509          maxPt[Yelt] = points[i][Yelt];
00510 
00511       if ( points[i][Zelt] < minPt[Zelt] )
00512          minPt[Zelt] = points[i][Zelt];
00513       else if ( points[i][Zelt] > maxPt[Zelt] )
00514          maxPt[Zelt] = points[i][Zelt];
00515    }
00516 
00517    // Now update the box
00518    box.makeEmpty();
00519    box.mMax = maxPt;
00520    box.mMin = minPt;
00521 }
00522 //----------------------------------------------------------------------------
00523 //----------------------------------------------------------------------------
00524 //MgcBox3 MgcContOrientedBox (int iQuantity, const MgcVector3* akPoint)
00525 inline void computeContainment( OOBox& box, const std::vector<gmtl::Point3>& points)
00526 {
00527     //MgcGaussPointsFit(iQuantity,akPoint,kBox.Center(),kBox.Axes(),
00528     //    kBox.Extents());
00529 
00530     gmtl::GaussPointsFit(points.size(), &points[0], box.center(), box.axes(), box.halfLens());
00531 
00532     // Let C be the box center and let U0, U1, and U2 be the box axes.  Each
00533     // input point is of the form X = C + y0*U0 + y1*U1 + y2*U2.  The
00534     // following code computes min(y0), max(y0), min(y1), max(y1), min(y2),
00535     // and max(y2).  The box center is then adjusted to be
00536     //   C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 +
00537     //        0.5*(min(y2)+max(y2))*U2
00538 #ifdef _DEBUG
00539    gmtl::OOBox box_test;
00540    box_test = box;
00541    gmtl::Vec3 ax0 = box_test.axis(0);
00542    gmtl::Vec3 ax1 = box_test.axis(1);
00543    gmtl::Vec3 ax2 = box_test.axis(2);
00544 #endif
00545 
00546     gmtlASSERT(box.axis(0).isNormalized());
00547     gmtlASSERT(box.axis(1).isNormalized());
00548     gmtlASSERT(box.axis(2).isNormalized());
00549 
00550     // XXX: Sign is sometimes wrong here
00551     // This is hack code to make it "work right"
00552     Vec3 cross;
00553     cross = box.axis(0).cross(box.axis(1));
00554     cross.normalize();
00555     box.axis(2) = cross;
00556 
00557     Vec3 kDiff = points[0] - box.center();
00558     float fY0Min = kDiff.dot(box.axis(0)), fY0Max = fY0Min;
00559     float fY1Min = kDiff.dot(box.axis(1)), fY1Max = fY1Min;
00560     float fY2Min = kDiff.dot(box.axis(2)), fY2Max = fY2Min;
00561 
00562     float fY0, fY1, fY2;
00563 
00564     for (unsigned i = 1; i < points.size(); i++)
00565     {
00566         kDiff = points[i] - box.center();
00567 
00568         fY0 = kDiff.dot(box.axis(0));
00569         if ( fY0 < fY0Min )
00570             fY0Min = fY0;
00571         else if ( fY0 > fY0Max )
00572             fY0Max = fY0;
00573 
00574         fY1 = kDiff.dot(box.axis(1));
00575         if ( fY1 < fY1Min )
00576             fY1Min = fY1;
00577         else if ( fY1 > fY1Max )
00578             fY1Max = fY1;
00579 
00580         fY2 = kDiff.dot(box.axis(2));
00581         if ( fY2 < fY2Min )
00582             fY2Min = fY2;
00583         else if ( fY2 > fY2Max )
00584             fY2Max = fY2;
00585     }
00586 
00587     box.center() += (0.5*(fY0Min+fY0Max))*box.axis(0) +
00588                     (0.5*(fY1Min+fY1Max))*box.axis(1) +
00589                     (0.5*(fY2Min+fY2Max))*box.axis(2);
00590 
00591     box.halfLen(0) = 0.5*(fY0Max - fY0Min);
00592     box.halfLen(1) = 0.5*(fY1Max - fY1Min);
00593     box.halfLen(2) = 0.5*(fY2Max - fY2Min);
00594 }
00595 
00596 */
00597 /*
00598 inline void computeContainment (OOBox& out_box, const OOBox& box0, const OOBox& box1, bool fast=true)
00599 {
00600    gmtl::OOBox ret_box;    // The resulting box
00601 
00602    if (fast)
00603    {
00604       ret_box.center() = 0.5*(box0.center() + box1.center());       // Center at average
00605 
00606       // Average the quats to get a new orientation
00607       Quat quat0, quat1;
00608       quat0.makeAxes(box0.axis(0), box0.axis(1), box0.axis(2));
00609       quat1.makeAxes(box1.axis(0), box1.axis(1), box1.axis(2));
00610       if ( quat0.dot(quat1) < 0.0 )
00611          quat1 = -quat1;
00612 
00613       Quat full_quat = quat0 + quat1;
00614 
00615       //float inv_len = 1.0/Math::sqrt(full_quat.norm());
00616       //full_quat = inv_len*full_quat;
00617       full_quat.normalize();
00618       full_quat.getAxes(ret_box.axis(0), ret_box.axis(1), ret_box.axis(2));
00619 
00620       // Now that we have new orientation, extend half lens to cover the volume
00621       //
00622       unsigned i, j;
00623       Point3 verts[8];
00624       Vec3 diff;
00625       float aDot;
00626 
00627       ret_box.halfLen(0) = 0.0;
00628       ret_box.halfLen(1) = 0.0;
00629       ret_box.halfLen(2) = 0.0;
00630 
00631       box0.getVerts(verts);
00632       for (i = 0; i < 8; i++)
00633       {
00634          diff = verts[i] - ret_box.center();
00635          for (j = 0; j < 3; j++)                       // For each axis of box0
00636          {
00637             aDot = Math::abs(diff.dot(ret_box.axis(j)));
00638             if ( aDot > ret_box.halfLen(j) )
00639                ret_box.halfLen(j) = aDot;
00640          }
00641       }
00642 
00643       box1.getVerts(verts);
00644       for (i = 0; i < 8; i++)
00645       {
00646          diff = verts[i] - ret_box.center();
00647          for (j = 0; j < 3; j++)
00648          {
00649             aDot = Math::abs(diff.dot(ret_box.axis(j)));
00650             if ( aDot > ret_box.halfLen(j) )
00651                ret_box.halfLen(j) = aDot;
00652          }
00653       }
00654    }
00655    else     // Tighter fit
00656    {
00657       // Hack that will do it correctly, but is slow
00658       Point3 verts[8];
00659       std::vector<gmtl::Point3> vert_points;
00660 
00661       box0.getVerts(verts);
00662       for (unsigned i=0;i<8;i++) vert_points.push_back(verts[i]);
00663       box1.getVerts(verts);
00664       for (unsigned i=0;i<8;i++) vert_points.push_back(verts[i]);
00665 
00666       computeContainment(ret_box, vert_points);
00667    }
00668 
00669    out_box = ret_box;
00670 }
00671 */
00672 
00673 
00674 }
00675 
00676 #endif

Generated on Mon Apr 7 15:28:54 2003 for GenericMathTemplateLibrary by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002