Simbody  3.4 (development)
Geo_Box.h
Go to the documentation of this file.
00001 #ifndef SimTK_SIMMATH_GEO_BOX_H_
00002 #define SimTK_SIMMATH_GEO_BOX_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                        Simbody(tm): SimTKmath                              *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK biosimulation toolkit originating from           *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
00011  *                                                                            *
00012  * Portions copyright (c) 2011-12 Stanford University and the Authors.        *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
00017  * not use this file except in compliance with the License. You may obtain a  *
00018  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
00019  *                                                                            *
00020  * Unless required by applicable law or agreed to in writing, software        *
00021  * distributed under the License is distributed on an "AS IS" BASIS,          *
00022  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
00023  * See the License for the specific language governing permissions and        *
00024  * limitations under the License.                                             *
00025  * -------------------------------------------------------------------------- */
00026 
00030 #include "SimTKcommon.h"
00031 #include "simmath/internal/common.h"
00032 #include "simmath/internal/Geo.h"
00033 
00034 #include <cassert>
00035 #include <cmath>
00036 #include <algorithm>
00037 
00038 namespace SimTK {
00039 
00040 //==============================================================================
00041 //                                  GEO BOX
00042 //==============================================================================
00047 template <class P>
00048 class Geo::Box_ {
00049 typedef P               RealP;
00050 typedef Vec<3,P>        Vec3P;
00051 typedef Mat<3,3,P>      Mat33P;
00052 typedef Rotation_<P>    RotationP;
00053 typedef Transform_<P>    TransformP;
00054 
00055 public:
00057 Box_() {}
00060 Box_(const Vec3P& halfLengths) {setHalfLengths(halfLengths);} 
00061 
00064 Box_& setHalfLengths(const Vec3P& halfLengths) {
00065     SimTK_ERRCHK3(halfLengths >= 0, "Geo::Box_::setHalfLengths()",
00066         "Half lengths must be nonnegative; got %g,%g,%g.",
00067         (double)halfLengths[0],(double)halfLengths[1],(double)halfLengths[2]);
00068     h = halfLengths; 
00069     sortEdges();
00070     return *this; 
00071 }
00072 
00075 Box_& addToHalfLengths(const Vec3P& incr) {
00076     h += incr; 
00077     SimTK_ERRCHK3(h >= 0, "Geo::Box_::addToHalfLengths()",
00078         "Half lengths must be nonnegative but were %g,%g,%g after change.",
00079         (double)h[0],(double)h[1],(double)h[2]);
00080     sortEdges();
00081     return *this; 
00082 }
00083 
00086 const Vec3P& getHalfLengths() const {return h;}
00087 
00089 RealP getOrderedHalfLength(int i) const {
00090     SimTK_INDEXCHECK(i, 3, "Geo::Box_::getOrderedHalfLength()");
00091     return h[order[i]];
00092 }
00093 
00095 CoordinateAxis getOrderedAxis(int i) const {
00096     SimTK_INDEXCHECK(i, 3, "Geo::Box_::getOrderedAxis()");
00097     return CoordinateAxis(order[i]);
00098 }
00099 
00101 RealP findVolume() const {return 8*h[0]*h[1]*h[2];}
00104 RealP findArea() const {return 8*(h[0]*h[1] + h[0]*h[2] + h[1]*h[2]);}
00105 
00109 bool containsPoint(const Vec3P& pt) const {
00110     const Vec3P absPt = pt.abs(); // reflect to first quadrant
00111     return absPt <= h;
00112 }
00113 
00118 RealP findDistanceSqrToPoint(const Vec3P& pt) const {
00119     const Vec3P absPt = pt.abs(); // reflect to first quadrant
00120     RealP d2 = 0;
00121     if (absPt[0] > h[0]) d2 += square(absPt[0]-h[0]);
00122     if (absPt[1] > h[1]) d2 += square(absPt[1]-h[1]);
00123     if (absPt[2] > h[2]) d2 += square(absPt[2]-h[2]);
00124     return d2;
00125 }
00126 
00131 RealP findDistanceSqrToSphere(const Geo::Sphere_<P>& sphere) const {
00132     const Vec3P absCtr = sphere.getCenter().abs(); // reflect to first quadrant
00133     const Vec3P grow = h + sphere.getRadius(); // 3 flops
00134     RealP d2 = 0;
00135     if (absCtr[0] > grow[0]) d2 += square(absCtr[0]-grow[0]);
00136     if (absCtr[1] > grow[1]) d2 += square(absCtr[1]-grow[1]);
00137     if (absCtr[2] > grow[2]) d2 += square(absCtr[2]-grow[2]);
00138     return d2;
00139 }
00140 
00145 RealP findDistanceSqrToAlignedBox(const Geo::AlignedBox_<P>& aab) const {
00146     const Vec3P absCtr = aab.getCenter().abs(); // reflect to first quadrant
00147     const Vec3P grow = h + aab.getHalfLengths();
00148     RealP d2 = 0;
00149     if (absCtr[0] > grow[0]) d2 += square(absCtr[0]-grow[0]);
00150     if (absCtr[1] > grow[1]) d2 += square(absCtr[1]-grow[1]);
00151     if (absCtr[2] > grow[2]) d2 += square(absCtr[2]-grow[2]);
00152     return d2;
00153 }
00154 
00159 bool intersectsSphere(const Geo::Sphere_<P>& sphere) const {
00160     const Vec3P absCtr = sphere.getCenter().abs(); // reflect to first quadrant
00161     const RealP r = sphere.getRadius();
00162     if (absCtr[0] > h[0]+r) return false;
00163     if (absCtr[1] > h[1]+r) return false;
00164     if (absCtr[2] > h[2]+r) return false;
00165     return true;
00166 }
00167 
00172 bool intersectsAlignedBox(const Geo::AlignedBox_<P>& aab) const {
00173     const Vec3P absCtr = aab.getCenter().abs(); // reflect to first quadrant
00174     const Vec3P& aabh = aab.getHalfLengths();
00175     if (absCtr[0] > h[0]+aabh[0]) return false;
00176     if (absCtr[1] > h[1]+aabh[1]) return false;
00177     if (absCtr[2] > h[2]+aabh[2]) return false;
00178     return true;
00179 }
00180 
00189 SimTK_SIMMATH_EXPORT bool 
00190 intersectsOrientedBox(const Geo::OrientedBox_<P>& ob) const;
00191 
00199 SimTK_SIMMATH_EXPORT bool 
00200 mayIntersectOrientedBox(const Geo::OrientedBox_<P>& ob) const;
00201 
00202 
00203 private:
00204 // Call this whenever an edge length changes. Each axis will appear once.
00205 void sortEdges() {
00206     CoordinateAxis shortest = XAxis, longest = ZAxis; 
00207     if (h[YAxis] < h[shortest]) shortest=YAxis;
00208     if (h[ZAxis] < h[shortest]) shortest=ZAxis;
00209     if (h[XAxis] > h[longest])  longest=XAxis;
00210     if (h[YAxis] > h[longest])  longest=YAxis;
00211     order[0] = shortest; order[2] = longest; 
00212     order[1] = shortest.getThirdAxis(longest); // not shortest or longest
00213 }
00214 
00215 int intersectsOrientedBoxHelper(const OrientedBox_<P>& O,
00216                                 Mat33P&  absR_BO, 
00217                                 Vec3P&   absP_BO) const;
00218 
00219 Vec3P           h;         // half-dimensions of the box
00220 unsigned char   order[3];  // 0,1,2 reordered short to long
00221 };
00222 
00223 
00224 
00225 //==============================================================================
00226 //                              GEO ALIGNED BOX
00227 //==============================================================================
00231 template <class P>
00232 class SimTK_SIMMATH_EXPORT Geo::AlignedBox_ {
00233 typedef P               RealP;
00234 typedef Vec<3,RealP>    Vec3P;
00235 
00236 public:
00239 AlignedBox_() {}
00242 AlignedBox_(const Vec3P& center, const Geo::Box_<P>& box) 
00243 :   center(center), box(box) {} 
00246 AlignedBox_(const Vec3P& center, const Vec3P& halfLengths) 
00247 :   center(center), box(halfLengths) {} 
00248 
00250 AlignedBox_& setCenter(const Vec3P& center) 
00251 {   this->center=center; return *this; }
00252 
00254 AlignedBox_& setHalfLengths(const Vec3P& halfLengths) 
00255 {   box.setHalfLengths(halfLengths); return *this; }
00256 
00258 const Vec3P& getCenter() const {return center;}
00260 Vec3P& updCenter() {return center;}
00263 const Vec3P& getHalfLengths() const {return box.getHalfLengths();}
00264 // no updHalfLengths()
00265 const Box_<P>& getBox() const {return box;}
00266 Box_<P>& updBox() {return box;}
00267 
00271 bool containsPoint(const Vec3P& pt_F) const
00272 {   return box.containsPoint(pt_F - center); } // shift to box frame B
00273 
00281 AlignedBox_& stretchBoundary() {
00282     const RealP tol    = Geo::getDefaultTol<P>();
00283     const RealP maxdim = max(getCenter().abs());
00284     const RealP maxrad = max(getHalfLengths());
00285     const RealP scale  = std::max(maxdim, maxrad);
00286     const RealP incr   = std::max(scale*Geo::getEps<P>(), tol);
00287     box.addToHalfLengths(Vec3P(incr));
00288     return *this; 
00289 }
00290 
00291 private:
00292 Vec3P           center;
00293 Geo::Box_<P>    box;
00294 };
00295 
00296 
00297 //==============================================================================
00298 //                              GEO ORIENTED BOX
00299 //==============================================================================
00302 template <class P>
00303 class SimTK_SIMMATH_EXPORT Geo::OrientedBox_ {
00304 typedef P               RealP;
00305 typedef Vec<3,P>        Vec3P;
00306 typedef Rotation_<P>    RotationP;
00307 typedef Transform_<P>   TransformP;
00308 
00309 public:
00312 OrientedBox_() {}
00316 OrientedBox_(const TransformP& X_FB, const Geo::Box_<P>& box) 
00317 :   X_FB(X_FB), box(box) {} 
00320 OrientedBox_(const TransformP& X_FB, const Vec3P& halfLengths) 
00321 :   X_FB(X_FB), box(halfLengths) {} 
00322 
00323 
00325 OrientedBox_& setTransform(const TransformP& newX_FB) 
00326 {   X_FB=newX_FB; return *this; }
00327 
00329 OrientedBox_& setHalfLengths(const Vec3P& halfLengths) 
00330 {   box.setHalfLengths(halfLengths); return *this; }
00331 
00332 const Vec3P& getCenter() const {return X_FB.p();}
00333 Vec3P& updCenter() {return X_FB.updP();}
00334 const RotationP& getOrientation() const {return X_FB.R();}
00335 RotationP& updOrientation() {return X_FB.updR();}
00336 const TransformP& getTransform() const {return X_FB;}
00337 TransformP& updTransform() {return X_FB;}
00338 const Vec3P& getHalfLengths() const {return box.getHalfLengths();}
00339 // no updHalfLengths()
00340 const Box_<P>& getBox() const {return box;}
00341 Box_<P>& updBox() {return box;}
00342 
00343 
00347 bool containsPoint(const Vec3P& pt_F) const
00348 {   return box.containsPoint(~X_FB*pt_F); } // shift to box frame B
00349 
00357 OrientedBox_& stretchBoundary() {
00358     const RealP tol    = Geo::getDefaultTol<P>();
00359     const RealP maxdim = max(getCenter().abs());
00360     const RealP maxrad = max(getHalfLengths());
00361     const RealP scale  = std::max(maxdim, maxrad);
00362     const RealP incr   = std::max(scale*Geo::getEps<P>(), tol);
00363     box.addToHalfLengths(Vec3P(incr));
00364     return *this; 
00365 }
00366 
00367 private:
00368 TransformP      X_FB;
00369 Geo::Box_<P>    box;
00370 };
00371 
00372 
00373 } // namespace SimTK
00374 
00375 #endif // SimTK_SIMMATH_GEO_BOX_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines