Simbody  3.4 (development)
Geo_BicubicBezierPatch.h
Go to the documentation of this file.
00001 #ifndef SimTK_SIMMATH_GEO_BICUBIC_BEZIER_PATCH_H_
00002 #define SimTK_SIMMATH_GEO_BICUBIC_BEZIER_PATCH_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_CubicBezierCurve.h"
00035 
00036 #include <cassert>
00037 #include <cmath>
00038 #include <algorithm>
00039 
00040 namespace SimTK {
00041 
00042 
00043 //==============================================================================
00044 //                         GEO BICUBIC BEZIER PATCH
00045 //==============================================================================
00100 template <class P>
00101 class Geo::BicubicBezierPatch_ {
00102 typedef P               RealP;
00103 typedef Vec<3,RealP>    Vec3P;
00104 
00105 public:
00107 BicubicBezierPatch_() {}
00108 
00113 explicit BicubicBezierPatch_(const Mat<4,4,Vec3P>& controlPoints) 
00114 :   B(controlPoints) {} 
00115 
00116 
00120 Vec3P evalP(RealP u, RealP w) const {return evalPUsingB(B,u,w);}
00121 
00125 void evalP1(RealP u, RealP w, Vec3P& Pu, Vec3P& Pw) const 
00126 {   return evalP1UsingB(B,u,w,Pu,Pw); }
00127 
00132 void evalP2(RealP u, RealP w, Vec3P& Puu, Vec3P& Puw, Vec3P& Pww) const 
00133 {   evalP2UsingB(B,u,w,Puu,Puw,Pww); }
00134 
00139 void evalP3(RealP u, RealP w, Vec3P& Puuu, Vec3P& Puuw, 
00140                               Vec3P& Puww, Vec3P& Pwww) const 
00141 {   evalP3UsingB(B,u,w,Puuu,Puuw,Puww,Pwww); }
00142 
00146 const Mat<4,4,Vec3P>& getControlPoints() const {return B;}
00150 Mat<4,4,Vec3P>& updControlPoints() {return B;}
00154 Mat<4,4,Vec3P> calcAlgebraicCoefficients() const {return calcAFromB(B);}
00158 Mat<4,4,Vec3P> calcHermiteCoefficients() const {return calcHFromB(B);}
00159 
00163 CubicBezierCurve_<P> getBoundaryCurveU0() const 
00164 {   return CubicBezierCurve_<P>(B[0]); } // b11 b12 b13 b14
00168 CubicBezierCurve_<P> getBoundaryCurveU1() const 
00169 {   return CubicBezierCurve_<P>(B[3]); } // b41 b42 b43 b44
00173 CubicBezierCurve_<P> getBoundaryCurveW0() const 
00174 {   return CubicBezierCurve_<P>(B(0)); } // b11 b21 b31 b41
00178 CubicBezierCurve_<P> getBoundaryCurveW1() const 
00179 {   return CubicBezierCurve_<P>(B(3)); } // b14 b24 b34 b44
00180 
00184 CubicBezierCurve_<P> calcIsoCurveU(RealP u0) const 
00185 {   return calcIsoCurveU(B, u0); }
00189 CubicBezierCurve_<P> calcIsoCurveW(RealP w0) const 
00190 {   return calcIsoCurveW(B, w0); }
00191 
00206 void splitU(RealP u, BicubicBezierPatch_<P>& patch0, 
00207                      BicubicBezierPatch_<P>& patch1) const {
00208     const RealP tol = getDefaultTol<RealP>();
00209     SimTK_ERRCHK1(tol <= u && u <= 1-tol, "Geo::BicubicBezierPatch::splitU()",
00210         "Can't split patch at parameter u=%g; it is either out of range or"
00211         " too close to an edge.", (double)u);
00212     CubicBezierCurve_<P> l,h;
00213     if (u==RealP(0.5)) // bisecting
00214         for (int i=0; i<4; ++i) {
00215             CubicBezierCurve_<P>(B(i)).bisect(l,h);
00216             patch0.B(i) = l.getControlPoints(); 
00217             patch1.B(i) = h.getControlPoints();
00218         }
00219     else 
00220         for (int i=0; i<4; ++i) {
00221             CubicBezierCurve_<P>(B(i)).split(u,l,h);
00222             patch0.B(i) = l.getControlPoints(); 
00223             patch1.B(i) = h.getControlPoints();
00224         }
00225 }
00226 
00241 void splitW(RealP w, BicubicBezierPatch_<P>& patch0, 
00242                      BicubicBezierPatch_<P>& patch1) const {
00243     const RealP tol = getDefaultTol<RealP>();
00244     SimTK_ERRCHK1(tol <= w && w <= 1-tol, "Geo::BicubicBezierPatch::splitW()",
00245         "Can't split patch at parameter w=%g; it is either out of range or"
00246         " too close to an edge.", (double)w);
00247     CubicBezierCurve_<P> l,h;
00248     if (w==RealP(0.5)) // bisecting
00249         for (int i=0; i<4; ++i) {
00250             CubicBezierCurve_<P>(B[i]).bisect(l,h);
00251             patch0.B[i] = l.getControlPoints().positionalTranspose(); 
00252             patch1.B[i] = h.getControlPoints().positionalTranspose();
00253         }
00254     else 
00255         for (int i=0; i<4; ++i) {
00256             CubicBezierCurve_<P>(B[i]).split(w,l,h);
00257             patch0.B[i] = l.getControlPoints().positionalTranspose(); 
00258             patch1.B[i] = h.getControlPoints().positionalTranspose();
00259         }
00260 }
00261 
00262 
00278 void split(RealP u, RealP w, BicubicBezierPatch_<P>& patch00, 
00279                              BicubicBezierPatch_<P>& patch01, 
00280                              BicubicBezierPatch_<P>& patch10, 
00281                              BicubicBezierPatch_<P>& patch11) const {
00282     const RealP tol = getDefaultTol<RealP>();
00283     SimTK_ERRCHK2((tol <= u && u <= 1-tol) && (tol <= w && w <= 1-tol), 
00284         "Geo::BicubicBezierPatch::split()",
00285         "Can't split patch at parametric point u,w=%g,%g; it is either out of"
00286         " range or too close to an edge.", (double)u, (double)w);
00287 
00288     BicubicBezierPatch_<P> patch0, patch1; // results of the first split
00289 
00290     // We split once along one direction, and then twice along the other, so
00291     // make sure the second direction is the cheap bisecting one.
00292     if (u == Real(0.5)) {
00293         splitW(w,patch0,patch1);            // 120 or 180 flops
00294         patch0.splitU(u, patch00, patch10); // 120 flops
00295         patch1.splitU(u, patch01, patch11); // 120 flops
00296     } else {
00297         splitU(u,patch0,patch1);            // 180 flops
00298         patch0.splitW(w, patch00, patch01); // 120 or 180 flops
00299         patch1.splitW(w, patch10, patch11); // 120 or 180 flops
00300     }
00301 }
00302 
00310 Geo::Sphere_<P> calcBoundingSphere() const 
00311 {   const ArrayViewConst_<Vec3P> points(&B(0,0), &B(0,0)+16); // no copy 
00312     return Geo::Point_<P>::calcBoundingSphere(points); }
00313 
00321 Geo::AlignedBox_<P> calcAxisAlignedBoundingBox() const 
00322 {   const ArrayViewConst_<Vec3P> points(&B(0,0), &B(0,0)+16); // no copy 
00323     return Geo::Point_<P>::calcAxisAlignedBoundingBox(points); }
00324 
00332 Geo::OrientedBox_<P> calcOrientedBoundingBox() const 
00333 {   const ArrayViewConst_<Vec3P> points(&B(0,0), &B(0,0)+16); // no copy 
00334     return Geo::Point_<P>::calcOrientedBoundingBox(points); }
00335 
00344 static Vec3P evalPUsingB(const Mat<4,4,Vec3P>& B, RealP u, RealP w) { 
00345     Row<4,P> Fbu = CubicBezierCurve_<P>::calcFb(u);     // 9 flops
00346     Row<4,P> Fbw = CubicBezierCurve_<P>::calcFb(w);     // 9 flops
00347     return Fbu * B * ~Fbw;                              // 3x35 flops
00348 }
00349 
00354 static void evalP1UsingB(const Mat<4,4,Vec3P>& B, RealP u, RealP w,
00355                          Vec3P& Pu, Vec3P& Pw) {
00356     Row<4,P> Fbu  = CubicBezierCurve_<P>::calcFb(u);     //  9 flops
00357     Row<4,P> Fbw  = CubicBezierCurve_<P>::calcFb(w);     //  9 flops
00358     Row<4,P> dFbu = CubicBezierCurve_<P>::calcDFb(u);    // 10 flops
00359     Row<4,P> dFbw = CubicBezierCurve_<P>::calcDFb(w);    // 10 flops
00360     Pu = dFbu * B * ~Fbw;                                // 3x35
00361     Pw = Fbu  * B * ~dFbw;                               // 3x35
00362 }
00363 
00368 static void evalP2UsingB(const Mat<4,4,Vec3P>& B, RealP u, RealP w,
00369                          Vec3P& Puu, Vec3P& Puw, Vec3P& Pww) {
00370     Row<4,P> Fbu   = CubicBezierCurve_<P>::calcFb(u);     //  9 flops
00371     Row<4,P> Fbw   = CubicBezierCurve_<P>::calcFb(w);     //  9 flops
00372     Row<4,P> dFbu  = CubicBezierCurve_<P>::calcDFb(u);    // 10 flops
00373     Row<4,P> dFbw  = CubicBezierCurve_<P>::calcDFb(w);    // 10 flops
00374     Row<4,P> d2Fbu = CubicBezierCurve_<P>::calcD2Fb(u);   //  5 flops
00375     Row<4,P> d2Fbw = CubicBezierCurve_<P>::calcD2Fb(w);   //  5 flops
00376     Puu = d2Fbu * B * ~Fbw;                               // 3x35
00377     Puw = dFbu  * B * ~dFbw;                              // 3x35
00378     Pww = Fbu   * B * ~d2Fbw;                             // 3x35
00379 }
00380 
00385 static void evalP3UsingB(const Mat<4,4,Vec3P>& B, RealP u, RealP w,
00386                          Vec3P& Puuu, Vec3P& Puuw, Vec3P& Puww, Vec3P& Pwww) {
00387     Row<4,P> Fbu   = CubicBezierCurve_<P>::calcFb(u);     //  9 flops
00388     Row<4,P> Fbw   = CubicBezierCurve_<P>::calcFb(w);     //  9 flops
00389     Row<4,P> dFbu  = CubicBezierCurve_<P>::calcDFb(u);    // 10 flops
00390     Row<4,P> dFbw  = CubicBezierCurve_<P>::calcDFb(w);    // 10 flops
00391     Row<4,P> d2Fbu = CubicBezierCurve_<P>::calcD2Fb(u);   //  5 flops
00392     Row<4,P> d2Fbw = CubicBezierCurve_<P>::calcD2Fb(w);   //  5 flops
00393     Row<4,P> d3Fbu = CubicBezierCurve_<P>::calcD3Fb(u);   //  0 
00394     Row<4,P> d3Fbw = CubicBezierCurve_<P>::calcD3Fb(w);   //  0
00395     Puuu = d3Fbu * B * ~Fbw;                              // 3x35
00396     Puuw = d2Fbu * B * ~dFbw;                             // 3x35
00397     Puww = dFbu  * B * ~d2Fbw;                            // 3x35
00398     Pwww = Fbu   * B * ~d3Fbw;                            // 3x35
00399 }
00400 
00404 static CubicBezierCurve_<P> 
00405 calcIsoCurveU(const Mat<4,4,Vec3P>& B, RealP u0) 
00406 {   const Row<4,Vec3P> Bu0 = CubicBezierCurve_<P>::calcFb(u0) * B;
00407     return CubicBezierCurve_<P>(Bu0); }
00408 
00412 static CubicBezierCurve_<P> 
00413 calcIsoCurveW(const Mat<4,4,Vec3P>& B, RealP w0)
00414 {    const Vec<4,Vec3P> Bw0 = B * ~CubicBezierCurve_<P>::calcFb(w0);
00415      return CubicBezierCurve_<P>(Bw0); }
00416 
00419 static Mat<4,4,Vec3P> calcAFromB(const Mat<4,4,Vec3P>& B) {
00420     typedef const Vec3P& Coef;
00421     Coef b11=B(0,0), b12=B(0,1), b13=B(0,2), b14=B(0,3), 
00422          b21=B(1,0), b22=B(1,1), b23=B(1,2), b24=B(1,3), 
00423          b31=B(2,0), b32=B(2,1), b33=B(2,2), b34=B(2,3), 
00424          b41=B(3,0), b42=B(3,1), b43=B(3,2), b44=B(3,3); 
00425     // First calculate Mb*B:
00426     //       a   b   c   d
00427     //       e   f   g   h
00428     //       p   q   r   s
00429     //      b11 b12 b13 b14
00430     Vec3P a= b41-b11+3*(b21-b31), b= b42-b12+3*(b22-b32),   // 3x16 flops
00431           c= b43-b13+3*(b23-b33), d= b44-b14+3*(b24-b34);
00432     Vec3P e= 3*(b11+b31)-6*b21,   f= 3*(b12+b32)-6*b22,     // 3x16 flops
00433           g= 3*(b13+b33)-6*b23,   h= 3*(b14+b34)-6*b24;
00434     Vec3P p= 3*(b21-b11),         q= 3*(b22-b12),           // 3x8 flops
00435           r= 3*(b23-b13),         s= 3*(b24-b14);
00436 
00437     // Then calculate (Mb*B)*~Mb. (3x40 more flops)
00438     return Mat<4,4,Vec3P>
00439        ( d-a+3*(b-c),          3*(a+c)-6*b,       3*(b-a),        a,
00440          h-e+3*(f-g),          3*(e+g)-6*f,       3*(f-e),        e,
00441          s-p+3*(q-r),          3*(p+r)-6*q,       3*(q-p),        p,
00442          b14-b11+3*(b12-b13),  3*(b11+b13)-6*b12, 3*(b12-b11),   b11 );
00443 }
00444 
00447 static Mat<4,4,Vec3P> calcBFromA(const Mat<4,4,Vec3P>& A) {
00448     typedef const Vec3P& Coef;
00449     Coef a33=A(0,0), a32=A(0,1), a31=A(0,2), a30=A(0,3), 
00450          a23=A(1,0), a22=A(1,1), a21=A(1,2), a20=A(1,3), 
00451          a13=A(2,0), a12=A(2,1), a11=A(2,2), a10=A(2,3), 
00452          a03=A(3,0), a02=A(3,1), a01=A(3,2), a00=A(3,3); 
00453     // First calculate Mb^-1*A:
00454     //      a03 a02 a01 a00
00455     //       a   b   c   d
00456     //       e   f   g   h
00457     //       p   q   r   s
00458     Vec3P a=a13/3+a03, b=a12/3+a02, c=a11/3+a01, d=a10/3+a00;   // 3x8 flops
00459     Vec3P e=(a23+2*a13)/3+a03, f=(a22+2*a12)/3+a02,             // 3x16 flops
00460           g=(a21+2*a11)/3+a01, h=(a20+2*a10)/3+a00;
00461     Vec3P p=a33+a23+a13+a03, q=a32+a22+a12+a02,                 // 3x12 flops
00462           r=a31+a21+a11+a01, s=a30+a20+a10+a00;
00463 
00464 
00465     // Then calculate (Mb^-1*A)*Mb^-T (3x36 more flops)
00466     return Mat<4,4,Vec3P>
00467        ( a00,   a01/3+a00,  (a02+2*a01)/3+a00,     a03+a02+a01+a00,
00468           d,      c/3+d,       (b+2*c)/3+d,             a+b+c+d,
00469           h,      g/3+h,       (f+2*g)/3+h,             e+f+g+h,
00470           s,      r/3+s,       (q+2*r) /3+s,            p+q+r+s     );
00471 }
00472 
00475 static Mat<4,4,Vec3P> calcHFromB(const Mat<4,4,Vec3P>& B) {
00476     typedef const Vec3P& Coef;
00477     Coef b11=B(0,0), b12=B(0,1), b13=B(0,2), b14=B(0,3), 
00478          b21=B(1,0), b22=B(1,1), b23=B(1,2), b24=B(1,3), 
00479          b31=B(2,0), b32=B(2,1), b33=B(2,2), b34=B(2,3), 
00480          b41=B(3,0), b42=B(3,1), b43=B(3,2), b44=B(3,3); 
00481 
00482     // First calculate a few temps -- see class comments. (3x4 flops)
00483     Vec3P b12mb11=b12-b11, b24mb14=b24-b14, b42mb41=b42-b41, b44mb34=b44-b34;
00484 
00485     // Then calculate (Mh^-1 Mb) B ~(Mh^-1 Mb). (3x24 more flops)
00486     return Mat<4,4,Vec3P>
00487        (     b11,         b14,          3*b12mb11,           3*(b14-b13),
00488              b41,         b44,          3*b42mb41,           3*(b44-b43),
00489          3*(b21-b11),  3*b24mb14,  9*(b22-b21-b12mb11),  9*(b24mb14+b13-b23),
00490          3*(b41-b31),  3*b44mb34,  9*(b42mb41+b31-b32),  9*(b44mb34+b33-b43) );
00491 }
00492 
00495 static Mat<4,4,Vec3P> calcBFromH(const Mat<4,4,Vec3P>& H) {
00496     typedef const Vec3P& Coef;
00497     Coef h00=H(0,0), h01=H(0,1), w00=H(0,2), w01=H(0,3), 
00498          h10=H(1,0), h11=H(1,1), w10=H(1,2), w11=H(1,3), 
00499          u00=H(2,0), u01=H(2,1), t00=H(2,2), t01=H(2,3), 
00500          u10=H(3,0), u11=H(3,1), t10=H(3,2), t11=H(3,3); 
00501 
00502     // First calculate a few temps -- see class comments. (3x8 flops)
00503     Vec3P tmp00=h00+u00/3, tmp01=h01+u01/3, 
00504           tmp10=h10-u10/3, tmp11=h11-u11/3;
00505 
00506     // Then calculate (Mb^-1 Mh) H ~(Mb^-1 Mh). (3x24 more flops)
00507     return Mat<4,4,Vec3P>
00508        (  h00,       h00+w00/3,          h01-w01/3,       h01,
00509          tmp00,  tmp00+w00/3+t00/9,  tmp01-w01/3-t01/9,  tmp01,
00510          tmp10,  tmp10+w10/3-t10/9,  tmp11-w11/3+t11/9,  tmp11,
00511           h10,       h10+w10/3,          h11-w11/3,       h11  );
00512 }
00515 private:
00516 Mat<4,4,Vec3P> B;   // 16 Bezier control points; see above for definition
00517 };
00518 
00519 
00520 
00521 } // namespace SimTK
00522 
00523 #endif // SimTK_SIMMATH_GEO_BICUBIC_BEZIER_PATCH_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines