1 #ifndef SimTK_SimTKCOMMON_TRANSFORM_H
2 #define SimTK_SimTKCOMMON_TRANSFORM_H
3
4 /* -------------------------------------------------------------------------- *
5 * Simbody(tm): SimTKcommon *
6 * -------------------------------------------------------------------------- *
7 * This is part of the SimTK biosimulation toolkit originating from *
8 * Simbios, the NIH National Center for Physics-Based Simulation of *
9 * Biological Structures at Stanford, funded under the NIH Roadmap for *
10 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
11 * *
12 * Portions copyright (c) 2005-14 Stanford University and the Authors. *
13 * Authors: Michael Sherman *
14 * Contributors: Paul Mitiguy *
15 * *
16 * Licensed under the Apache License, Version 2.0 (the "License"); you may *
17 * not use this file except in compliance with the License. You may obtain a *
18 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
19 * *
20 * Unless required by applicable law or agreed to in writing, software *
21 * distributed under the License is distributed on an "AS IS" BASIS, *
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
23 * See the License for the specific language governing permissions and *
24 * limitations under the License. *
25 * -------------------------------------------------------------------------- */
26
27 //-----------------------------------------------------------------------------
28 #include "SimTKcommon/SmallMatrix.h"
29 #include "SimTKcommon/internal/BigMatrix.h"
30 #include "SimTKcommon/internal/UnitVec.h"
31 #include "SimTKcommon/internal/Quaternion.h"
32 #include "SimTKcommon/internal/Rotation.h"
33 //-----------------------------------------------------------------------------
34 #include <iosfwd> // Forward declaration of iostream
35 //-----------------------------------------------------------------------------
36
37
38 //-----------------------------------------------------------------------------
39 namespace SimTK {
40
41 //-----------------------------------------------------------------------------
42 // Forward declarations (everything is templatized by precision).
43 template <class P> class Transform_;
44 template <class P> class InverseTransform_;
45
46 typedef Transform_<Real> Transform;
47 typedef Transform_<float> fTransform;
48 typedef Transform_<double> dTransform;
49
50
51 //-----------------------------------------------------------------------------
52 /**
53 * This class represents the rotate-and-shift transform which gives the
54 * location and orientation of a new frame F in a base (reference) frame
55 * B. A frame is an orthogonal, right-handed set of three axes, and an
56 * origin point. A transform X from frame B to F consists of 3 perpendicular
57 * unit vectors defining F's axes as viewed from B (that is, as expressed in
58 * the basis formed by B's axes), and a vector from B's origin point Bo to F's
59 * origin point Fo. Note that the meaning of "B" comes from the context in
60 * which the transform is used. We use the phrase "frame F is in frame B" to
61 * describe the above relationship, that is, "in" means both measured from
62 * and expressed in.
63 *
64 * The axis vectors constitute a Rotation_. They are ordered 1-2-3 or x-y-z
65 * as you prefer, with z = x X y, making a right-handed set. These axes are
66 * arranged as columns of a 3x3 rotation matrix R_BF = [ x y z ] which is a
67 * direction cosine (rotation) matrix useful for conversions between frame
68 * B and F. (The columns of R_BF are F's coordinate axes, expressed in B.) For
69 * example, given a vector vF expressed in the F frame, that same vector
70 * re-expressed in B is given by vB = R_BF*vF. F's origin point OF is
71 * stored as the translation vector p_BF=(Fo-Bo) and expressed in B.
72 *
73 * Transform is designed to behave as much as possible like the computer
74 * graphics 4x4 affine transform X which would be arranged like this:
75 * <pre>
76 *
77 * [ | ]
78 * X = [ R | p ] R is a 3x3 orthogonal rotation matrix
79 * [.......|...] p is a 3x1 translation vector
80 * [ 0 0 0 1 ]
81 * </pre>
82 *
83 * These can be composed directly by matrix multiplication, but more
84 * importantly they have a particularly simple inverse:
85 * <pre>
86 *
87 * -1 [ | ]
88 * X = [ ~R | p* ] ~R is R transpose, p* = ~R(-p).
89 * [.......|....]
90 * [ 0 0 0 1 ]
91 * </pre>
92 *
93 * This inverse is so simple that we compute it simply by defining another
94 * type, InverseTransform_, which is identical to %Transform_ in memory but
95 * behaves as though it contains the inverse. That way we invert just by
96 * changing point of view (recasting) rather than computing.
97 *
98 * This is a "POD" (plain old data) class with a well-defined memory
99 * layout on which a client of this class may depend: There are
100 * exactly 4 consecutive, packed 3-vectors in the order x,y,z,p.
101 * That is, this class is equivalent to an array of 12 Reals with
102 * the order x1,x2,x3,y1,y2,y3,z1,z2,z3,p1,p2,p3. It is expressly allowed
103 * to reinterpret Transform objects in any appropriate manner that depends
104 * on this memory layout.
105 */
106 //-----------------------------------------------------------------------------
107 template <class P>
108 class Transform_ {
109 public:
110 /// Default constructor gives an identity transform.
Transform_()111 Transform_() : R_BF(), p_BF(0) { }
112
113 /// Combine a rotation and a translation into a transform.
Transform_(const Rotation_<P> & R,const Vec<3,P> & p)114 Transform_( const Rotation_<P>& R, const Vec<3,P>& p ) : R_BF(R), p_BF(p) { }
115
116 /// Construct or default-convert a rotation into a transform
117 /// containing that rotation and zero translation.
Transform_(const Rotation_<P> & R)118 Transform_( const Rotation_<P>& R ) : R_BF(R), p_BF(0) { }
119
120 /// Construct or default-convert a translation (expressed as a Vec3)
121 /// into a transform with that translation and a zero rotation.
Transform_(const Vec<3,P> & p)122 Transform_( const Vec<3,P>& p ) : R_BF(), p_BF(p) { }
123
124 // default copy, assignment, destructor
125
126 /// Assignment from InverseTransform. This means that the
127 /// transform we're assigning to must end up with the same @em meaning
128 /// as the inverse transform X has, so we'll need to end up with:
129 /// @li p == X.p()
130 /// @li R == X.R()
131 ///
132 /// Cost: one frame conversion and a negation, 18 flops.
133 // (Definition is below after InverseTransform is declared.)
134 inline Transform_& operator=( const InverseTransform_<P>& X );
135
136 /// Add an offset to the position vector in this %Transform. Cost
137 /// is 3 flops.
138 template <int S>
139 Transform_& operator+=(const Vec<3,P,S>& offset_B)
140 { p_BF += offset_B; return *this; }
141
142 /// Subtract an offset from the position vector in this %Transform. Cost
143 /// is 3 flops.
144 template <int S>
145 Transform_& operator-=(const Vec<3,P,S>& offset_B)
146 { p_BF -= offset_B; return *this; }
147
148 /// Assign a new value to this transform, explicitly providing
149 /// the rotation and translation separately. We return a reference to
150 /// the now-modified transform as though this were an assignment operator.
set(const Rotation_<P> & R,const Vec<3,P> & p)151 Transform_& set( const Rotation_<P>& R, const Vec<3,P>& p ) { p_BF=p; R_BF=R; return *this; }
152
153 /// By zero we mean "zero transform", i.e., an identity rotation
154 /// and zero translation. We return a reference to the now-modified
155 /// transform as though this were an assignment operator.
setToZero()156 Transform_& setToZero() { R_BF.setRotationToIdentityMatrix(); p_BF = P(0); return *this; }
157
158 /// This fills both the rotation and translation with NaNs. Note: this is
159 /// @em not the same as a default-constructed transform, which is a
160 /// legitimate identity transform instead. We return a reference to the now-modified
161 /// transform as though this were an assignment operator.
setToNaN()162 Transform_& setToNaN() { R_BF.setRotationToNaN(); p_BF.setToNaN(); return *this; }
163
164 /// Return a read-only inverse of the current Transform_<P>, simply by casting it to
165 /// the InverseTransform_<P> type. Zero cost.
invert()166 const InverseTransform_<P>& invert() const { return *reinterpret_cast<const InverseTransform_<P>*>(this); }
167
168 /// Return a writable (lvalue) inverse of the current transform, simply by casting it to
169 /// the InverseTransform_<P> type. That is, this is an lvalue. Zero cost.
updInvert()170 InverseTransform_<P>& updInvert() { return *reinterpret_cast<InverseTransform_<P>*>(this); }
171
172 /// Overload transpose operator to mean inversion. @see invert
173 const InverseTransform_<P>& operator~() const {return invert();}
174
175 /// Overload transpose operator to mean inversion. @see updInvert
176 InverseTransform_<P>& operator~() {return updInvert();}
177
178 /// Compose the current transform (X_BF) with the given one. That is,
179 /// return X_BY=X_BF*X_FY. Cost is 63 flops.
compose(const Transform_ & X_FY)180 Transform_ compose(const Transform_& X_FY) const {
181 return Transform_( R_BF * X_FY.R(), p_BF + R_BF * X_FY.p() );
182 }
183
184 /// Compose the current transform (X_BF) with one that is supplied
185 /// as an InverseTransform_ (typically as a result of applying
186 /// the "~" operator to a transform). That is, return
187 /// X_BY=X_BF*X_FY, but now X_FY is represented as ~X_YF. Cost
188 /// is an extra 18 flops to calculate X_FY.p(), total 81 flops.
189 // (Definition is below after InverseTransform_ is declared.)
190 inline Transform_ compose( const InverseTransform_<P>& X_FY ) const;
191
192 /// %Transform a vector expressed in our "F" frame to our "B" frame.
193 /// Note that this involves rotation only; it is independent of
194 /// the translation stored in this transform. Cost is 15 flops.
xformFrameVecToBase(const Vec<3,P> & vF)195 Vec<3,P> xformFrameVecToBase( const Vec<3,P>& vF ) const {return R_BF*vF;}
196
197 /// %Transform a vector expressed in our "B" frame to our "F" frame.
198 /// Note that this involves rotation only; it is independent of
199 /// the translation stored in this transform. Cost is 15 flops.
xformBaseVecToFrame(const Vec<3,P> & vB)200 Vec<3,P> xformBaseVecToFrame( const Vec<3,P>& vB ) const { return ~R_BF*vB; }
201
202 /// %Transform a point (station) measured from and expressed in
203 /// our "F" frame to that same point but measured from and
204 /// expressed in our "B" frame. Cost is 18 flops.
shiftFrameStationToBase(const Vec<3,P> & sF)205 Vec<3,P> shiftFrameStationToBase( const Vec<3,P>& sF ) const
206 { return p_BF + xformFrameVecToBase(sF); }
207
208 /// %Transform a point (station) measured from and expressed in
209 /// our "B" frame to that same point but measured from and
210 /// expressed in our "F" frame. Cost is 18 flops.
shiftBaseStationToFrame(const Vec<3,P> & sB)211 Vec<3,P> shiftBaseStationToFrame( const Vec<3,P>& sB ) const
212 { return xformBaseVecToFrame(sB - p_BF); }
213
214 /// Return a read-only reference to the contained rotation R_BF.
R()215 const Rotation_<P>& R() const { return R_BF; }
216
217 /// Return a writable (lvalue) reference to the contained rotation R_BF.
updR()218 Rotation_<P>& updR() { return R_BF; }
219
220 /// Return a read-only reference to the x direction (unit vector)
221 /// of the F frame, expressed in the B frame.
x()222 const typename Rotation_<P>::ColType& x() const { return R().x(); }
223 /// Return a read-only reference to the y direction (unit vector)
224 /// of the F frame, expressed in the B frame.
y()225 const typename Rotation_<P>::ColType& y() const { return R().y(); }
226 /// Return a read-only reference to the z direction (unit vector)
227 /// of the F frame, expressed in the B frame.
z()228 const typename Rotation_<P>::ColType& z() const { return R().z(); }
229
230 /// Return a read-only reference to the inverse (transpose) of
231 /// our contained rotation, that is R_FB.
RInv()232 const InverseRotation_<P>& RInv() const { return ~R_BF; }
233
234 /// Return a writable (lvalue) reference to the inverse (transpose) of
235 /// our contained rotation, that is R_FB.
updRInv()236 InverseRotation_<P>& updRInv() { return ~R_BF; }
237
238 /// Return a read-only reference to our translation vector p_BF.
p()239 const Vec<3,P>& p() const { return p_BF; }
240
241 /// Return a writable (lvalue) reference to our translation vector p_BF.
242 /// Caution: if you write through this reference you update the transform.
updP()243 Vec<3,P>& updP() { return p_BF; }
244
245 /// Assign a new value to our translation vector. We expect the
246 /// supplied vector @p p to be expressed in our B frame. A reference
247 /// to the now-modified transform is returned as though this were
248 /// an assignment operator.
setP(const Vec<3,P> & p)249 Transform_<P>& setP( const Vec<3,P>& p ) { p_BF=p; return *this; }
250
251 /// Calculate the inverse of the translation vector in this transform.
252 /// The returned vector will be the negative of the original and will
253 /// be expressed in the F frame rather than our B frame. Cost is 18 flops.
pInv()254 Vec<3,P> pInv() const { return -(~R_BF*p_BF); }
255
256 /// Assign a value to the @em inverse of our translation vector.
257 /// That is, we're given a vector in F which we invert and reexpress
258 /// in B to store it in p, so that we get the original argument back if
259 /// we ask for the inverse of p. Sorry, can't update pInv as an lvalue, but here we
260 /// want -(~R_BF*p_BF)=p_FB => p_BF=-(R_BF*p_FB) so we can calculate
261 /// it in 18 flops. A reference to the now-modified transform is returned
262 /// as though this were an assignment operator.
setPInv(const Vec<3,P> & p_FB)263 Transform_<P>& setPInv( const Vec<3,P>& p_FB ) { p_BF = -(R_BF*p_FB); return *this; }
264
265 /// Recast this transform as a read-only 3x4 matrix. This is a zero-cost
266 /// reinterpretation of the data; the first three columns are the
267 /// columns of the rotation and the last column is the translation.
asMat34()268 const Mat<3,4,P>& asMat34() const { return Mat<3,4,P>::getAs(reinterpret_cast<const P*>(this)); }
269
270 /// Less efficient version of asMat34(); copies into return variable.
toMat34()271 Mat<3,4,P> toMat34() const { return asMat34(); }
272
273 /// Return the equivalent 4x4 transformation matrix.
toMat44()274 Mat<4,4,P> toMat44() const {
275 Mat<4,4,P> tmp;
276 tmp.template updSubMat<3,4>(0,0) = asMat34();
277 tmp[3] = Row<4,P>(0,0,0,1);
278 return tmp;
279 }
280
281 // OBSOLETE -- alternate name for p
T()282 const Vec<3,P>& T() const {return p();}
updT()283 Vec<3,P>& updT() {return updP();}
284
285 private:
286 //TODO: these might not pack correctly; should use an array of 12 Reals.
287 Rotation_<P> R_BF; // rotation matrix that expresses F's axes in R
288 Vec<3,P> p_BF; // location of F's origin measured from B's origin, expressed in B
289 };
290
291
292 //-----------------------------------------------------------------------------
293 /**
294 * %Transform from frame B to frame F, but with the internal representation
295 * inverted. That is, we store R*,p* here but the transform this represents is
296 * <pre>
297 *
298 * B F [ | ]
299 * X_BF = X = [ R | p ] where R=~(R*), p = - ~(R*)(p*).
300 * [.......|...]
301 * [ 0 0 0 1 ]
302 * </pre>
303 */
304 //-----------------------------------------------------------------------------
305 template <class P>
306 class InverseTransform_ {
307 public:
308 /// Default constructor produces an identity transform.
InverseTransform_()309 InverseTransform_() : R_FB(), p_FB(0) { }
310
311 // default copy, assignment, destructor
312
313 /// Implicit conversion from %InverseTransform_ to Transform_.
314 operator Transform_<P>() const { return Transform_<P>( R(), p() ); }
315
316 // Assignment from Transform_. This means that the inverse
317 // transform we're assigning to must end up with the same meaning
318 // as the inverse transform X has, so we'll need:
319 // p* == X.pInv()
320 // R* == X.RInv()
321 // Cost: one frame conversion and a negation for pInv, 18 flops.
322 InverseTransform_& operator=( const Transform_<P>& X ) {
323 // Be careful to do this in the right order in case X and this
324 // are the same object, i.e. ~X = X which is weird but has
325 // the same meaning as X = ~X, i.e. invert X in place.
326 p_FB = X.pInv(); // This might change X.p ...
327 R_FB = X.RInv(); // ... but this doesn't depend on X.p.
328 return *this;
329 }
330
331 // Inverting one of these just recasts it back to a Transform_<P>.
invert()332 const Transform_<P>& invert() const { return *reinterpret_cast<const Transform_<P>*>(this); }
updInvert()333 Transform_<P>& updInvert() { return *reinterpret_cast<Transform_<P>*>(this); }
334
335 // Overload transpose to mean inversion.
336 const Transform_<P>& operator~() const { return invert(); }
337 Transform_<P>& operator~() { return updInvert(); }
338
339 // Return X_BY=X_BF*X_FY, where X_BF (this) is represented here as ~X_FB. This
340 // costs exactly the same as a composition of two Transforms (63 flops).
compose(const Transform_<P> & X_FY)341 Transform_<P> compose(const Transform_<P>& X_FY) const {
342 return Transform_<P>( ~R_FB * X_FY.R(), ~R_FB *(X_FY.p() - p_FB) );
343 }
344 // Return X_BY=X_BF*X_FY, but now both xforms are represented by their inverses.
345 // This costs one extra vector transformation and a negation (18 flops) more
346 // than a composition of two Transforms, for a total of 81 flops.
compose(const InverseTransform_<P> & X_FY)347 Transform_<P> compose(const InverseTransform_<P>& X_FY) const {
348 return Transform_<P>( ~R_FB * X_FY.R(), ~R_FB *(X_FY.p() - p_FB) );
349 }
350
351 // Forward and inverse vector transformations cost the same here as
352 // for a Transform_<P> (or for that matter, a Rotation_<P>): 15 flops.
xformFrameVecToBase(const Vec<3,P> & vF)353 Vec<3,P> xformFrameVecToBase(const Vec<3,P>& vF) const {return ~R_FB*vF;}
xformBaseVecToFrame(const Vec<3,P> & vB)354 Vec<3,P> xformBaseVecToFrame(const Vec<3,P>& vB) const {return R_FB*vB;}
355
356 // Forward and inverse station shift & transform cost the same here as for a Transform_<P>: 18 flops.
shiftFrameStationToBase(const Vec<3,P> & sF)357 Vec<3,P> shiftFrameStationToBase(const Vec<3,P>& sF) const { return ~R_FB*(sF-p_FB); }
shiftBaseStationToFrame(const Vec<3,P> & sB)358 Vec<3,P> shiftBaseStationToFrame(const Vec<3,P>& sB) const { return R_FB*sB + p_FB; }
359
R()360 const InverseRotation_<P>& R() const {return ~R_FB;}
updR()361 InverseRotation_<P>& updR() {return ~R_FB;}
362
x()363 const typename InverseRotation_<P>::ColType& x() const {return R().x();}
y()364 const typename InverseRotation_<P>::ColType& y() const {return R().y();}
z()365 const typename InverseRotation_<P>::ColType& z() const {return R().z();}
366
RInv()367 const Rotation_<P>& RInv() const {return R_FB;}
updRInv()368 Rotation_<P>& updRInv() {return R_FB;}
369
370 /// Calculate the actual translation vector at a cost of 18 flops.
371 /// It is better if you can just work with the %InverseTransform
372 /// directly since then you'll never have to pay this cost.
p()373 Vec<3,P> p() const { return -(~R_FB*p_FB); }
374
375
376 // no updP lvalue
377
378 // Sorry, can't update translation as an lvalue, but here we
379 // want -(R_BF*p_FB)=p_BF => p_FB=-(R_FB*p_BF). Cost: 18 flops.
setP(const Vec<3,P> & p_BF)380 void setP( const Vec<3,P>& p_BF ) { p_FB = -(R_FB*p_BF); }
381
382 // Inverse translation is free.
pInv()383 const Vec<3,P>& pInv() const { return p_FB; }
setPInv(const Vec<3,P> & p)384 void setPInv( const Vec<3,P>& p ) { p_FB = p; }
385
386 /// For compatibility with Transform_<P>, but we don't provide an "as"
387 /// method here since the internal storage layout is somewhat odd.
toMat34()388 Mat<3,4,P> toMat34() const { return Transform_<P>(*this).asMat34(); }
389
390 /// Return the equivalent 4x4 transformation matrix.
toMat44()391 Mat<4,4,P> toMat44() const { return Transform_<P>(*this).toMat44(); }
392
393 // OBSOLETE -- alternate name for p.
T()394 Vec<3,P> T() const {return p();}
395
396 private:
397 // DATA LAYOUT MUST BE IDENTICAL TO Transform_<P> !!
398 // TODO: redo packing here when it is done for Transform_<P>.
399 Rotation_<P> R_FB; // transpose of our rotation matrix, R_BF
400 Vec<3,P> p_FB; // our translation is -(R_BF*p_FB)=-(~R_FB*p_FB)
401 };
402
403 /// If we multiply a transform or inverse transform by a 3-vector, we treat
404 /// the vector as though it had a 4th element "1" appended, that is, it is
405 /// treated as a \e station rather than a \e vector. This way we use both
406 /// the rotational and translational components of the transform.
407 /// @relates Transform_
408 template <class P, int S> inline Vec<3,P>
409 operator*(const Transform_<P>& X_BF, const Vec<3,P,S>& s_F)
410 { return X_BF.shiftFrameStationToBase(s_F); }
411 template <class P, int S> inline Vec<3,P>
412 operator*(const InverseTransform_<P>& X_BF, const Vec<3,P,S>& s_F)
413 { return X_BF.shiftFrameStationToBase(s_F); }
414 template <class P, int S> inline Vec<3,P>
415 operator*(const Transform_<P>& X_BF, const Vec<3,negator<P>,S>& s_F)
416 { return X_BF*Vec<3,P>(s_F); }
417 template <class P, int S> inline Vec<3,P>
418 operator*(const InverseTransform_<P>& X_BF, const Vec<3,negator<P>,S>& s_F)
419 { return X_BF*Vec<3,P>(s_F); }
420
421 /// Adding a 3-vector to a Transform produces a new shifted transform.
422 /// @relates Transform_
423 template <class P, int S> inline Transform_<P>
424 operator+(const Transform_<P>& X_BF, const Vec<3,P,S>& offset_B)
425 { return Transform_<P>(X_BF) += offset_B; }
426 /// Adding a 3-vector to a Transform produces a new shifted transform.
427 /// @relates Transform_
428 template <class P, int S> inline Transform_<P>
429 operator+(const Vec<3,P,S>& offset_B, const Transform_<P>& X_BF)
430 { return Transform_<P>(X_BF) += offset_B; }
431
432 /// Subtracting a 3-vector from a Transform produces a new shifted transform.
433 /// @relates Transform_
434 template <class P, int S> inline Transform_<P>
435 operator-(const Transform_<P>& X_BF, const Vec<3,P,S>& offset_B)
436 { return Transform_<P>(X_BF) -= offset_B; }
437
438 //-----------------------------------------------------------------------------
439 /// If we multiply a transform or inverse transform by an augmented 4-vector,
440 /// we use the 4th element to decide how to treat it. The 4th element must be
441 /// 0 or 1. If 0 it is treated as a vector only and the translation is ignored.
442 /// If 1 it is treated as a station and rotated & shifted.
443 /// @relates Transform_
444 template <class P, int S> inline Vec<4,P>
445 operator*(const Transform_<P>& X_BF, const Vec<4,P,S>& a_F) {
446 assert(a_F[3]==0 || a_F[3]==1);
447 const Vec<3,P,S>& v_F = Vec<3,P,S>::getAs(&a_F[0]); // recast the 1st 3 elements as Vec3
448
449 Vec<4,P> out;
450 if( a_F[3] == 0 ) { Vec<3,P>::updAs(&out[0]) = X_BF.xformFrameVecToBase(v_F); out[3] = 0; }
451 else { Vec<3,P>::updAs(&out[0]) = X_BF.shiftFrameStationToBase(v_F); out[3] = 1; }
452 return out;
453 }
454
455 template <class P, int S> inline Vec<4,P>
456 operator*(const InverseTransform_<P>& X_BF, const Vec<4,P,S>& a_F ) {
457 assert(a_F[3]==0 || a_F[3]==1);
458 const Vec<3,P,S>& v_F = Vec<3,P,S>::getAs(&a_F[0]); // recast the 1st 3 elements as Vec3
459
460 Vec<4,P> out;
461 if( a_F[3] == 0 ) { Vec<3,P>::updAs(&out[0]) = X_BF.xformFrameVecToBase(v_F); out[3] = 0; }
462 else { Vec<3,P>::updAs(&out[0]) = X_BF.shiftFrameStationToBase(v_F); out[3] = 1; }
463 return out;
464 }
465 template <class P, int S> inline Vec<4,P>
466 operator*(const Transform_<P>& X_BF, const Vec<4,negator<P>,S>& s_F) {return X_BF*Vec<4,P>(s_F);}
467 template <class P, int S> inline Vec<4,P>
468 operator*(const InverseTransform_<P>& X_BF, const Vec<4,negator<P>,S>& s_F) {return X_BF*Vec<4,P>(s_F);}
469 //-----------------------------------------------------------------------------
470
471 /// Multiplying a matrix or vector by a Transform_<P> applies it to each element
472 /// individually.
473 /// @relates Transform_
474 template <class P, class E> inline Vector_<E>
475 operator*(const Transform_<P>& X, const VectorBase<E>& v) {
476 Vector_<E> result(v.size());
477 for (int i = 0; i < v.size(); ++i)
478 result[i] = X*v[i];
479 return result;
480 }
481 template <class P, class E> inline Vector_<E>
482 operator*(const VectorBase<E>& v, const Transform_<P>& X) {
483 Vector_<E> result(v.size());
484 for (int i = 0; i < v.size(); ++i)
485 result[i] = X*v[i];
486 return result;
487 }
488 template <class P, class E> inline RowVector_<E>
489 operator*(const Transform_<P>& X, const RowVectorBase<E>& v) {
490 RowVector_<E> result(v.size());
491 for (int i = 0; i < v.size(); ++i)
492 result[i] = X*v[i];
493 return result;
494 }
495 template <class P, class E> inline RowVector_<E>
496 operator*(const RowVectorBase<E>& v, const Transform_<P>& X) {
497 RowVector_<E> result(v.size());
498 for (int i = 0; i < v.size(); ++i)
499 result[i] = X*v[i];
500 return result;
501 }
502 template <class P, class E> inline Matrix_<E>
503 operator*(const Transform_<P>& X, const MatrixBase<E>& v) {
504 Matrix_<E> result(v.nrow(), v.ncol());
505 for (int i = 0; i < v.nrow(); ++i)
506 for (int j = 0; j < v.ncol(); ++j)
507 result(i, j) = X*v(i, j);
508 return result;
509 }
510 template <class P, class E> inline Matrix_<E>
511 operator*(const MatrixBase<E>& v, const Transform_<P>& X) {
512 Matrix_<E> result(v.nrow(), v.ncol());
513 for (int i = 0; i < v.nrow(); ++i)
514 for (int j = 0; j < v.ncol(); ++j)
515 result(i, j) = X*v(i, j);
516 return result;
517 }
518 template <class P, int N, class E, int S> inline Vec<N,E>
519 operator*(const Transform_<P>& X, const Vec<N,E,S>& v) {
520 Vec<N,E> result;
521 for (int i = 0; i < N; ++i)
522 result[i] = X*v[i];
523 return result;
524 }
525 template <class P, int N, class E, int S> inline Vec<N,E>
526 operator*(const Vec<N,E,S>& v, const Transform_<P>& X) {
527 Vec<N,E> result;
528 for (int i = 0; i < N; ++i)
529 result[i] = X*v[i];
530 return result;
531 }
532 template <class P, int N, class E, int S> inline Row<N,E>
533 operator*(const Transform_<P>& X, const Row<N,E,S>& v) {
534 Row<N,E> result;
535 for (int i = 0; i < N; ++i)
536 result[i] = X*v[i];
537 return result;
538 }
539 template <class P, int N, class E, int S> inline Row<N,E>
540 operator*(const Row<N,E,S>& v, const Transform_<P>& X) {
541 Row<N,E> result;
542 for (int i = 0; i < N; ++i)
543 result[i] = X*v[i];
544 return result;
545 }
546 template <class P, int M, int N, class E, int CS, int RS> inline Mat<M,N,E>
547 operator*(const Transform_<P>& X, const Mat<M,N,E,CS,RS>& v) {
548 Mat<M,N,E> result;
549 for (int i = 0; i < M; ++i)
550 for (int j = 0; j < N; ++j)
551 result(i, j) = X*v(i, j);
552 return result;
553 }
554 template <class P, int M, int N, class E, int CS, int RS> inline Mat<M,N,E>
555 operator*(const Mat<M,N,E,CS,RS>& v, const Transform_<P>& X) {
556 Mat<M,N,E> result;
557 for (int i = 0; i < M; ++i)
558 for (int j = 0; j < N; ++j)
559 result(i, j) = X*v(i, j);
560 return result;
561 }
562
563 // These Transform definitions had to wait for InverseTransform to be declared.
564
565 template <class P> inline Transform_<P>&
566 Transform_<P>::operator=( const InverseTransform_<P>& X ) {
567 // Be careful to do this in the right order in case X and this
568 // are the same object, i.e. we're doing X = ~X, inverting X in place.
569 p_BF = X.p(); // This might change X.p ...
570 R_BF = X.R(); // ... but this doesn't depend on X.p.
571 return *this;
572 }
573
574 template <class P> inline Transform_<P>
compose(const InverseTransform_<P> & X_FY)575 Transform_<P>::compose( const InverseTransform_<P>& X_FY ) const {
576 return Transform_<P>( R_BF * X_FY.R(), p_BF + R_BF * X_FY.p() );
577 }
578
579 /// Composition of transforms. Operators are provided for all the combinations
580 /// of transform and inverse transform.
581 /// @relates Transform_
582 template <class P> inline Transform_<P>
583 operator*(const Transform_<P>& X1, const Transform_<P>& X2) {return X1.compose(X2);}
584 template <class P> inline Transform_<P>
585 operator*(const Transform_<P>& X1, const InverseTransform_<P>& X2) {return X1.compose(X2);}
586 template <class P> inline Transform_<P>
587 operator*(const InverseTransform_<P>& X1, const Transform_<P>& X2) {return X1.compose(X2);}
588 template <class P> inline Transform_<P>
589 operator*(const InverseTransform_<P>& X1, const InverseTransform_<P>& X2) {return X1.compose(X2);}
590
591 /// Comparison operators return true only if the two transforms are bit
592 /// identical; that's not too useful.
593 /// @relates Transform_
594 template <class P> inline bool
595 operator==(const Transform_<P>& X1, const Transform_<P>& X2) {return X1.R()==X2.R() && X1.p()==X2.p();}
596 template <class P> inline bool
597 operator==(const InverseTransform_<P>& X1, const InverseTransform_<P>& X2) {return X1.R()==X2.R() && X1.p()==X2.p();}
598 template <class P> inline bool
599 operator==(const Transform_<P>& X1, const InverseTransform_<P>& X2) {return X1.R()==X2.R() && X1.p()==X2.p();}
600 template <class P> inline bool
601 operator==(const InverseTransform_<P>& X1, const Transform_<P>& X2) {return X1.R()==X2.R() && X1.p()==X2.p();}
602
603 /// Generate formatted output of a Transform to an output stream.
604 /// @relates Transform_
605 template <class P> SimTK_SimTKCOMMON_EXPORT std::ostream&
606 operator<<(std::ostream&, const Transform_<P>&);
607 /// Generate formatted output of an InverseTransform to an output stream.
608 /// @relates InverseTransform_
609 template <class P> SimTK_SimTKCOMMON_EXPORT std::ostream&
610 operator<<(std::ostream&, const InverseTransform_<P>&);
611
612
613
614 //------------------------------------------------------------------------------
615 } // End of namespace SimTK
616
617 //--------------------------------------------------------------------------
618 #endif // SimTK_SimTKCOMMON_TRANSFORM_H
619 //--------------------------------------------------------------------------
620
621