/usr/include/simbody/simmath/internal/Geo_BicubicHermitePatch.h is in libsimbody-dev 3.5.4+dfsg-1ubuntu2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 | #ifndef SimTK_SIMMATH_GEO_BICUBIC_HERMITE_PATCH_H_
#define SimTK_SIMMATH_GEO_BICUBIC_HERMITE_PATCH_H_
/* -------------------------------------------------------------------------- *
* Simbody(tm): SimTKmath *
* -------------------------------------------------------------------------- *
* This is part of the SimTK biosimulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
* *
* Portions copyright (c) 2011-12 Stanford University and the Authors. *
* Authors: Michael Sherman *
* Contributors: *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may *
* not use this file except in compliance with the License. You may obtain a *
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* -------------------------------------------------------------------------- */
/** @file
Provides primitive operations for a single bicubic Hermite patch using either
single or double precision. **/
#include "SimTKcommon.h"
#include "simmath/internal/common.h"
#include "simmath/internal/Geo.h"
#include <cassert>
#include <cmath>
#include <algorithm>
namespace SimTK {
//==============================================================================
// GEO BICUBIC HERMITE PATCH
//==============================================================================
/** A primitive useful for computations involving a single bicubic Hermite
patch. Note that a bicubic Hermite spline surface would not necessarily be
composed of these, but could use the static methods here for patch
computations.
<h3>Theory</h3>
The primary reference for this implementation is the book "Geometric Modeling,
3rd ed." by Michael E. Mortenson, Industrial Press 2006, chapter 7. We follow
Mortenson's notation here (with some name changes) and equation numbers are
from the text. See CubicHermiteCurve_ comments for
introductory material; here we add the code needed for a bicubic Hermite
surface, leaning on the cubic Hermite curve code whenever possible. Note that
a bicubic surface is bounded by cubic curves and every cross section is a
cubic curve. This class deals with a bicubic patch in algebraic or Hermite
(geometric) form. The algebraic form is stored since most operations are faster
when the algebraic coefficients are available. Methods are available to
convert quickly between the algebraic and Hermite forms. See
BicubicBezierPatch_ for additional code for conversions to/from Bezier form
and additional operations that are better performed on Bezier control points.
We use H for Hermite coefficients, rather than B, to avoid confusion with
Bezier coefficients. We call the Hermite basis matrix Mh (rather than Mf).
With that name change, the algebraic and Hermite basis matrices match
Mortenson's:
<pre>
[ a33 a32 a31 a30 ] [ h00 h01 w00 w01 ] u=dp/du
A = [ a23 a22 a21 a20 ] H = [ h10 h11 w10 w11 ] w=dp/dw
[ a13 a12 a11 a10 ] [ u00 u01 t00 t01 ] t=d2p/dudw
[ a03 a02 a01 a00 ] [ u10 u11 t10 t11 ] ("twist")
</pre>
We store those in a 4x4 hypermatrix with Vec3 elements. Note that the element
indices do \e not match the matrix indices; instead they have different
meanings as defined by Mortenson. For the algebraic coefficients we have
aij = A[3-i][3-j].
The patch is parameterized by u,w each in
range [0..1]. A point P(u,w) on the patch can be calculated as
<pre>
P(u,w) = U A ~W = sum_ij( aij u^i w^j )
= U Mh H ~Mh ~W
</pre>
where U and W are row vectors U=[u^3 u^2 u 1], W=[w^3 w^2 w 1]. From that you
can see how to interconvert between the two forms:
<pre>
A = Mh H ~Mh
H = Mh^-1 A ~Mh^-1
</pre>
The Mh matrix is presented explicitly in CubicHermiteCurve_; it has a very
simple structure. This can be used to work out low cost interconversions:
**/
template <class P>
class Geo::BicubicHermitePatch_ {
typedef P RealP;
typedef Vec<3,RealP> Vec3P;
public:
/** Construct an uninitialized patch; control points will be garbage. **/
BicubicHermitePatch_() {}
/** Construct a bicubic Hermite patch using the given geometry matrix B. **/
explicit BicubicHermitePatch_(const Mat<4,4,Vec3P>& A) : A(A) {}
/** Return a reference to the algebraic coefficients A that are
stored in this object. See the documentation for this class to see how the
returned matrix of coefficients is defined. **/
const Mat<4,4,Vec3P>& getAlgebraicCoefficients() const {return A;}
/** Calculate the Hermite coefficients H from the stored
algebraic coefficients. See the documentation for this class to see how the
returned matrix of coefficients is defined. Cost is 168 flops. **/
Mat<4,4,Vec3P> calcHermiteCoefficients() const {return calcHFromA(A);}
/** Evaluate a point P(u,w) on this patch given values for the
parameters u and w in [0,1]. Values outside this range are permitted but do
not lie on the patch. Cost is 94 flops. **/
Vec3P evalP(RealP u, RealP w) const {return evalPUsingA(A,u,w);}
/** Evaluate the tangents Pu=dP/du, Pw=dP/dw on this patch given values for the
parameters u and w in [0,1]. Values outside this range are permitted but do not
lie on the curve segment. Cost is 148 flops. **/
void evalP1(RealP u, RealP w, Vec3P& Pu, Vec3P& Pw) const
{ return evalP1UsingA(A,u,w,Pu,Pw); }
/** Evaluate the second derivatives Puu=d2P/du2, Pww=d2P/dw2, and cross
derivative Puw=Pwu=d2P/dudw on this patch given values for the parameters u
and w in [0,1]. Values outside this range are permitted but do not lie on the
curve segment. Cost is 172 flops. **/
void evalP2(RealP u, RealP w, Vec3P& Puu, Vec3P& Puw, Vec3P& Pww) const
{ evalP2UsingA(A,u,w,Puu,Puw,Pww); }
/** Evaluate the third derivatives Puuu=d3P/du3, Pwww=d3P/dw3, and cross
derivatives Puuw=Pwuu=Puwu=d3P/du2dw and Puww=Pwwu=Pwuw=d3P/dudw2 on this patch
given values for the parameters u and w in [0,1]. Cost is 142 flops. All
higher derivatives of a cubic patch are zero. **/
void evalP3(RealP u, RealP w, Vec3P& Puuu, Vec3P& Puuw,
Vec3P& Puww, Vec3P& Pwww) const
{ evalP3UsingA(A,u,w,Puuu,Puuw,Puww,Pwww); }
/**@name Utility methods
These static methods work with given coefficients. **/
/**@{**/
/** Given the vector Hermite coefficients H, return the algebraic
coefficients A. All coefficients are 3-vectors. Cost is 3x70=210 flops. **/
static Mat<4,4,Vec3P> calcAFromH(const Mat<4,4,Vec3P>& H) {
typedef const Vec3P& Coef;
Coef h00=H(0,0), h01=H(0,1), w00=H(0,2), w01=H(0,3),
h10=H(1,0), h11=H(1,1), w10=H(1,2), w11=H(1,3),
u00=H(2,0), u01=H(2,1), t00=H(2,2), t01=H(2,3),
u10=H(3,0), u11=H(3,1), t10=H(3,2), t11=H(3,3);
// First calculate Mh*H:
// a b c d
// p q r s
// u00 u01 t00 t01
// h00 h01 w00 w01
Vec3P a=2*(h00-h10)+u00+u10, b=2*(h01-h11)+u01+u11,
c=2*(w00-w10)+t00+t10, d=2*(w01-w11)+t01+t11;
Vec3P p=3*(h10-h00)-2*u00-u10, q=3*(h11-h01)-2*u01-u11,
r=3*(w10-w00)-2*t00-t10, s=3*(w11-w01)-2*t01-t11;
// Then calculate (Mh*H)*~Mh.
Vec3P bma=b-a, qmp=q-p;
return Mat<4,4,Vec3P>
( c+d-2*bma, 3*bma-2*c-d, c, a,
r+s-2*qmp, 3*qmp-2*r-s, r, p,
2*(u00-u01)+t00+t01, 3*(u01-u00)-2*t00-t01, t00, u00,
2*(h00-h01)+w00+w01, 3*(h01-h00)-2*w00-w01, w00, h00 );
}
/** Given the vector algebraic coefficients A, return the Hermite coefficients
H. All coefficients are 3-vectors. Cost is 3x56=168 flops. **/
static Mat<4,4,Vec3P> calcHFromA(const Mat<4,4,Vec3P>& A) {
typedef const Vec3P& Coef;
Coef a33=A(0,0), a32=A(0,1), a31=A(0,2), a30=A(0,3),
a23=A(1,0), a22=A(1,1), a21=A(1,2), a20=A(1,3),
a13=A(2,0), a12=A(2,1), a11=A(2,2), a10=A(2,3),
a03=A(3,0), a02=A(3,1), a01=A(3,2), a00=A(3,3);
// First calculate Mh^-1*A:
// a03 a02 a01 a00
// a b c d
// a13 a12 a11 a10
// p q r s
Vec3P a=a33+a23+a13+a03, b=a32+a22+a12+a02, // 3x12 flops
c=a31+a21+a11+a01, d=a30+a20+a10+a00;
Vec3P p=3*a33+2*a23+a13, q=3*a32+2*a22+a12, // 3x16 flops
r=3*a31+2*a21+a11, s=3*a30+2*a20+a10;
// Then calculate (Mh^-1*A)*Mh^-T (3x28 flops)
return Mat<4,4,Vec3P>
( a00, a03+a02+a01+a00, a01, 3*a03+2*a02+a01,
d, a+b+c+d, c, 3*a+2*b+c,
a10, a13+a12+a11+a10, a11, 3*a13+2*a12+a11,
s, p+q+r+s, r, 3*p+2*q+r );
}
/** Given vector algebraic coefficients A and values for the curve parameters
u and w in [0..1], return the point P(u,w)=U*A*~W at that location. Cost is
3x30+4=94 flops. **/
static Vec3P evalPUsingA(const Mat<4,4,Vec3P>& A, RealP u, RealP w) {
typedef const Vec3P& Coef;
Coef a33=A(0,0), a32=A(0,1), a31=A(0,2), a30=A(0,3),
a23=A(1,0), a22=A(1,1), a21=A(1,2), a20=A(1,3),
a13=A(2,0), a12=A(2,1), a11=A(2,2), a10=A(2,3),
a03=A(3,0), a02=A(3,1), a01=A(3,2), a00=A(3,3);
const RealP u2 = u*u, u3 = u*u2, w2 = w*w, w3 = w*w2;
Vec3P p = u3*(a33*w3 + a32*w2 + a31*w + a30)
+ u2*(a23*w3 + a22*w2 + a21*w + a20)
+ u *(a13*w3 + a12*w2 + a11*w + a10)
+ (a03*w3 + a02*w2 + a01*w + a00);
return p;
}
/** Given vector algebraic coefficients A and values for the curve parameters
u and w in [0..1], return the tangents Pu(u,w)=dU*A*~W and Pw(u,w)=U*A*~dW at
that location. Cost is 3x48+4=148 flops. **/
static void evalP1UsingA(const Mat<4,4,Vec3P>& A, RealP u, RealP w,
Vec3P& Pu, Vec3P& Pw) {
typedef const Vec3P& Coef;
Coef a33=A(0,0), a32=A(0,1), a31=A(0,2), a30=A(0,3),
a23=A(1,0), a22=A(1,1), a21=A(1,2), a20=A(1,3),
a13=A(2,0), a12=A(2,1), a11=A(2,2), a10=A(2,3),
a03=A(3,0), a02=A(3,1), a01=A(3,2);
const RealP u2 = u*u, u3 = u*u2, w2 = w*w, w3 = w*w2;
Pu = 3*u2*(a33*w3 + a32*w2 + a31*w + a30)
+ 2* u*(a23*w3 + a22*w2 + a21*w + a20)
+ (a13*w3 + a12*w2 + a11*w + a10);
Pw = 3*w2*(u3*a33 + u2*a23 + u*a13 + a03)
+ 2* w*(u3*a32 + u2*a22 + u*a12 + a02)
+ (u3*a31 + u2*a21 + u*a11 + a01);
}
/** Given vector algebraic coefficients A and values for the curve parameters
u and w in [0..1], return the second derivatives Puu(u,w)=d2U*A*~W,
Puw(u,w)=dU*A*~dW and Pww(u,w)=U*A*~d2W at that location.
Cost is 3x56+4=172 flops. **/
static void evalP2UsingA(const Mat<4,4,Vec3P>& A, RealP u, RealP w,
Vec3P& Puu, Vec3P& Puw, Vec3P& Pww) {
typedef const Vec3P& Coef;
Coef a33=A(0,0), a32=A(0,1), a31=A(0,2), a30=A(0,3),
a23=A(1,0), a22=A(1,1), a21=A(1,2), a20=A(1,3),
a13=A(2,0), a12=A(2,1), a11=A(2,2),
a03=A(3,0), a02=A(3,1);
const RealP u2 = u*u, u3 = u*u2, w2 = w*w, w3 = w*w2;
Puu = 6*u*(a33*w3 + a32*w2 + a31*w + a30)
+ 2 *(a23*w3 + a22*w2 + a21*w + a20);
Pww = 6*w*(u3*a33 + u2*a23 + u*a13 + a03)
+ 2 *(u3*a32 + u2*a22 + u*a12 + a02);
Puw = 3*u2*(3*a33*w2 + 2*a32*w + a31)
+ 2*u *(3*a23*w2 + 2*a22*w + a21)
+ (3*a13*w2 + 2*a12*w + a11);
}
/** Given vector algebraic coefficients A and values for the curve parameters
u and w in [0..1], return the third derivatives Puuu(u,w)=d3U*A*~W,
Puuw(u,w)=d2U*A*~dW, Puww(u,w)=dU*A*~d2W and Pwww(u,w)=U*A*~d3W at that
location. Cost is 3x46+4=142 flops. **/
static void evalP3UsingA(const Mat<4,4,Vec3P>& A, RealP u, RealP w,
Vec3P& Puuu, Vec3P& Puuw, Vec3P& Puww, Vec3P& Pwww) {
typedef const Vec3P& Coef;
Coef a33=A(0,0), a32=A(0,1), a31=A(0,2), a30=A(0,3),
a23=A(1,0), a22=A(1,1), a21=A(1,2), a20=A(1,3),
a13=A(2,0), a12=A(2,1),
a03=A(3,0), a02=A(3,1);
const RealP u2 = u*u, u3 = u*u2, w2 = w*w, w3 = w*w2;
Puuu = 6*(a33*w3 + a32*w2 + a31*w + a30);
Pwww = 6*(u3*a33 + u2*a23 + u*a13 + a03);
Puuw = 6*u*(3*a33*w2 + 2*a32*w + a31)
+ 6*a23*w2 + 4*a22*w + 2*a21;
Puww = 6*w*(3*u2*a33 + 2*u*a23 + a13)
+ 6*u2*a32 + 4*u*a22 + 2*a12;
}
/**@}**/
private:
Mat<4,4,Vec3P> A; // algebraic coefficients
};
} // namespace SimTK
#endif // SimTK_SIMMATH_GEO_BICUBIC_HERMITE_PATCH_H_
|