Simbody
3.4 (development)
|
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_