1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2008-2015 Imperial College London
5  * Copyright 2008-2013 Daniel Rueckert, Julia Schnabel
6  * Copyright 2013-2015 Andreas Schuh
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef MIRTK_MultiLevelTransformation_H
22 #define MIRTK_MultiLevelTransformation_H
23 
24 #include "mirtk/Transformation.h"
25 #include "mirtk/RigidTransformation.h"
26 #include "mirtk/AffineTransformation.h"
27 #include "mirtk/FreeFormTransformation.h"
28 
29 #include <cstdlib>
30 #include <iostream>
31 
32 
33 namespace mirtk {
34 
35 
36 const int MAX_TRANS = 200;
37 
38 
39 /**
40  * Base class for multi-level transformations.
41  *
42  * This is the abstract base class which defines a common interface for all
43  * multi-level transformations. Each derived class has to implement at least
44  * the abstract methods and some of the virtual ones. Most other methods call
45  * these virtual methods and should not be required to be overridden in
46  * subclasses.
47  */
48 class MultiLevelTransformation : public Transformation
49 {
50   mirtkAbstractTransformationMacro(MultiLevelTransformation);
51 
52 public:
53 
54   /// Type of local transformation status
55   typedef Status FFDStatus;
56 
57 protected:
58 
59   // ---------------------------------------------------------------------------
60   // Data members
61 
62   /// Global transformation
63   AffineTransformation _GlobalTransformation;
64 
65   /// Local transformations
66   FreeFormTransformation *_LocalTransformation[MAX_TRANS];
67 
68   /// Whether this class is responsible for destructing the local transformation
69   bool _LocalTransformationOwner[MAX_TRANS];
70 
71   /// Status of local transformations
72   FFDStatus _LocalTransformationStatus[MAX_TRANS];
73 
74   /// Number of local transformations
75   int _NumberOfLevels;
76 
77   // ---------------------------------------------------------------------------
78   // Construction/Destruction
79 
80   /// Default constructor
81   MultiLevelTransformation();
82 
83   /// Construct multi-level transformation given a rigid transformation
84   MultiLevelTransformation(const RigidTransformation &);
85 
86   /// Construct multi-level transformation given an affine transformation
87   MultiLevelTransformation(const AffineTransformation &);
88 
89   /// Copy constructor
90   MultiLevelTransformation(const MultiLevelTransformation &);
91 
92 public:
93 
94   /// Destructor
95   virtual ~MultiLevelTransformation();
96 
97   // ---------------------------------------------------------------------------
98   // Approximation
99 
100   /// Approximate displacements: This function takes a set of points and a set
101   /// of displacements and finds a transformation which approximates these
102   /// displacements. After approximation, the displacements are replaced by the
103   /// residual displacement errors at the points.
104   ///
105   /// \note This function does not change the global transformation.
106   ///       Use ApproximateAsNew to also approximate a new global transformation.
107   virtual double Approximate(const ImageAttributes &, double *, double *, double *,
108                              int = 1, double = .0);
109 
110   /// Approximate displacements: This function takes a set of points and a set
111   /// of displacements and finds a transformation which approximates these
112   /// displacements. After approximation, the displacements are replaced by the
113   /// residual displacement errors at the points.
114   ///
115   /// \note This function does not change the global transformation.
116   ///       Use ApproximateAsNew to also approximate a new global transformation.
117   virtual double Approximate(const double *, const double *, const double *,
118                              double *,       double *,       double *, int,
119                              int = 1, double = .0);
120 
121   /// Approximate displacements: This function takes a set of points and a set
122   /// of displacements and finds a transformation which approximates these
123   /// displacements. After approximation, the displacements are replaced by the
124   /// residual displacement errors at the points.
125   ///
126   /// \note This function does not change the global transformation.
127   ///       Use ApproximateAsNew to also approximate a new global transformation.
128   virtual double Approximate(const double *, const double *, const double *, const double *,
129                              double *,       double *,       double *,       int,
130                              int = 1, double = .0);
131 
132   /// Approximate displacements: This function takes a set of points and a set
133   /// of displacements and finds a !new! transformation which approximates these
134   /// displacements. After approximation, the displacements are replaced by the
135   /// residual displacement errors at the points.
136   ///
137   /// \note This function also modifies the global transformation.
138   ///       Use Reset and Approximate instead if this is not desired.
139   virtual double ApproximateAsNew(const ImageAttributes &, double *, double *, double *,
140                                   int = 1, double = .0);
141 
142   /// Approximate displacements: This function takes a set of points and a set
143   /// of displacements and finds a !new! transformation which approximates these
144   /// displacements. After approximation, the displacements are replaced by the
145   /// residual displacement errors at the points.
146   ///
147   /// \note This function also modifies the global transformation.
148   ///       Use Reset and Approximate instead if this is not desired.
149   virtual double ApproximateAsNew(const double *, const double *, const double *,
150                                   double *,       double *,       double *, int,
151                                   int = 1, double = .0);
152 
153   /// Approximate displacements: This function takes a set of points and a set
154   /// of displacements and finds a !new! transformation which approximates these
155   /// displacements. After approximation, the displacements are replaced by the
156   /// residual displacement errors at the points.
157   ///
158   /// \note This function also modifies the global transformation.
159   ///       Use Reset and Approximate instead if this is not desired.
160   virtual double ApproximateAsNew(const double *, const double *, const double *, const double *,
161                                   double *,       double *,       double *,       int,
162                                   int = 1, double = .0);
163 
164   /// Approximate displacements: This function takes a set of points and a set
165   /// of displacements and finds !new! parameters such that the resulting
166   /// transformation approximates the displacements as good as possible.
167   virtual void ApproximateDOFs(const double *, const double *, const double *, const double *,
168                                const double *, const double *, const double *, int);
169 
170   /// Finds gradient of approximation error: This function takes a set of points
171   /// and a set of errors. It finds a gradient w.r.t. the transformation parameters
172   /// which minimizes the L2 norm of the approximation error and adds it to the
173   /// input gradient with the given weight.
174   virtual void ApproximateDOFsGradient(const double *, const double *, const double *, const double *,
175                                        const double *, const double *, const double *, int,
176                                        double *, double = 1.0) const;
177 
178   // ---------------------------------------------------------------------------
179   // Transformation parameters (DoFs)
180 
181   /// Copy active transformation parameters (DoFs) from given
182   /// transformation if possible and return \c false, otherwise
183   virtual bool CopyFrom(const Transformation *);
184 
185   /// Get norm of the gradient vector
186   virtual double DOFGradientNorm(const double *) const;
187 
188   /// Get number of transformation parameters
189   virtual int NumberOfDOFs() const;
190 
191   /// Put value of transformation parameter
192   virtual void Put(int, double);
193 
194   /// Put values of transformation parameters
195   virtual void Put(const DOFValue *);
196 
197   /// Add change to transformation parameters
198   virtual void Add(const DOFValue *);
199 
200   /// Update transformation parameters given parametric gradient
201   virtual double Update(const DOFValue *);
202 
203   /// Get value of transformation parameter
204   virtual double Get(int) const;
205 
206   /// Get values of transformation parameters
207   virtual void Get(DOFValue *) const;
208 
209   /// Put status of transformation parameter
210   virtual void PutStatus(int, DOFStatus);
211 
212   /// Get status of transformation parameter
213   virtual DOFStatus GetStatus(int) const;
214 
215   /// Checks whether transformation depends on the same vector of parameters
216   virtual bool HasSameDOFsAs(const Transformation *) const;
217 
218   /// Checks whether transformation is an identity mapping
219   virtual bool IsIdentity() const;
220 
221   /// Reset transformation (does not remove local transformations)
222   virtual void Reset();
223 
224   /// Reset transformation and remove all local transformations
225   virtual void Clear();
226 
227   // ---------------------------------------------------------------------------
228   // Parameters (non-DoFs)
229 
230   // Import other overloads
231   using Transformation::Parameter;
232 
233   /// Set named (non-DoF) parameter from value as string
234   virtual bool Set(const char *, const char *);
235 
236   /// Get (non-DoF) parameters as key/value as string map
237   virtual ParameterList Parameter() const;
238 
239   // ---------------------------------------------------------------------------
240   // Levels
241 
242   /// Returns the number of levels
243   virtual int NumberOfLevels() const;
244 
245   /// Returns the number of active levels
246   virtual int NumberOfActiveLevels() const;
247 
248   /// Returns the number of passive levels
249   virtual int NumberOfPassiveLevels() const;
250 
251   /// Returns the total number of control points
252   virtual int NumberOfCPs(bool = false) const;
253 
254   /// Returns the total number of active control points on all active levels
255   virtual int NumberOfActiveCPs() const;
256 
257   /// Gets global transformation
258   virtual AffineTransformation *GetGlobalTransformation();
259 
260   /// Get global transformation
261   virtual const AffineTransformation *GetGlobalTransformation() const;
262 
263   /// Gets local transformation
264   virtual FreeFormTransformation *GetLocalTransformation(int);
265 
266   /// Gets local transformation
267   virtual const FreeFormTransformation *GetLocalTransformation(int) const;
268 
269   /// Put local transformation and return pointer to previous one (needs to be deleted if not used)
270   virtual FreeFormTransformation *PutLocalTransformation(FreeFormTransformation *, int, bool = true);
271 
272   /// Push local transformation on stack (append transformation)
273   virtual void PushLocalTransformation(FreeFormTransformation *, bool = true);
274 
275   /// Insert local transformation
276   virtual void InsertLocalTransformation(FreeFormTransformation *, int = 0, bool = true);
277 
278   /// Pop local transformation from stack (remove last transformation)
279   virtual FreeFormTransformation *PopLocalTransformation();
280 
281   /// Remove local transformation and return the pointer (need to be deleted if not used)
282   virtual FreeFormTransformation *RemoveLocalTransformation(int = 0);
283 
284   /// Combine local transformations on stack
285   virtual void CombineLocalTransformation();
286 
287   /// Put status of local transformation
288   virtual void LocalTransformationStatus(int, FFDStatus);
289 
290   /// Get status of local transformation
291   virtual FFDStatus LocalTransformationStatus(int) const;
292 
293   /// Get whether local transformation is active
294   virtual bool LocalTransformationIsActive(int) const;
295 
296   /// Convert the global transformation from a matrix representation to a
297   /// FFD and incorporate it with any existing local transformation
298   virtual void MergeGlobalIntoLocalDisplacement();
299 
300 protected:
301 
302   /// Checks whether a given transformation is supported as local transformation
303   virtual void CheckTransformation(FreeFormTransformation *) const;
304 
305   /// Helper function for MergeGlobalIntoLocalDisplacement
306   void InterpolateGlobalDisplacement(FreeFormTransformation *);
307 
308 public:
309 
310   // ---------------------------------------------------------------------------
311   // Point transformation
312 
313   // Do not hide methods of base class
314   using Transformation::Transform;
315   using Transformation::LocalDisplacement;
316   using Transformation::Displacement;
317   using Transformation::Inverse;
318   using Transformation::LocalInverseDisplacement;
319   using Transformation::InverseDisplacement;
320 
321   /// Whether the caching of the transformation displacements is required
322   /// (or preferred) by this transformation. For some transformations such as
323   /// those parameterized by velocities, caching of the displacements for
324   /// each target voxel results in better performance or is needed for example
325   /// for the scaling and squaring method.
326   virtual bool RequiresCachingOfDisplacements() const;
327 
328   /// Transforms a single point using the global transformation component only
329   virtual void GlobalTransform(double &, double &, double &, double = 0, double = NaN) const;
330 
331   /// Transforms a single point using the local transformation component only
332   virtual void LocalTransform(int, int, double &, double &, double &, double = 0, double = NaN) const;
333 
334   /// Transforms a single point using the local transformation component only
335   virtual void LocalTransform(int, double &, double &, double &, double = 0, double = NaN) const;
336 
337   /// Transforms a single point using the local transformation component only
338   virtual void LocalTransform(double &, double &, double &, double = 0, double = NaN) const;
339 
340   /// Transforms a single point
341   virtual void Transform(int, int, double &, double &, double &, double = 0, double = NaN) const = 0;
342 
343   /// Transforms a single point
344   virtual void Transform(int, double &, double &, double &, double = 0, double = NaN) const;
345 
346   /// Transforms a single point
347   virtual void Transform(double &, double &, double &, double = 0, double = NaN) const;
348 
349   /// Transforms a single point
350   virtual void Transform(int, int, Point &, double = 0, double = NaN) const;
351 
352   /// Transforms a single point
353   virtual void Transform(int, Point &, double = 0, double = NaN) const;
354 
355   /// Transforms a set of points
356   virtual void Transform(int, int, PointSet &, double = 0, double = NaN) const;
357 
358   /// Transforms a set of points
359   virtual void Transform(int, PointSet &, double = 0, double = NaN) const;
360 
361   /// Calculates the displacement of a single point using the local transformation component only
362   virtual void LocalDisplacement(int, int, double &, double &, double &, double = 0, double = NaN) const;
363 
364   /// Calculates the displacement of a single point using the local transformation component only
365   virtual void LocalDisplacement(int, double &, double &, double &, double = 0, double = NaN) const;
366 
367   /// Calculates the displacement of a single point
368   virtual void Displacement(int, int, double &, double &, double &, double = 0, double = NaN) const;
369 
370   /// Calculates the displacement of a single point
371   virtual void Displacement(int, double &, double &, double &, double = 0, double = NaN) const;
372 
373   /// Calculates the displacement vectors for a whole image domain
374   virtual void Displacement(int, int, GenericImage<double> &, double = NaN, const WorldCoordsImage * = NULL) const;
375 
376   /// Calculates the displacement vectors for a whole image domain
377   virtual void Displacement(int, int, GenericImage<float> &, double = NaN, const WorldCoordsImage * = NULL) const;
378 
379   /// Calculates the displacement vectors for a whole image domain
380   virtual void Displacement(int, GenericImage<double> &, double = NaN, const WorldCoordsImage * = NULL) const;
381 
382   /// Calculates the displacement vectors for a whole image domain
383   virtual void Displacement(int, GenericImage<float> &, double = NaN, const WorldCoordsImage * = NULL) const;
384 
385   /// Calculates the displacement vectors for a whole image domain
386   ///
387   /// \attention The displacements are computed at the positions after applying the
388   ///            current displacements at each voxel. These displacements are then
389   ///            added to the current displacements. Therefore, set the input
390   ///            displacements to zero if only interested in the displacements of
391   ///            this transformation at the voxel positions.
392   virtual void Displacement(int, int, GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
393 
394   /// Calculates the displacement vectors for a whole image domain
395   ///
396   /// \attention The displacements are computed at the positions after applying the
397   ///            current displacements at each voxel. These displacements are then
398   ///            added to the current displacements. Therefore, set the input
399   ///            displacements to zero if only interested in the displacements of
400   ///            this transformation at the voxel positions.
401   virtual void Displacement(int, int, GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
402 
403   /// Calculates the displacement vectors for a whole image domain
404   ///
405   /// \attention The displacements are computed at the positions after applying the
406   ///            current displacements at each voxel. These displacements are then
407   ///            added to the current displacements. Therefore, set the input
408   ///            displacements to zero if only interested in the displacements of
409   ///            this transformation at the voxel positions.
410   virtual void Displacement(int, GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
411 
412   /// Calculates the displacement vectors for a whole image domain
413   ///
414   /// \attention The displacements are computed at the positions after applying the
415   ///            current displacements at each voxel. These displacements are then
416   ///            added to the current displacements. Therefore, set the input
417   ///            displacements to zero if only interested in the displacements of
418   ///            this transformation at the voxel positions.
419   virtual void Displacement(int, GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
420 
421   /// Calculates the displacement vectors for a whole image domain
422   ///
423   /// \attention The displacements are computed at the positions after applying the
424   ///            current displacements at each voxel. These displacements are then
425   ///            added to the current displacements. Therefore, set the input
426   ///            displacements to zero if only interested in the displacements of
427   ///            this transformation at the voxel positions.
428   virtual void Displacement(GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
429 
430   /// Calculates the displacement vectors for a whole image domain
431   ///
432   /// \attention The displacements are computed at the positions after applying the
433   ///            current displacements at each voxel. These displacements are then
434   ///            added to the current displacements. Therefore, set the input
435   ///            displacements to zero if only interested in the displacements of
436   ///            this transformation at the voxel positions.
437   virtual void Displacement(GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
438 
439   /// Transforms a single point using the inverse of the global transformation only
440   virtual void GlobalInverse(double &, double &, double &, double = 0, double = NaN) const;
441 
442   /// Transforms a single point using the inverse of the local transformation only
443   virtual bool LocalInverse(int, int, double &, double &, double &, double = 0, double = NaN) const;
444 
445   /// Transforms a single point using the inverse of the local transformation only
446   virtual bool LocalInverse(int, double &, double &, double &, double = 0, double = NaN) const;
447 
448   /// Transforms a single point using the inverse of the local transformation only
449   virtual bool LocalInverse(double &, double &, double &, double = 0, double = NaN) const;
450 
451   /// Transforms a single point using the inverse of the transformation
452   virtual bool Inverse(int, int, double &, double &, double &, double = 0, double = NaN) const;
453 
454   /// Transforms a single point using the inverse of the transformation
455   virtual bool Inverse(int, double &, double &, double &, double = 0, double = NaN) const;
456 
457   /// Transforms a single point using the inverse of the transformation
458   virtual bool Inverse(double &, double &, double &, double = 0, double = NaN) const;
459 
460   /// Calculates the displacement of a single point using the inverse of the local transformation only
461   virtual bool LocalInverseDisplacement(int, int, double &, double &, double &, double = 0, double = NaN) const;
462 
463   /// Calculates the displacement of a single point using the inverse of the local transformation only
464   virtual bool LocalInverseDisplacement(int, double &, double &, double &, double = 0, double = NaN) const;
465 
466   /// Calculates the displacement of a single point using the inverse of the transformation
467   virtual bool InverseDisplacement(int, int, double &, double &, double &, double = 0, double = NaN) const;
468 
469   /// Calculates the displacement of a single point using the inverse of the transformation
470   virtual bool InverseDisplacement(int, double &, double &, double &, double = 0, double = NaN) const;
471 
472   /// Calculates the inverse displacement vectors for a whole image domain
473   ///
474   /// \attention The displacements are computed at the positions after applying the
475   ///            current displacements at each voxel. These displacements are then
476   ///            added to the current displacements. Therefore, set the input
477   ///            displacements to zero if only interested in the displacements of
478   ///            this transformation at the voxel positions.
479   ///
480   /// \returns Number of points at which transformation is non-invertible.
481   virtual int InverseDisplacement(int, int, GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
482 
483   /// Calculates the inverse displacement vectors for a whole image domain
484   ///
485   /// \attention The displacements are computed at the positions after applying the
486   ///            current displacements at each voxel. These displacements are then
487   ///            added to the current displacements. Therefore, set the input
488   ///            displacements to zero if only interested in the displacements of
489   ///            this transformation at the voxel positions.
490   ///
491   /// \returns Number of points at which transformation is non-invertible.
492   virtual int InverseDisplacement(int, int, GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
493 
494   /// Calculates the inverse displacement vectors for a whole image domain
495   ///
496   /// \attention The displacements are computed at the positions after applying the
497   ///            current displacements at each voxel. These displacements are then
498   ///            added to the current displacements. Therefore, set the input
499   ///            displacements to zero if only interested in the displacements of
500   ///            this transformation at the voxel positions.
501   ///
502   /// \returns Number of points at which transformation is non-invertible.
503   virtual int InverseDisplacement(int, GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
504 
505   /// Calculates the inverse displacement vectors for a whole image domain
506   ///
507   /// \attention The displacements are computed at the positions after applying the
508   ///            current displacements at each voxel. These displacements are then
509   ///            added to the current displacements. Therefore, set the input
510   ///            displacements to zero if only interested in the displacements of
511   ///            this transformation at the voxel positions.
512   ///
513   /// \returns Number of points at which transformation is non-invertible.
514   virtual int InverseDisplacement(int, GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
515 
516   /// Calculates the inverse displacement vectors for a whole image domain
517   ///
518   /// \attention The displacements are computed at the positions after applying the
519   ///            current displacements at each voxel. These displacements are then
520   ///            added to the current displacements. Therefore, set the input
521   ///            displacements to zero if only interested in the displacements of
522   ///            this transformation at the voxel positions.
523   ///
524   /// \returns Number of points at which transformation is non-invertible.
525   virtual int InverseDisplacement(GenericImage<double> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
526 
527   /// Calculates the inverse displacement vectors for a whole image domain
528   ///
529   /// \attention The displacements are computed at the positions after applying the
530   ///            current displacements at each voxel. These displacements are then
531   ///            added to the current displacements. Therefore, set the input
532   ///            displacements to zero if only interested in the displacements of
533   ///            this transformation at the voxel positions.
534   ///
535   /// \returns Number of points at which transformation is non-invertible.
536   virtual int InverseDisplacement(GenericImage<float> &, double, double = NaN, const WorldCoordsImage * = NULL) const;
537 
538   // ---------------------------------------------------------------------------
539   // Derivatives
540 
541   // Do not hide methods of base class
542   using Transformation::GlobalJacobian;
543   using Transformation::LocalJacobian;
544   using Transformation::Jacobian;
545 
546   /// Calculates the Jacobian of the global transformation w.r.t world coordinates
547   virtual void GlobalJacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
548 
549   /// Calculates the Jacobian of the local transformation w.r.t world coordinates
550   virtual void LocalJacobian(int, Matrix &, double, double, double, double = 0, double = NaN) const;
551 
552   /// Calculates the Jacobian of the local transformation w.r.t world coordinates
553   virtual void LocalJacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
554 
555   /// Calculates the Jacobian of the transformation w.r.t world coordinates
556   virtual void Jacobian(int, int, Matrix &, double, double, double, double = 0, double = NaN) const;
557 
558   /// Calculates the Jacobian of the transformation w.r.t world coordinates
559   virtual void Jacobian(int, Matrix &, double, double, double, double = 0, double = NaN) const;
560 
561   /// Calculates the Jacobian of the transformation w.r.t world coordinates
562   virtual void Jacobian(Matrix &, double, double, double, double = 0, double = NaN) const;
563 
564   /// Calculates the determinant of the Jacobian of the local transformation w.r.t world coordinates
565   virtual double LocalJacobian(int, double, double, double, double = 0, double = NaN) const;
566 
567   /// Calculates the determinant of the Jacobian of the transformation w.r.t world coordinates
568   virtual double Jacobian(int, int, double, double, double, double = 0, double = NaN) const;
569 
570   /// Calculates the determinant of the Jacobian of the transformation w.r.t world coordinates
571   virtual double Jacobian(int, double, double, double, double = 0, double = NaN) const;
572 
573   /// Calculates the Hessian for each component of the global transformation w.r.t world coordinates
574   virtual void GlobalHessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
575 
576   /// Calculates the Hessian for each component of the local transformation w.r.t world coordinates
577   virtual void LocalHessian(int, Matrix [3], double, double, double, double = 0, double = NaN) const;
578 
579   /// Calculates the Hessian for each component of the local transformation w.r.t world coordinates
580   virtual void LocalHessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
581 
582   /// Calculates the Hessian for each component of the transformation w.r.t world coordinates
583   virtual void Hessian(int, int, Matrix [3], double, double, double, double = 0, double = NaN) const;
584 
585   /// Calculates the Hessian for each component of the transformation w.r.t world coordinates
586   virtual void Hessian(int, Matrix [3], double, double, double, double = 0, double = NaN) const;
587 
588   /// Calculates the Hessian for each component of the transformation w.r.t world coordinates
589   virtual void Hessian(Matrix [3], double, double, double, double = 0, double = NaN) const;
590 
591   /// Calculates the Jacobian of the transformation w.r.t the transformation parameters
592   virtual void JacobianDOFs(double [3], int, double, double, double, double = 0, double = NaN) const;
593 
594   /// Calculates the derivative of the Jacobian of the transformation (w.r.t. world coordinates) w.r.t. a transformation parameter
595   virtual void DeriveJacobianWrtDOF(Matrix &, int, double, double, double, double = 0, double = NaN) const;
596 
597   // ---------------------------------------------------------------------------
598   // Properties
599 
600   /// Calculates the bending energy of the transformation
601   virtual double BendingEnergy(int, int, double, double, double, double = 0, double = NaN, bool = true) const;
602 
603   /// Calculates the bending energy of the transformation
604   virtual double BendingEnergy(int, double, double, double, double = 0, double = NaN, bool = true) const;
605 
606   /// Calculates the bending energy of the transformation
607   virtual double BendingEnergy(double, double, double, double = 0, double = NaN, bool = true) const;
608 
609   // ---------------------------------------------------------------------------
610   // I/O
611 
612   // Do not hide methods of base class
613   using Transformation::Print;
614 
615   /// Prints the parameters of the transformation
616   virtual void Print(ostream &, Indent = 0) const;
617 
618 protected:
619 
620   /// Reads transformation parameters from a file stream
621   virtual Cifstream &ReadDOFs(Cifstream &, TransformationType);
622 
623   /// Writes transformation parameters to a file stream
624   virtual Cofstream &WriteDOFs(Cofstream &) const;
625 
626 };
627 
628 ////////////////////////////////////////////////////////////////////////////////
629 // Inline definitions
630 ////////////////////////////////////////////////////////////////////////////////
631 
632 // =============================================================================
633 // Transformation parameters
634 // =============================================================================
635 
636 // -----------------------------------------------------------------------------
DOFIndexToLocalTransformation(const MultiLevelTransformation * mffd,int idx,const FreeFormTransformation * & ffd,int & dof)637 inline int DOFIndexToLocalTransformation(const MultiLevelTransformation *mffd, int  idx,
638                                          const FreeFormTransformation   *&ffd, int &dof)
639 {
640   mirtkAssert(idx >= 0, "DoF index must be positive");
641   dof = idx;
642   for (int l = 0; l < mffd->NumberOfLevels(); ++l) {
643     if (!mffd->LocalTransformationIsActive(l)) continue;
644     ffd = mffd->GetLocalTransformation(l);
645     if (dof < ffd->NumberOfDOFs()) return l;
646     dof -= ffd->NumberOfDOFs();
647   }
648   ffd = NULL;
649   mirtkAssert(false, "DoF index out-of-bounds");
650   return -1;
651 }
652 
653 // -----------------------------------------------------------------------------
DOFIndexToLocalTransformation(MultiLevelTransformation * mffd,int idx,FreeFormTransformation * & ffd,int & dof)654 inline int DOFIndexToLocalTransformation(MultiLevelTransformation *mffd, int  idx,
655                                          FreeFormTransformation   *&ffd, int &dof)
656 {
657   mirtkAssert(idx >= 0, "DoF index must be positive");
658   dof = idx;
659   for (int l = 0; l < mffd->NumberOfLevels(); ++l) {
660     if (!mffd->LocalTransformationIsActive(l)) continue;
661     ffd = mffd->GetLocalTransformation(l);
662     if (dof < ffd->NumberOfDOFs()) return l;
663     dof -= ffd->NumberOfDOFs();
664   }
665   ffd = NULL;
666   mirtkAssert(false, "DoF index out-of-bounds");
667   return -1;
668 }
669 
670 // =============================================================================
671 // Levels
672 // =============================================================================
673 
674 // -----------------------------------------------------------------------------
NumberOfLevels()675 inline int MultiLevelTransformation::NumberOfLevels() const
676 {
677   return _NumberOfLevels;
678 }
679 
680 // -----------------------------------------------------------------------------
NumberOfActiveLevels()681 inline int MultiLevelTransformation::NumberOfActiveLevels() const
682 {
683   int n = 0;
684   for (int i = 0; i < _NumberOfLevels; ++i) {
685     if (_LocalTransformationStatus[i] == Active) ++n;
686   }
687   return n;
688 }
689 
690 // -----------------------------------------------------------------------------
NumberOfPassiveLevels()691 inline int MultiLevelTransformation::NumberOfPassiveLevels() const
692 {
693   return _NumberOfLevels - this->NumberOfActiveLevels();
694 }
695 
696 // -----------------------------------------------------------------------------
GetGlobalTransformation()697 inline AffineTransformation *MultiLevelTransformation::GetGlobalTransformation()
698 {
699   return &_GlobalTransformation;
700 }
701 
702 // -----------------------------------------------------------------------------
GetGlobalTransformation()703 inline const AffineTransformation *MultiLevelTransformation::GetGlobalTransformation() const
704 {
705   return &_GlobalTransformation;
706 }
707 
708 // -----------------------------------------------------------------------------
GetLocalTransformation(int i)709 inline FreeFormTransformation *MultiLevelTransformation::GetLocalTransformation(int i)
710 {
711   if (i < 0) i += _NumberOfLevels;
712   return (0 <= i && i < _NumberOfLevels) ? _LocalTransformation[i] : NULL;
713 }
714 
715 // -----------------------------------------------------------------------------
GetLocalTransformation(int i)716 inline const FreeFormTransformation *MultiLevelTransformation::GetLocalTransformation(int i) const
717 {
718   if (i < 0) i += _NumberOfLevels;
719   return (0 <= i && i < _NumberOfLevels) ? _LocalTransformation[i] : NULL;
720 }
721 
722 // -----------------------------------------------------------------------------
LocalTransformationStatus(int i,FFDStatus status)723 inline void MultiLevelTransformation::LocalTransformationStatus(int i, FFDStatus status)
724 {
725   if (i < 0) i += _NumberOfLevels;
726   _LocalTransformationStatus[i] = status;
727 }
728 
729 // -----------------------------------------------------------------------------
730 inline MultiLevelTransformation::FFDStatus
LocalTransformationStatus(int i)731 MultiLevelTransformation::LocalTransformationStatus(int i) const
732 {
733   if (i < 0) i += _NumberOfLevels;
734   return _LocalTransformationStatus[i];
735 }
736 
737 // -----------------------------------------------------------------------------
LocalTransformationIsActive(int i)738 inline bool MultiLevelTransformation::LocalTransformationIsActive(int i) const
739 {
740   if (i < 0) i += _NumberOfLevels;
741   return (_LocalTransformationStatus[i] == Active);
742 }
743 
744 // =============================================================================
745 // Point transformation
746 // =============================================================================
747 
748 // -----------------------------------------------------------------------------
RequiresCachingOfDisplacements()749 inline bool MultiLevelTransformation::RequiresCachingOfDisplacements() const
750 {
751   for (int i = 0; i < this->NumberOfLevels(); ++i) {
752     if (this->GetLocalTransformation(i)->RequiresCachingOfDisplacements()) return true;
753   }
754   return false;
755 }
756 
757 // -----------------------------------------------------------------------------
GlobalTransform(double & x,double & y,double & z,double t,double t0)758 inline void MultiLevelTransformation::GlobalTransform(double &x, double &y, double &z, double t, double t0) const
759 {
760   this->GetGlobalTransformation()->Transform(x, y, z, t, t0);
761 }
762 
763 // -----------------------------------------------------------------------------
764 // Note: The Transformation interface requires that every transformation is
765 //       the sum of global and local transformations, i.e., T = T_global + T_local.
766 //       This allows a common interpretation of what LocalTransform does.
LocalTransform(int m,int n,double & x,double & y,double & z,double t,double t0)767 inline void MultiLevelTransformation::LocalTransform(int m, int n, double &x, double &y, double &z, double t, double t0) const
768 {
769   if (m < 0) {
770     // Compute y = x + (T(x) - T_global(x))
771     double x1 = x, y1 = y, z1 = z;
772     double x2 = x, y2 = y, z2 = z;
773     this->GetGlobalTransformation()->Transform(x1, y1, z1);
774     this->Transform(-1, n, x2, y2, z2, t, t0);
775     x += (x2 - x1);
776     y += (y2 - y1);
777     z += (z2 - z1);
778   } else {
779     this->Transform(m, n, x, y, z, t, t0);
780   }
781 }
782 
783 // -----------------------------------------------------------------------------
LocalTransform(int n,double & x,double & y,double & z,double t,double t0)784 inline void MultiLevelTransformation::LocalTransform(int n, double &x, double &y, double &z, double t, double t0) const
785 {
786   this->LocalTransform(0, n, x, y, z, t, t0);
787 }
788 
789 // -----------------------------------------------------------------------------
LocalTransform(double & x,double & y,double & z,double t,double t0)790 inline void MultiLevelTransformation::LocalTransform(double &x, double &y, double &z, double t, double t0) const
791 {
792   this->LocalTransform(-1, x, y, z, t, t0);
793 }
794 
795 // -----------------------------------------------------------------------------
Transform(int n,double & x,double & y,double & z,double t,double t0)796 inline void MultiLevelTransformation::Transform(int n, double &x, double &y, double &z, double t, double t0) const
797 {
798   this->Transform(-1, n, x, y, z, t, t0);
799 }
800 
801 // -----------------------------------------------------------------------------
Transform(double & x,double & y,double & z,double t,double t0)802 inline void MultiLevelTransformation::Transform(double &x, double &y, double &z, double t, double t0) const
803 {
804   this->Transform(-1, x, y, z, t, t0);
805 }
806 
807 // -----------------------------------------------------------------------------
Transform(int l,int n,Point & p,double t,double t0)808 inline void MultiLevelTransformation::Transform(int l, int n, Point &p, double t, double t0) const
809 {
810   this->Transform(l, n, p._x, p._y, p._z, t, t0);
811 }
812 
813 // -----------------------------------------------------------------------------
Transform(int n,Point & p,double t,double t0)814 inline void MultiLevelTransformation::Transform(int n, Point &p, double t, double t0) const
815 {
816   this->Transform(0, n, p, t, t0);
817 }
818 
819 // -----------------------------------------------------------------------------
Transform(int l,int n,PointSet & pset,double t,double t0)820 inline void MultiLevelTransformation::Transform(int l, int n, PointSet &pset, double t, double t0) const
821 {
822   for (int i = 0; i < pset.Size(); i++) this->Transform(l, n, pset(i), t, t0);
823 }
824 
825 // -----------------------------------------------------------------------------
Transform(int n,PointSet & pset,double t,double t0)826 inline void MultiLevelTransformation::Transform(int n, PointSet &pset, double t, double t0) const
827 {
828   this->Transform(0, n, pset, t, t0);
829 }
830 
831 // -----------------------------------------------------------------------------
LocalDisplacement(int l,int n,double & x,double & y,double & z,double t,double t0)832 inline void MultiLevelTransformation::LocalDisplacement(int l, int n, double &x, double &y, double &z, double t, double t0) const
833 {
834   const double u = x;
835   const double v = y;
836   const double w = z;
837 
838   this->LocalTransform(l, n, x, y, z, t, t0);
839 
840   x -= u;
841   y -= v;
842   z -= w;
843 }
844 
845 // -----------------------------------------------------------------------------
LocalDisplacement(int n,double & x,double & y,double & z,double t,double t0)846 inline void MultiLevelTransformation::LocalDisplacement(int n, double &x, double &y, double &z, double t, double t0) const
847 {
848   this->LocalDisplacement(0, n, x, y, z, t, t0);
849 }
850 
851 // -----------------------------------------------------------------------------
Displacement(int l,int n,double & x,double & y,double & z,double t,double t0)852 inline void MultiLevelTransformation::Displacement(int l, int n, double &x, double &y, double &z, double t, double t0) const
853 {
854   const double u = x;
855   const double v = y;
856   const double w = z;
857 
858   this->Transform(l, n, x, y, z, t, t0);
859 
860   x -= u;
861   y -= v;
862   z -= w;
863 }
864 
865 // -----------------------------------------------------------------------------
Displacement(int n,double & x,double & y,double & z,double t,double t0)866 inline void MultiLevelTransformation::Displacement(int n, double &x, double &y, double &z, double t, double t0) const
867 {
868   this->Displacement(-1, n, x, y, z, t, t0);
869 }
870 
871 // -----------------------------------------------------------------------------
Displacement(int l,int n,GenericImage<double> & disp,double t0,const WorldCoordsImage * i2w)872 inline void MultiLevelTransformation::Displacement(int l, int n, GenericImage<double> &disp, double t0, const WorldCoordsImage *i2w) const
873 {
874   disp = .0;
875   this->Displacement(l, n, disp, disp.GetTOrigin(), t0, i2w);
876 }
877 
878 // -----------------------------------------------------------------------------
Displacement(int l,int n,GenericImage<float> & disp,double t0,const WorldCoordsImage * i2w)879 inline void MultiLevelTransformation::Displacement(int l, int n, GenericImage<float> &disp, double t0, const WorldCoordsImage *i2w) const
880 {
881   disp = .0f;
882   this->Displacement(l, n, disp, disp.GetTOrigin(), t0, i2w);
883 }
884 
885 // -----------------------------------------------------------------------------
Displacement(int n,GenericImage<double> & disp,double t0,const WorldCoordsImage * i2w)886 inline void MultiLevelTransformation::Displacement(int n, GenericImage<double> &disp, double t0, const WorldCoordsImage *i2w) const
887 {
888   this->Displacement(-1, n, disp, t0, i2w);
889 }
890 
891 // -----------------------------------------------------------------------------
Displacement(int n,GenericImage<float> & disp,double t0,const WorldCoordsImage * i2w)892 inline void MultiLevelTransformation::Displacement(int n, GenericImage<float> &disp, double t0, const WorldCoordsImage *i2w) const
893 {
894   this->Displacement(-1, n, disp, t0, i2w);
895 }
896 
897 // -----------------------------------------------------------------------------
Displacement(int n,GenericImage<double> & disp,double t,double t0,const WorldCoordsImage * wc)898 inline void MultiLevelTransformation::Displacement(int n, GenericImage<double> &disp, double t, double t0, const WorldCoordsImage *wc) const
899 {
900   this->Displacement(-1, n, disp, t, t0, wc);
901 }
902 
903 // -----------------------------------------------------------------------------
Displacement(int n,GenericImage<float> & disp,double t,double t0,const WorldCoordsImage * wc)904 inline void MultiLevelTransformation::Displacement(int n, GenericImage<float> &disp, double t, double t0, const WorldCoordsImage *wc) const
905 {
906   this->Displacement(-1, n, disp, t, t0, wc);
907 }
908 
909 // -----------------------------------------------------------------------------
Displacement(GenericImage<double> & disp,double t,double t0,const WorldCoordsImage * wc)910 inline void MultiLevelTransformation::Displacement(GenericImage<double> &disp, double t, double t0, const WorldCoordsImage *wc) const
911 {
912   this->Displacement(-1, disp, t, t0, wc);
913 }
914 
915 // -----------------------------------------------------------------------------
Displacement(GenericImage<float> & disp,double t,double t0,const WorldCoordsImage * wc)916 inline void MultiLevelTransformation::Displacement(GenericImage<float> &disp, double t, double t0, const WorldCoordsImage *wc) const
917 {
918   this->Displacement(-1, disp, t, t0, wc);
919 }
920 
921 // -----------------------------------------------------------------------------
GlobalInverse(double & x,double & y,double & z,double t,double t0)922 inline void MultiLevelTransformation::GlobalInverse(double &x, double &y, double &z, double t, double t0) const
923 {
924   this->GetGlobalTransformation()->Inverse(x, y, z, t, t0);
925 }
926 
927 // -----------------------------------------------------------------------------
928 // Note: The Transformation interface requires that every transformation is
929 //       the sum of global and local transformations, i.e., T = T_global + T_local.
930 //       This allows a common interpretation of what LocalTransform does.
LocalInverse(int m,int n,double & x,double & y,double & z,double t,double t0)931 inline bool MultiLevelTransformation::LocalInverse(int m, int n, double &x, double &y, double &z, double t, double t0) const
932 {
933   if (m < 0) {
934     // Compute y = x + (inv T(x) - inv T_global(x))
935     double x1 = x, y1 = y, z1 = z;
936     double x2 = x, y2 = y, z2 = z;
937     this->GetGlobalTransformation()->Inverse(x1, y1, z1);
938     bool ok = this->Inverse(-1, n, x2, y2, z2, t, t0);
939     x += (x2 - x1);
940     y += (y2 - y1);
941     z += (z2 - z1);
942     return ok;
943   } else {
944     return this->Inverse(m, n, x, y, z, t, t0);
945   }
946 }
947 
948 // -----------------------------------------------------------------------------
LocalInverse(int n,double & x,double & y,double & z,double t,double t0)949 inline bool MultiLevelTransformation::LocalInverse(int n, double &x, double &y, double &z, double t, double t0) const
950 {
951   return this->LocalInverse(0, n, x, y, z, t, t0);
952 }
953 
954 // -----------------------------------------------------------------------------
LocalInverse(double & x,double & y,double & z,double t,double t0)955 inline bool MultiLevelTransformation::LocalInverse(double &x, double &y, double &z, double t, double t0) const
956 {
957   return this->LocalInverse(-1, x, y, z, t, t0);
958 }
959 
960 // -----------------------------------------------------------------------------
Inverse(int n,double & x,double & y,double & z,double t,double t0)961 inline bool MultiLevelTransformation::Inverse(int n, double &x, double &y, double &z, double t, double t0) const
962 {
963   return this->Inverse(-1, n, x, y, z, t, t0);
964 }
965 
966 // -----------------------------------------------------------------------------
Inverse(double & x,double & y,double & z,double t,double t0)967 inline bool MultiLevelTransformation::Inverse(double &x, double &y, double &z, double t, double t0) const
968 {
969   return this->Inverse(-1, x, y, z, t, t0);
970 }
971 
972 // -----------------------------------------------------------------------------
LocalInverseDisplacement(int l,int n,double & x,double & y,double & z,double t,double t0)973 inline bool MultiLevelTransformation::LocalInverseDisplacement(int l, int n, double &x, double &y, double &z, double t, double t0) const
974 {
975   const double u = x;
976   const double v = y;
977   const double w = z;
978 
979   bool ok = this->LocalInverse(l, n, x, y, z, t, t0);
980 
981   x -= u;
982   y -= v;
983   z -= w;
984 
985   return ok;
986 }
987 
988 // -----------------------------------------------------------------------------
LocalInverseDisplacement(int n,double & x,double & y,double & z,double t,double t0)989 inline bool MultiLevelTransformation::LocalInverseDisplacement(int n, double &x, double &y, double &z, double t, double t0) const
990 {
991   return this->LocalInverseDisplacement(0, n, x, y, z, t, t0);
992 }
993 
994 // -----------------------------------------------------------------------------
InverseDisplacement(int l,int n,double & x,double & y,double & z,double t,double t0)995 inline bool MultiLevelTransformation::InverseDisplacement(int l, int n, double &x, double &y, double &z, double t, double t0) const
996 {
997   const double u = x;
998   const double v = y;
999   const double w = z;
1000 
1001   bool ok = this->Inverse(l, n, x, y, z, t, t0);
1002 
1003   x -= u;
1004   y -= v;
1005   z -= w;
1006 
1007   return ok;
1008 }
1009 
1010 // -----------------------------------------------------------------------------
InverseDisplacement(int n,double & x,double & y,double & z,double t,double t0)1011 inline bool MultiLevelTransformation::InverseDisplacement(int n, double &x, double &y, double &z, double t, double t0) const
1012 {
1013   return this->InverseDisplacement(-1, n, x, y, z, t, t0);
1014 }
1015 
1016 // -----------------------------------------------------------------------------
InverseDisplacement(int n,GenericImage<double> & disp,double t,double t0,const WorldCoordsImage * wc)1017 inline int MultiLevelTransformation::InverseDisplacement(int n, GenericImage<double> &disp, double t, double t0, const WorldCoordsImage *wc) const
1018 {
1019   return this->InverseDisplacement(-1, n, disp, t, t0, wc);
1020 }
1021 
1022 // -----------------------------------------------------------------------------
InverseDisplacement(int n,GenericImage<float> & disp,double t,double t0,const WorldCoordsImage * wc)1023 inline int MultiLevelTransformation::InverseDisplacement(int n, GenericImage<float> &disp, double t, double t0, const WorldCoordsImage *wc) const
1024 {
1025   return this->InverseDisplacement(-1, n, disp, t, t0, wc);
1026 }
1027 
1028 // -----------------------------------------------------------------------------
InverseDisplacement(GenericImage<double> & disp,double t,double t0,const WorldCoordsImage * wc)1029 inline int MultiLevelTransformation::InverseDisplacement(GenericImage<double> &disp, double t, double t0, const WorldCoordsImage *wc) const
1030 {
1031   return this->InverseDisplacement(-1, disp, t, t0, wc);
1032 }
1033 
1034 // -----------------------------------------------------------------------------
InverseDisplacement(GenericImage<float> & disp,double t,double t0,const WorldCoordsImage * wc)1035 inline int MultiLevelTransformation::InverseDisplacement(GenericImage<float> &disp, double t, double t0, const WorldCoordsImage *wc) const
1036 {
1037   return this->InverseDisplacement(-1, disp, t, t0, wc);
1038 }
1039 
1040 // =============================================================================
1041 // Derivatives
1042 // =============================================================================
1043 
1044 // -----------------------------------------------------------------------------
Jacobian(int,int,Matrix &,double,double,double,double,double)1045 inline void MultiLevelTransformation::Jacobian(int, int, Matrix &, double, double, double, double, double) const
1046 {
1047   cerr << this->NameOfClass() << "::Jacobian(int, int, ...): Not implemented" << endl;
1048   exit(1);
1049 }
1050 
1051 // -----------------------------------------------------------------------------
Jacobian(int n,Matrix & jac,double x,double y,double z,double t,double t0)1052 inline void MultiLevelTransformation::Jacobian(int n, Matrix &jac, double x, double y, double z, double t, double t0) const
1053 {
1054   this->Jacobian(-1, n, jac, x, y, z, t, t0);
1055 }
1056 
1057 // -----------------------------------------------------------------------------
Jacobian(Matrix & jac,double x,double y,double z,double t,double t0)1058 inline void MultiLevelTransformation::Jacobian(Matrix &jac, double x, double y, double z, double t, double t0) const
1059 {
1060   this->Jacobian(-1, -1, jac, x, y, z, t, t0);
1061 }
1062 
1063 // -----------------------------------------------------------------------------
GlobalJacobian(Matrix & jac,double x,double y,double z,double t,double t0)1064 inline void MultiLevelTransformation::GlobalJacobian(Matrix &jac, double x, double y, double z, double t, double t0) const
1065 {
1066   this->GetGlobalTransformation()->Jacobian(jac, x, y, z, t, t0);
1067 }
1068 
1069 // -----------------------------------------------------------------------------
LocalJacobian(int n,Matrix & jac,double x,double y,double z,double t,double t0)1070 inline void MultiLevelTransformation::LocalJacobian(int n, Matrix &jac, double x, double y, double z, double t, double t0) const
1071 {
1072   this->Jacobian(0, n, jac, x, y, z, t, t0);
1073 }
1074 
1075 // -----------------------------------------------------------------------------
LocalJacobian(Matrix & jac,double x,double y,double z,double t,double t0)1076 inline void MultiLevelTransformation::LocalJacobian(Matrix &jac, double x, double y, double z, double t, double t0) const
1077 {
1078   this->Jacobian(0, -1, jac, x, y, z, t, t0);
1079 }
1080 
1081 // -----------------------------------------------------------------------------
Jacobian(int m,int n,double x,double y,double z,double t,double t0)1082 inline double MultiLevelTransformation::Jacobian(int m, int n, double x, double y, double z, double t, double t0) const
1083 {
1084   Matrix jac(3, 3);
1085   this->Jacobian(m, n, jac, x, y, z, t, t0);
1086   return jac.Det3x3();
1087 }
1088 
1089 // -----------------------------------------------------------------------------
Jacobian(int n,double x,double y,double z,double t,double t0)1090 inline double MultiLevelTransformation::Jacobian(int n, double x, double y, double z, double t, double t0) const
1091 {
1092   return this->Jacobian(-1, n, x, y, z, t, t0);
1093 }
1094 
1095 // -----------------------------------------------------------------------------
LocalJacobian(int n,double x,double y,double z,double t,double t0)1096 inline double MultiLevelTransformation::LocalJacobian(int n, double x, double y, double z, double t, double t0) const
1097 {
1098   return this->Jacobian(0, n, x, y, z, t, t0);
1099 }
1100 
1101 // -----------------------------------------------------------------------------
Hessian(int,int,Matrix[3],double,double,double,double,double)1102 inline void MultiLevelTransformation::Hessian(int, int, Matrix [3], double, double, double, double, double) const
1103 {
1104   cerr << this->NameOfClass() << "::Hessian(int, int,...): Not implemented" << endl;
1105   exit(1);
1106 }
1107 
1108 // -----------------------------------------------------------------------------
Hessian(int n,Matrix hessian[3],double x,double y,double z,double t,double t0)1109 inline void MultiLevelTransformation::Hessian(int n, Matrix hessian[3], double x, double y, double z, double t, double t0) const
1110 {
1111   this->Hessian(-1, n, hessian, x, y, z, t, t0);
1112 }
1113 
1114 // -----------------------------------------------------------------------------
Hessian(Matrix hessian[3],double x,double y,double z,double t,double t0)1115 inline void MultiLevelTransformation::Hessian(Matrix hessian[3], double x, double y, double z, double t, double t0) const
1116 {
1117   this->Hessian(-1, -1, hessian, x, y, z, t, t0);
1118 }
1119 
1120 // -----------------------------------------------------------------------------
GlobalHessian(Matrix hessian[3],double x,double y,double z,double t,double t0)1121 inline void MultiLevelTransformation::GlobalHessian(Matrix hessian[3], double x, double y, double z, double t, double t0) const
1122 {
1123   this->GetGlobalTransformation()->Hessian(hessian, x, y, z, t, t0);
1124 }
1125 
1126 // -----------------------------------------------------------------------------
LocalHessian(int n,Matrix hessian[3],double x,double y,double z,double t,double t0)1127 inline void MultiLevelTransformation::LocalHessian(int n, Matrix hessian[3], double x, double y, double z, double t, double t0) const
1128 {
1129   this->Hessian(0, n, hessian, x, y, z, t, t0);
1130 }
1131 
1132 // -----------------------------------------------------------------------------
LocalHessian(Matrix hessian[3],double x,double y,double z,double t,double t0)1133 inline void MultiLevelTransformation::LocalHessian(Matrix hessian[3], double x, double y, double z, double t, double t0) const
1134 {
1135   this->Hessian(0, -1, hessian, x, y, z, t, t0);
1136 }
1137 
1138 // -----------------------------------------------------------------------------
DeriveJacobianWrtDOF(Matrix & jac,int dof,double x,double y,double z,double t,double t0)1139 inline void MultiLevelTransformation::DeriveJacobianWrtDOF(Matrix &jac, int dof, double x, double y, double z, double t, double t0) const
1140 {
1141   cerr << this->NameOfClass() << "::DeriveJacobianWrtDOF: Not implemented" << endl;
1142   exit(1);
1143 }
1144 
1145 // =============================================================================
1146 // Properties
1147 // =============================================================================
1148 
1149 // -----------------------------------------------------------------------------
BendingEnergy(int m,int n,double x,double y,double z,double t,double t0,bool wrt_world)1150 inline double MultiLevelTransformation::BendingEnergy(int m, int n, double x, double y, double z, double t, double t0, bool wrt_world) const
1151 {
1152   double bending = .0;
1153   const int l1 = (m < 0 ? 0 : m);
1154   const int l2 = (n < 0 || n > this->NumberOfLevels() ? this->NumberOfLevels() : n);
1155   for (int l = l1; l < l2; ++l) {
1156     bending += this->GetLocalTransformation(l)->BendingEnergy(x, y, z, t, t0, wrt_world);
1157   }
1158   return bending;
1159 }
1160 
1161 // -----------------------------------------------------------------------------
BendingEnergy(int n,double x,double y,double z,double t,double t0,bool wrt_world)1162 inline double MultiLevelTransformation::BendingEnergy(int n, double x, double y, double z, double t, double t0, bool wrt_world) const
1163 {
1164   return this->BendingEnergy(0, n, x, y, z, t, t0, wrt_world);
1165 }
1166 
1167 // -----------------------------------------------------------------------------
BendingEnergy(double x,double y,double z,double t,double t0,bool wrt_world)1168 inline double MultiLevelTransformation::BendingEnergy(double x, double y, double z, double t, double t0, bool wrt_world) const
1169 {
1170   return this->BendingEnergy(0, -1, x, y, z, t, t0, wrt_world);
1171 }
1172 
1173 
1174 } // namespace mirtk
1175 
1176 #endif // MIRTK_MultiLevelTransformation_H
1177