Simbody
3.4 (development)
|
00001 #ifndef SimTK_SIMMATH_GEO_CUBIC_BEZIER_CURVE_H_ 00002 #define SimTK_SIMMATH_GEO_CUBIC_BEZIER_CURVE_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 00031 #include "SimTKcommon.h" 00032 #include "simmath/internal/common.h" 00033 #include "simmath/internal/Geo.h" 00034 #include "simmath/internal/Geo_Point.h" 00035 #include "simmath/internal/Geo_Sphere.h" 00036 #include "simmath/internal/Geo_Box.h" 00037 00038 #include <cassert> 00039 #include <cmath> 00040 #include <algorithm> 00041 00042 namespace SimTK { 00043 00044 00045 //============================================================================== 00046 // GEO CUBIC BEZIER CURVE 00047 //============================================================================== 00136 template <class P> 00137 class Geo::CubicBezierCurve_ { 00138 typedef P RealP; 00139 typedef Vec<3,RealP> Vec3P; 00140 typedef UnitVec<P,1> UnitVec3P; 00141 typedef Rotation_<P> RotationP; 00142 typedef Transform_<P> TransformP; 00143 00144 public: 00146 CubicBezierCurve_() {} 00147 00150 template <int S> 00151 explicit CubicBezierCurve_(const Vec<4,Vec3P,S>& controlPoints) 00152 : B(controlPoints) {} 00153 00156 template <int S> 00157 explicit CubicBezierCurve_(const Row<4,Vec3P,S>& controlPoints) 00158 : B(controlPoints.positionalTranspose()) {} 00159 00162 const Vec<4,Vec3P>& getControlPoints() const {return B;} 00165 Vec<4,Vec3P> calcAlgebraicCoefficients() const {return calcAFromB(B);} 00168 Vec<4,Vec3P> calcHermiteCoefficients() const {return calcHFromB(B);} 00172 Vec3P evalP(RealP u) const {return evalPUsingB(B,u);} 00176 Vec3P evalPu(RealP u) const {return evalPuUsingB(B,u);} 00180 Vec3P evalPuu(RealP u) const {return evalPuuUsingB(B,u);} 00184 Vec3P evalPuuu(RealP u) const {return evalPuuuUsingB(B,u);} 00185 00189 RealP calcDsdu(RealP u) const {return evalPu(u).norm();} 00190 00194 UnitVec3P calcUnitTangent(RealP u) const { 00195 const Vec3P Pu=evalPu(u); // 15 flops 00196 return Geo::calcUnitTangent(Pu); // ~40 flops 00197 } 00198 00202 Vec3P calcCurvatureVector(RealP u) const { 00203 const Vec3P Pu=evalPu(u), Puu=evalPuu(u); // 25 flops 00204 return Geo::calcCurvatureVector(Pu,Puu); // ~30 flops 00205 } 00206 00210 RealP calcCurvatureSqr(RealP u) { 00211 const Vec3P Pu=evalPu(u), Puu=evalPuu(u); // 25 flops 00212 return Geo::calcCurvatureSqr(Pu,Puu); // ~30 flops 00213 } 00214 00221 RealP calcTorsion(RealP u) { 00222 const Vec3P Pu=evalPu(u), Puu=evalPuu(u), Puuu=evalPuuu(u); // 28 flops 00223 return Geo::calcTorsion(Pu,Puu,Puuu); 00224 } 00225 00226 00234 UnitVec3P calcUnitNormal(RealP u) const { 00235 const Vec3P Pu=evalPu(u), Puu=evalPuu(u); // 25 flops 00236 return Geo::calcUnitNormal(Pu,Puu); // ~80 flops 00237 } 00238 00248 RealP calcCurveFrame(RealP u, TransformP& X_FP) const { 00249 const Vec3P Pval=evalP(u), Pu=evalPu(u), Puu=evalPuu(u); // 45 flops 00250 return Geo::calcCurveFrame(Pval,Pu,Puu,X_FP); 00251 } 00252 00259 void split(RealP u, CubicBezierCurve_<P>& left, 00260 CubicBezierCurve_<P>& right) const { 00261 const RealP tol = getDefaultTol<RealP>(); 00262 SimTK_ERRCHK1(tol <= u && u <= 1-tol, "Geo::CubicBezierCurve::split()", 00263 "Can't split curve at parameter %g; it is either out of range or" 00264 " too close to an end point.", (double)u); 00265 00266 const RealP u1 = 1-u; 00267 const Vec3P p01 = u1*B[0] + u*B[1]; // 3x9 flops 00268 const Vec3P p12 = u1*B[1] + u*B[2]; 00269 const Vec3P p23 = u1*B[2] + u*B[3]; 00270 left.B[0] = B[0]; 00271 left.B[1] = p01; 00272 left.B[2] = u1*p01 + u*p12; // 3x3 flops 00273 00274 right.B[3] = B[3]; 00275 right.B[2] = p23; 00276 right.B[1] = u1*p12 + u*p23; 00277 left.B[3] = right.B[0] = u1*left.B[2] + u*right.B[1]; // 3x3 flops 00278 } 00279 00283 void bisect(CubicBezierCurve_<P>& left, 00284 CubicBezierCurve_<P>& right) const { 00285 const Vec3P p01 = (B[0] + B[1])/2; // 3x6 flops 00286 const Vec3P p12 = (B[1] + B[2])/2; 00287 const Vec3P p23 = (B[2] + B[3])/2; 00288 left.B[0] = B[0]; 00289 left.B[1] = p01; 00290 left.B[2] = (p01 + p12)/2; // 3x2 flops 00291 00292 right.B[3] = B[3]; 00293 right.B[2] = p23; 00294 right.B[1] = (p12 + p23)/2; 00295 left.B[3] = right.B[0] = (left.B[2] + right.B[1])/2; // 3x2 flops 00296 } 00297 00298 00303 Geo::Sphere_<P> calcBoundingSphere() const 00304 { return Geo::Point_<P>::calcBoundingSphere(B[0],B[1],B[2],B[3]); } 00305 00310 Geo::AlignedBox_<P> calcAxisAlignedBoundingBox() const 00311 { const ArrayViewConst_<Vec3P> points(&B[0], &B[0]+4); // no copy or heap use 00312 return Geo::Point_<P>::calcAxisAlignedBoundingBox(points); } 00313 00318 Geo::OrientedBox_<P> calcOrientedBoundingBox() const 00319 { const ArrayViewConst_<Vec3P> points(&B[0], &B[0]+4); // no copy or heap use 00320 return Geo::Point_<P>::calcOrientedBoundingBox(points); } 00321 00328 static Row<4,P> calcFb(RealP u) { 00329 const RealP u2 = u*u, u3 = u*u2; // powers of u 00330 const RealP u1 = 1-u, u12=u1*u1, u13=u1*u12; // powers of 1-u 00331 return Row<4,P>(u13, 3*u*u12, 3*u2*u1, u3); 00332 } 00333 00336 static Row<4,P> calcDFb(RealP u) { 00337 const RealP u6=6*u, u2 = u*u, u23 = 3*u2, u29 = 9*u2; 00338 return Row<4,P>(u6-u23-3, u29-12*u+3, u6-u29, u23); 00339 } 00340 00343 static Row<4,P> calcD2Fb(RealP u) { 00344 const RealP u6 = 6*u, u18 = 18*u; 00345 return Row<4,P>(6-u6, u18-12, 6-u18, u6); 00346 } 00347 00351 static Row<4,P> calcD3Fb(RealP u) { 00352 return Row<4,P>(-6, 18, -18, 6); 00353 } 00354 00358 template <int S> 00359 static Vec<4,Vec3P> calcAFromB(const Vec<4,Vec3P,S>& B) { 00360 const Vec3P& b0=B[0]; const Vec3P& b1=B[1]; // aliases for beauty 00361 const Vec3P& b2=B[2]; const Vec3P& b3=B[3]; 00362 return Vec<4,Vec3P>(b3-b0+3*(b1-b2), 3*(b0+b2)-6*b1, 3*(b1-b0), b0); 00363 } 00364 00368 template <int S> 00369 static Vec<4,Vec3P> calcBFromA(const Vec<4,Vec3P,S>& A) { 00370 const Vec3P& a3=A[0]; const Vec3P& a2=A[1]; // aliases for beauty 00371 const Vec3P& a1=A[2]; const Vec3P& a0=A[3]; 00372 return Vec<4,Vec3P>(a0, a1/3 + a0, (a2+2*a1)/3 + a0, a3+a2+a1+a0); 00373 } 00374 00378 template <int S> 00379 static Vec<4,Vec3P> calcHFromB(const Vec<4,Vec3P,S>& B) { 00380 const Vec3P& b0=B[0]; const Vec3P& b1=B[1]; // aliases for beauty 00381 const Vec3P& b2=B[2]; const Vec3P& b3=B[3]; 00382 return Vec<4,Vec3P>(b0, b3, 3*(b1-b0), 3*(b3-b2)); 00383 } 00384 00388 template <int S> 00389 static Vec<4,Vec3P> calcBFromH(const Vec<4,Vec3P,S>& H) { 00390 const Vec3P& h0= H[0]; const Vec3P& h1= H[1]; // aliases for beauty 00391 const Vec3P& hu0=H[2]; const Vec3P& hu1=H[3]; 00392 return Vec<4,Vec3P>(h0, h0 + hu0/3, h1 - hu1/3, h1); 00393 } 00394 00400 template <int S> 00401 static Vec3P evalPUsingB(const Vec<4,Vec3P,S>& B, RealP u) { 00402 return calcFb(u)*B; // 9 + 3*7 = 30 flops 00403 } 00409 template <int S> 00410 static Vec3P evalPuUsingB(const Vec<4,Vec3P,S>& B, RealP u) { 00411 return calcDFb(u)*B; // 10 + 3*7 = 31 flops 00412 } 00418 template <int S> 00419 static Vec3P evalPuuUsingB(const Vec<4,Vec3P,S>& B, RealP u) { 00420 return calcD2Fb(u)*B; // 5 + 3*7 = 26 flops 00421 } 00427 template <int S> 00428 static Vec3P evalPuuuUsingB(const Vec<4,Vec3P,S>& B, RealP u) { 00429 return calcD3Fb(u)*B; // 0 + 3*7 = 21 flops 00430 } 00435 static Mat<4,4,P> getMb() { 00436 return Mat<4,4,P>( -1, 3, -3, 1, 00437 3, -6, 3, 0, 00438 -3, 3, 0, 0, 00439 1, 0, 0, 0); 00440 } 00441 00446 template <int S> 00447 static Vec<4,P> multiplyByMb(const Vec<4,P,S>& b) { 00448 const RealP b0=b[0], b1=b[1], b2=b[2], b3=b[3]; 00449 return Vec<4,P>(3*(b1-b2)+b3-b0, 3*(b0+b2)-6*b1, 3*(b1-b0), b0); 00450 } 00451 00457 static Mat<4,4,P> getMbInv() { 00458 return Mat<4,4,P>( 0, 0, 0, 1, 00459 0, 0, P(1)/3, 1, 00460 0, P(1)/3, P(2)/3, 1, 00461 1, 1, 1, 1 ); 00462 } 00463 00468 template <int S> 00469 static Vec<4,P> multiplyByMbInv(const Vec<4,P,S>& b) { 00470 const RealP b0=b[0], b1=b[1], b2=b[2], b3=b[3]; 00471 return Vec<4,P>(b3, b2/3+b3, (b1+2*b2)/3+b3, b0+b1+b2+b3); 00472 } 00473 00481 static Mat<4,4,P> getMhInvMb() { 00482 return Mat<4,4,P>( 1, 0, 0, 0, 00483 0, 0, 0, 1, 00484 -3, 3, 0, 0, 00485 0, 0, -3, 3 ); 00486 } 00489 template <int S> 00490 static Vec<4,P> multiplyByMhInvMb(const Vec<4,P,S>& v) { 00491 const RealP v0=v[0], v1=v[1], v2=v[2], v3=v[3]; 00492 return Vec<4,P>(v0, v3, 3*(v1-v0), 3*(v3-v2)); 00493 } 00494 00503 static Mat<4,4,P> getMbInvMh() { 00504 return Mat<4,4,P>( 1, 0, 0, 0, 00505 1, 0, P(1)/3, 0, 00506 0, 1, 0, P(-1)/3, 00507 0, 1, 0, 0 ); 00508 } 00511 template <int S> 00512 static Vec<4,P> multiplyByMbInvMh(const Vec<4,P,S>& v) { 00513 const RealP v0=v[0], v1=v[1], v2=v[2], v3=v[3]; 00514 return Vec<4,P>(v0, v0+v2/3, v1-v3/3, v1); 00515 } 00518 private: 00519 Vec<4,Vec3P> B; 00520 }; 00521 00522 00523 00524 } // namespace SimTK 00525 00526 #endif // SimTK_SIMMATH_GEO_CUBIC_BEZIER_CURVE_H_