Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
AffineXform.hpp
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 #ifndef MOAB_AFFINE_XFORM_HPP
17 #define MOAB_AFFINE_XFORM_HPP
18 
19 #include "moab/Forward.hpp"
20 #include "moab/CartVect.hpp"
21 #include "moab/Matrix3.hpp"
22 
23 #include <cmath>
24 #include <limits>
25 
26 namespace moab
27 {
28 
29 /**
30  * \brief Define an affine transformation
31  * \author Jason Kraftcheck ([email protected])
32  * \date August, 2006
33  */
35 {
36  public:
37  inline AffineXform();
38 
39  inline AffineXform( const double* three_by_three, const double* translation );
40 
41  inline AffineXform( const Matrix3& mat, const CartVect& off );
42 
43  /** move */
44  static inline AffineXform translation( const double* vector );
45  /** rotate about axis through origin */
46  static inline AffineXform rotation( double radians, const double* axis );
47  /** define rotation such that if applied to \c from_vec the result aligned with \c to_vec */
48  static AffineXform rotation( const double* from_vec, const double* to_vec );
49  /** reflect about plane through origin */
50  static inline AffineXform reflection( const double* plane_normal );
51  /** scale about origin */
52  static inline AffineXform scale( double f );
53  /** scale about origin */
54  static inline AffineXform scale( const double* fractions );
55  /** scale about a point */
56  static inline AffineXform scale( double f, const double* point );
57  /** scale about a point */
58  static inline AffineXform scale( const double* fractions, const double* point );
59 
60  /** incorporate the passed transform into this one such that the
61  * resulting transform is the cumulative affect of this initial
62  * transform followed by the passed transform */
63  inline void accumulate( const AffineXform& other );
64 
65  /** apply transform to a point */
66  inline void xform_point( const double* input, double* output ) const;
67  /** apply transform to a point */
68  inline void xform_point( double* in_out ) const;
69 
70  /** apply transform to a vector */
71  inline void xform_vector( const double* input, double* output ) const;
72  /** apply transform to a vector */
73  inline void xform_vector( double* in_out ) const;
74 
75  /** get transform that is the inverse of this transform */
76  AffineXform inverse() const;
77 
78  /** get a tag that can be used to store an instance of this class */
79  static ErrorCode get_tag( Tag& tag_handle_out, Interface* moab, const char* tagname = 0 );
80 
81  /** get 3x3 matrix portion of transform */
82  const Matrix3& matrix() const
83  {
84  return mMatrix;
85  }
86  /** get translation portion of transform */
87  const CartVect& offset() const
88  {
89  return mOffset;
90  }
91 
92  /** Is this transform a reflection
93  *
94  * A relfecting transform will require the reversal of the
95  * order of edges in a loop, etc. because it produces a
96  * mirror-image of the input geometry. This method tests
97  * if this is such a transform. A reflection may be created
98  * with by an explicit transform, scaling with a negative
99  * scale factor, etc. If multiple transforms are combined
100  * such that the transform is no longer a reflection (e.g.
101  * two reflections that are effectively a rotation), this method
102  * will return false.
103  */
104  inline bool reflection() const;
105 
106  /** Does this transform do any scaling */
107  inline bool scale() const;
108 
109  private:
110  static inline AffineXform rotation( double cos_angle, double sin_angle, const CartVect& unit_axis );
111 
114 };
115 
116 /** create a new transform equivalent to transform \c A followed
117  * by transform \c B
118  */
119 inline AffineXform operator*( const AffineXform& A, const AffineXform& B )
120 {
121  AffineXform result( A );
122  result.accumulate( B );
123  return result;
124 }
125 
126 inline AffineXform::AffineXform() : mMatrix( 1.0 ), mOffset( 0.0 ) {}
127 
128 inline AffineXform::AffineXform( const double* three_by_three, const double* trans )
129  : mMatrix( three_by_three ), mOffset( trans )
130 {
131 }
132 
133 inline AffineXform::AffineXform( const Matrix3& mat, const CartVect& off ) : mMatrix( mat ), mOffset( off ) {}
134 
135 inline AffineXform AffineXform::translation( const double* vector )
136 {
137  return AffineXform( Matrix3( 1.0 ), CartVect( vector ) );
138 }
139 
140 inline AffineXform AffineXform::rotation( double angle, const double* axis )
141 {
142  CartVect a( axis );
143  a.normalize();
144  return AffineXform::rotation( std::cos( angle ), std::sin( angle ), a );
145 }
146 
147 inline AffineXform AffineXform::rotation( double c, double s, const CartVect& a )
148 {
149  const Matrix3 m1( c, -a[2] * s, a[1] * s, a[2] * s, c, -a[0] * s, -a[1] * s, a[0] * s, c );
150  return AffineXform( m1 + ( 1.0 - c ) * outer_product( a, a ), CartVect( 0.0 ) );
151 }
152 
153 inline AffineXform AffineXform::reflection( const double* plane_normal )
154 {
155  double i = plane_normal[0];
156  double j = plane_normal[1];
157  double k = plane_normal[2];
158  Matrix3 m( j * j + k * k - i * i, -2.0 * i * j, -2.0 * i * k, -2.0 * i * j, i * i + k * k - j * j, -2.0 * j * k,
159  -2.0 * i * k, -2.0 * j * k, i * i + j * j - k * k );
160  m *= 1.0 / ( i * i + j * j + k * k ); // normalize
161  return AffineXform( m, CartVect( 0.0 ) );
162 }
163 
164 inline AffineXform AffineXform::scale( const double* f )
165 {
166  return AffineXform( Matrix3( CartVect( f ) ), CartVect( 0.0 ) );
167 }
168 
169 inline AffineXform AffineXform::scale( double f )
170 {
171  return AffineXform( Matrix3( CartVect( f ) ), CartVect( 0.0 ) );
172 }
173 
174 inline AffineXform AffineXform::scale( double f, const double* point )
175 {
176  double fs[] = { f, f, f };
177  return AffineXform::scale( fs, point );
178 }
179 
180 inline AffineXform AffineXform::scale( const double* f, const double* p )
181 {
182  double offset[] = { p[0] * ( 1 - f[0] ), p[1] * ( 1 - f[1] ), p[2] * ( 1 - f[2] ) };
183  return AffineXform( Matrix3( CartVect( f ) ), CartVect( offset ) );
184 }
185 
186 inline void AffineXform::accumulate( const AffineXform& other )
187 {
188  mMatrix = other.mMatrix * mMatrix;
189  other.xform_point( mOffset.array() );
190 }
191 
192 inline void AffineXform::xform_point( const double* input, double* output ) const
193 {
194  xform_vector( input, output );
195  output[0] += mOffset[0];
196  output[1] += mOffset[1];
197  output[2] += mOffset[2];
198 }
199 
200 inline void AffineXform::xform_point( double* in_out ) const
201 {
202  xform_vector( in_out );
203  in_out[0] += mOffset[0];
204  in_out[1] += mOffset[1];
205  in_out[2] += mOffset[2];
206 }
207 
208 inline void AffineXform::xform_vector( const double* input, double* output ) const
209 {
210  output[0] = input[0] * mMatrix[0][0] + input[1] * mMatrix[0][1] + input[2] * mMatrix[0][2];
211  output[1] = input[0] * mMatrix[1][0] + input[1] * mMatrix[1][1] + input[2] * mMatrix[1][2];
212  output[2] = input[0] * mMatrix[2][0] + input[1] * mMatrix[2][1] + input[2] * mMatrix[2][2];
213 }
214 
215 inline void AffineXform::xform_vector( double* in_out ) const
216 {
217  double input[] = { in_out[0], in_out[1], in_out[2] };
218  xform_vector( input, in_out );
219 }
220 
222 {
223  Matrix3 m = mMatrix.inverse();
224  return AffineXform( m, m * -mOffset );
225 }
226 
227 inline bool AffineXform::reflection() const
228 {
229  return mMatrix.determinant() < 0.0;
230 }
231 
232 inline bool AffineXform::scale() const
233 {
234  return fabs( fabs( mMatrix.determinant() ) - 1 ) > std::numeric_limits< double >::epsilon();
235 }
236 
237 } // namespace moab
238 
239 #endif