Simbody
3.4 (development)
|
00001 #ifndef SimTK_SIMMATH_GEO_H_ 00002 #define SimTK_SIMMATH_GEO_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 00033 #include <cassert> 00034 #include <cmath> 00035 #include <algorithm> 00036 00037 namespace SimTK { 00038 00039 //============================================================================== 00040 // GEO 00041 //============================================================================== 00053 class SimTK_SIMMATH_EXPORT Geo { 00054 public: 00055 template <class P> class Point_; 00056 template <class P> class Sphere_; 00057 template <class P> class LineSeg_; 00058 template <class P> class Line_; 00059 template <class P> class Plane_; 00060 template <class P> class Circle_; 00061 template <class P> class Box_; 00062 template <class P> class AlignedBox_; 00063 template <class P> class OrientedBox_; 00064 template <class P> class Triangle_; 00065 template <class P> class CubicHermiteCurve_; 00066 template <class P> class BicubicHermitePatch_; 00067 template <class P> class CubicBezierCurve_; 00068 template <class P> class BicubicBezierPatch_; 00069 00070 typedef Point_<Real> Point; 00071 typedef Sphere_<Real> Sphere; 00072 typedef LineSeg_<Real> LineSeg; 00073 typedef Line_<Real> Line; 00074 typedef Plane_<Real> Plane; 00075 typedef Circle_<Real> Circle; 00076 typedef Box_<Real> Box; 00077 typedef AlignedBox_<Real> AlignedBox; 00078 typedef OrientedBox_<Real> OrientedBox; 00079 typedef Triangle_<Real> Triangle; 00080 typedef CubicHermiteCurve_<Real> CubicHermiteCurve; 00081 typedef BicubicHermitePatch_<Real> BicubicHermitePatch; 00082 typedef CubicBezierCurve_<Real> CubicBezierCurve; 00083 typedef BicubicBezierPatch_<Real> BicubicBezierPatch; 00084 00115 template <class RealP, int S> static bool 00116 isCusp(const Vec<3,RealP,S>& Pu) 00117 { return Pu.normSqr() < getDefaultTolSqr<RealP>(); } 00118 00132 template <class RealP, int S> static bool 00133 isInflectionPoint(const Vec<3,RealP,S>& Pu, const Vec<3,RealP,S>& Puu) 00134 { return (Pu % Puu).normSqr() < getDefaultTolSqr<RealP>(); } 00135 00139 template <class RealP, int S> static UnitVec<RealP,1> 00140 calcUnitTangent(const Vec<3,RealP,S>& Pu) { 00141 const RealP dsdu = Pu.norm(); // ~25 flops 00142 SimTK_ERRCHK(dsdu >= getDefaultTol<RealP>(), 00143 "Geo::calcUnitTangent()", "Unit tangent undefined at a cusp."); 00144 00145 return UnitVec<RealP,1>(Pu/dsdu, true); // ~13 flops 00146 } 00147 00170 template <class RealP, int S> static Vec<3,RealP> 00171 calcCurvatureVector(const Vec<3,RealP,S>& Pu, const Vec<3,RealP,S>& Puu) { 00172 const RealP Pu2 = Pu.normSqr(); // (ds/du)^2, 5 flops 00173 SimTK_ERRCHK(Pu2 >= getDefaultTolSqr<RealP>(), 00174 "Geo::calcCurvatureVector()", "Curvature undefined at a cusp."); 00175 const RealP PuPuu = dot(Pu,Puu); 00176 const RealP uPrimeSqr = 1/Pu2; // ~10 flops 00177 const RealP u2Prime = -PuPuu * square(uPrimeSqr); // 8 flops 00178 return uPrimeSqr*Puu + u2Prime*Pu; // 9 flops 00179 } 00180 00191 template <class RealP, int S> static UnitVec<RealP,1> 00192 calcUnitNormal(const Vec<3,RealP,S>& Pu, const Vec<3,RealP,S>& Puu) { 00193 typedef UnitVec<RealP,1> UnitVec3P; 00194 00195 const RealP Pu2 = Pu.normSqr(); // (ds/du)^2, 5 flops 00196 SimTK_ERRCHK(Pu2 >= getDefaultTolSqr<RealP>(), 00197 "Geo::calcUnitNormal()", "The normal is undefined at a cusp."); 00198 00199 // Now check if we're at an inflection point, meaning |Pu X Puu|==0. 00200 // Use this handy identity from Struik eq. 3-9 to avoid calculating 00201 // the cross product: (Pu X Puu)^2 = Pu^2Puu^2 - (~Pu*Puu)^2 00202 const RealP Puu2 = Puu.normSqr(); // 5 flops 00203 const RealP PuPuu = dot(Pu,Puu); // 5 flops 00204 const RealP PuXPuu2 = Pu2*Puu2 - square(PuPuu); // 3 flops 00205 if (PuXPuu2 < getDefaultTolSqr<RealP>()) // 1 flop 00206 return UnitVec3P(Pu).perp(); 00207 // Calculate the curvature vector, negate, and normalize. 00208 const RealP uPrimeSqr = 1/Pu2; // ~10 flops 00209 const RealP u2Prime = -PuPuu * square(uPrimeSqr); // 3 flops 00210 const Vec<3,RealP> c = uPrimeSqr*Puu + u2Prime*Pu; // 9 flops 00211 return UnitVec3P(-c); // ~40 flops 00212 } 00213 00223 template <class RealP, int S> static RealP 00224 calcCurveFrame(const Vec<3,RealP,S>& P, 00225 const Vec<3,RealP,S>& Pu, 00226 const Vec<3,RealP,S>& Puu, 00227 Transform_<RealP>& X_FP) { 00228 typedef UnitVec<RealP,1> UnitVec3P; 00229 00230 const RealP Pu2 = Pu.normSqr(); // (ds/du)^2, 5 flops 00231 SimTK_ERRCHK(Pu2 >= getDefaultTolSqr<RealP>(), 00232 "Geo::calcCurveFrame()", "Curve frame is undefined at a cusp."); 00233 00234 // Set the point P(u) as the frame origin. 00235 X_FP.updP() = P; 00236 00237 // Calculate the unit tangent t, our y axis. 00238 const RealP uPrimeSqr = 1/Pu2; // ~10 flops 00239 const RealP uPrime = std::sqrt(uPrimeSqr); // ~20 flops 00240 const UnitVec3P t(uPrime*Pu, true); // 3 flops 00241 00242 // Next calculate unit normal n, our x axis. See calcUnitNormal() above 00243 // for theory. 00244 const RealP Puu2 = Puu.normSqr(); // 5 flops 00245 const RealP PuPuu = dot(Pu,Puu); // 5 flops 00246 const RealP PuXPuu2 = Pu2*Puu2 - square(PuPuu); // 3 flops 00247 UnitVec3P n; // unit normal 00248 RealP k; // curvature magnitude 00249 if (PuXPuu2 < getDefaultTolSqr<RealP>()) { // 1 flop 00250 k = 0; 00251 n = t.perp(); // arbitrary 00252 } else { 00253 // Calculate the curvature vector, negate, and normalize. 00254 const RealP u2Prime = -PuPuu * square(uPrimeSqr); // 8 flops 00255 const Vec<3,RealP> c = uPrimeSqr*Puu + u2Prime*Pu; // 9 flops 00256 k = c.norm(); // curvature >= 0, ~25 flops 00257 n = UnitVec3P((-1/k)*c, true); // ~13 flops 00258 } 00259 00260 // Finally calculate the binormal, our z axis. No need to normalize 00261 // here because n and t are perpendicular unit vectors. 00262 const UnitVec3P b(n % t, true); // 9 flops 00263 00264 // Construct the coordinate frame without normalizing. 00265 X_FP.updR().setRotationFromUnitVecsTrustMe(n,t,b); 00266 00267 return k; 00268 } 00269 00282 template <class RealP, int S> static RealP 00283 calcCurvatureSqr(const Vec<3,RealP,S>& Pu, const Vec<3,RealP,S>& Puu) { 00284 const RealP Pu2 = Pu.normSqr(); // (ds/du)^2, 5 flops 00285 SimTK_ERRCHK(Pu2 >= getDefaultTolSqr<RealP>(), 00286 "Geo::calcCurvatureSqr()", "Curvature is undefined at a cusp."); 00287 const RealP num = cross(Pu,Puu).normSqr(); // 14 flops 00288 const RealP den = cube(Pu2); // 2 flops 00289 return num/den; // ~10 flops 00290 } 00291 00305 template <class RealP, int S> static RealP 00306 calcTorsion(const Vec<3,RealP,S>& Pu, const Vec<3,RealP,S>& Puu, 00307 const Vec<3,RealP,S>& Puuu) { 00308 const Vec<3,RealP> PuXPuu = cross(Pu,Puu); // 9 flops 00309 const RealP PuXPuu2 = PuXPuu.normSqr(); // 5 flops 00310 SimTK_ERRCHK(PuXPuu2 >= getDefaultTolSqr<RealP>(), "Geo::calcTorsion()", 00311 "Torsion is undefined at a cusp or inflection point."); 00312 const RealP num = dot(PuXPuu, Puuu); // 5 flops 00313 return num/PuXPuu2; // ~10 flops 00314 } 00338 template <class RealP> static void 00339 findClosestPointsOfTwoLines 00340 (const Vec<3,RealP>& p0, const UnitVec<RealP,1>& d0, 00341 const Vec<3,RealP>& p1, const UnitVec<RealP,1>& d1, 00342 Vec<3,RealP>& x0, Vec<3,RealP>& x1, bool& linesAreParallel) 00343 { 00344 const Vec<3,RealP> w = p1-p0; // vector from p0 to p1; 3 flops 00345 const RealP s2Theta = (d0 % d1).normSqr(); // sin^2(angle); 14 flops 00346 const RealP d = dot(w,d0); // 5 flops 00347 const RealP e = -dot(w,d1); // 6 flops 00348 00349 RealP t0, t1; // line parameters of closest points 00350 if (s2Theta < square(NTraits<RealP>::getSignificant())) { // 3 flops 00351 // Lines are parallel. Return a point on each line midway between 00352 // the origin points. 00353 linesAreParallel = true; // parallel 00354 t0 = d/2; t1 = e/2; // 2 flops 00355 } else { 00356 linesAreParallel = false; 00357 const RealP cTheta = dot(d0,d1); // cos(angle between lines); 5 flops 00358 const RealP oos2Theta = 1/s2Theta; // about 10 flops 00359 t0 = (e*cTheta + d) * oos2Theta; // 3 flops 00360 t1 = (d*cTheta + e) * oos2Theta; // 3 flops 00361 } 00362 00363 x0 = p0 + t0*d0; // 6 flops 00364 x1 = p1 + t1*d1; // 6 flops 00365 } 00366 00376 template <class RealP> static RealP getDefaultTol() 00377 { return NTraits<RealP>::getSignificant(); } 00380 template <class RealP> static RealP getDefaultTolSqr() 00381 { return square(getDefaultTol<RealP>()); } 00382 00385 template <class RealP> static RealP getEps() 00386 { return NTraits<RealP>::getEps(); } 00388 template <class RealP> static RealP getNaN() 00389 { return NTraits<RealP>::getNaN(); } 00391 template <class RealP> static RealP getInfinity() 00392 { return NTraits<RealP>::getInfinity(); } 00393 00398 template <class RealP> static RealP stretchBy(RealP length, RealP tol) { 00399 SimTK_ERRCHK2(tol >= getEps<RealP>(), "Geo::stretchBy()", 00400 "The supplied tolerance %g is too small; must be at least %g" 00401 " for significance at this precision.", 00402 (double)tol, (double)getEps<RealP>()); 00403 00404 return length + std::max(length*tol, tol); 00405 } 00406 00409 template <class RealP> static RealP stretch(RealP length) 00410 { return stretchBy(length, getDefaultTol<RealP>()); } 00411 00414 }; 00415 00416 00417 } // namespace SimTK 00418 00419 #endif // SimTK_SIMMATH_GEO_H_