1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2016 Imperial College London
5  * Copyright 2016 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 #ifndef MIRTK_Plane_H
21 #define MIRTK_Plane_H
22 
23 #include "mirtk/Object.h"
24 
25 #include "mirtk/Vector3.h"
26 #include "mirtk/Point.h"
27 #include "mirtk/PointSet.h"
28 
29 
30 namespace mirtk {
31 
32 
33 /**
34  * Plane in 3D space.
35  *
36  * The plane is stored in Hessian normal form. Additionally, the two orthonormal
37  * tangent vectors to the plane normal are stored which are used for projecting
38  * points onto the plane and expressing these as 2D (u, v) coordinates along these
39  * in-plane axes. The vectors Plane::Tangent1, Plane::Tangent2, and Plane::Normal
40  * form a right-handed coordinate system.
41  */
42 class Plane : public Object
43 {
44   mirtkObjectMacro(Plane);
45 
46   // ---------------------------------------------------------------------------
47   // Attributes
48 
49   /// Distance of plane from origin
50   mirtkPublicAttributeMacro(double, Offset);
51 
52   /// First in-plane axis
53   mirtkReadOnlyAttributeMacro(Vector3, Tangent1);
54 
55   /// Second in-plane axis
56   mirtkReadOnlyAttributeMacro(Vector3, Tangent2);
57 
58   /// Plane normal vector
59   mirtkReadOnlyAttributeMacro(Vector3, Normal);
60 
61   /// Origin of plane coordinate system
62   ///
63   /// When a plane is fit to a set of points, the origin is the centroid of the
64   /// point cloud. Otherwise, the origin is the point on the plane that is
65   /// closest to the world origin, i.e., the vector pointing from plane origin
66   /// to the world origin is orthogonal to the plane normal.
67   mirtkReadOnlyAttributeMacro(Point, Origin);
68 
69   /// Copy attributes of this class from another instance
70   void CopyAttributes(const Plane &);
71 
72 protected:
73 
74   /// Update origin after change of plane normal
75   void UpdateOrigin();
76 
77   /// Update tangent vectors after change of plane normal
78   void UpdateTangents();
79 
80   // ---------------------------------------------------------------------------
81   // Construction/Destruction
82 public:
83 
84   /// Default constructor
85   Plane();
86 
87   /// Construct plane given its Hessian normal form parameters
88   ///
89   /// \param[in] n Normal vector.
90   /// \param[in] b Distance of plane to origin.
91   Plane(const Vector3 &n, double b);
92 
93   /// Construct plane given its Hessian normal form parameters
94   ///
95   /// \param[in] n Normal vector.
96   /// \param[in] b Distance of plane to origin.
97   Plane(double n[3], double b);
98 
99   /// Construct plane given its Hessian normal form parameters
100   ///
101   /// \param[in] nx First  component of normal vector.
102   /// \param[in] ny Second component of normal vector.
103   /// \param[in] nz Third  component of normal vector.
104   /// \param[in] b  Distance of plane to origin.
105   Plane(double nx, double ny, double nz, double b);
106 
107   /// Copy constructor
108   Plane(const Plane &);
109 
110   /// Assignment operator
111   Plane &operator =(const Plane &);
112 
113   /// Destructor
114   virtual ~Plane();
115 
116   /// Set normal vector
117   void Normal(const Vector3 &n);
118 
119   /// Set normal vector
120   ///
121   /// \param[in] n Normal vector.
122   void Normal(double n[3]);
123 
124   /// Set normal vector
125   ///
126   /// \param[in] nx First  component of normal vector.
127   /// \param[in] ny Second component of normal vector.
128   /// \param[in] nz Third  component of normal vector.
129   void Normal(double nx, double ny, double nz);
130 
131   // ---------------------------------------------------------------------------
132   // Model fitting
133 public:
134 
135   /// Fit plane to a set of points
136   ///
137   /// \param[in] points Point cloud.
138   ///
139   /// \returns RMS error of the regression.
140   double Fit(const PointSet &points);
141 
142   // ---------------------------------------------------------------------------
143   // Evaluation
144 
145   /// Evaluates plane equation for a given point
146   ///
147   /// \param[in] p Point.
148   ///
149   /// \returns Signed distance of point to plane.
150   double Evaluate(const Point &p) const;
151 
152   /// Evaluates plane equation for a given point
153   ///
154   /// \param[in] p Point.
155   ///
156   /// \returns Signed distance of point to plane.
157   double Evaluate(const double p[3]) const;
158 
159   /// Evaluates plane equation for a given point
160   ///
161   /// \param[in] x First  coordinate of point.
162   /// \param[in] y Second coordinate of point.
163   /// \param[in] z Third  coordinate of point.
164   ///
165   /// \returns Signed distance of point to plane.
166   double Evaluate(double x, double y, double z) const;
167 
168   /// Evaluates plane equation for a given point
169   ///
170   /// \param[in] p Point.
171   ///
172   /// \returns Signed distance of point to plane.
173   double Distance(const Point &p) const;
174 
175   /// Evaluates plane equation for a given point
176   ///
177   /// \param[in] p Point.
178   ///
179   /// \returns Signed distance of point to plane.
180   double Distance(const double p[3]) const;
181 
182   /// Evaluates plane equation for a given point
183   ///
184   /// \param[in] x First  coordinate of point.
185   /// \param[in] y Second coordinate of point.
186   /// \param[in] z Third  coordinate of point.
187   ///
188   /// \returns Signed distance of point to plane.
189   double Distance(double x, double y, double z) const;
190 
191   // ---------------------------------------------------------------------------
192   // Projection
193 
194   /// Project point onto plane
195   ///
196   /// \param[in]  p Point.
197   /// \param[out] u Coordinate of projected point along Tangent1.
198   /// \param[out] v Coordinate of projected point along Tangent2.
199   void Project(const Point &p, double &u, double &v) const;
200 
201   /// Project point onto plane
202   ///
203   /// \param[in]  p Point.
204   /// \param[out] u Coordinate of projected point along Tangent1.
205   /// \param[out] v Coordinate of projected point along Tangent2.
206   void Project(const double p[3], double &u, double &v) const;
207 
208   /// Project point onto plane
209   ///
210   /// \param[in]  x First  coordinate of point.
211   /// \param[in]  y Second coordinate of point.
212   /// \param[in]  z Third  coordinate of point.
213   /// \param[out] u Coordinate of projected point along Tangent1.
214   /// \param[out] v Coordinate of projected point along Tangent2.
215   void Project(double x, double y, double z, double &u, double &v) const;
216 
217   // ---------------------------------------------------------------------------
218   // Debugging
219 
220   /// Print plane equation
221   ostream &Print(ostream &os, Indent = 0) const;
222 
223   /// Print plane equation to standard output stream
224   void Print(Indent = 0) const;
225 
226 };
227 
228 ////////////////////////////////////////////////////////////////////////////////
229 // Inline definitions
230 ////////////////////////////////////////////////////////////////////////////////
231 
232 // =============================================================================
233 // Construction/Destruction
234 // =============================================================================
235 
236 // -----------------------------------------------------------------------------
Plane()237 inline Plane::Plane()
238 :
239   _Offset(.0),
240   _Tangent1(1.0, .0, .0),
241   _Tangent2(.0, 1.0, .0),
242   _Normal  (.0, .0, 1.0),
243   _Origin  (.0, .0, .0)
244 {
245 }
246 
247 // -----------------------------------------------------------------------------
Plane(const Vector3 & n,double b)248 inline Plane::Plane(const Vector3 &n, double b)
249 :
250   _Offset(b),
251   _Normal(n)
252 {
253   UpdateOrigin();
254   UpdateTangents();
255 }
256 
257 // -----------------------------------------------------------------------------
Plane(double n[3],double b)258 inline Plane::Plane(double n[3], double b)
259 :
260   _Offset(b),
261   _Normal(n[0], n[1], n[2])
262 {
263   UpdateOrigin();
264   UpdateTangents();
265 }
266 
267 // -----------------------------------------------------------------------------
Plane(double nx,double ny,double nz,double b)268 inline Plane::Plane(double nx, double ny, double nz, double b)
269 :
270   _Offset(b),
271   _Normal(nx, ny, nz)
272 {
273   UpdateOrigin();
274   UpdateTangents();
275 }
276 
277 // -----------------------------------------------------------------------------
CopyAttributes(const Plane & other)278 inline void Plane::CopyAttributes(const Plane &other)
279 {
280   _Offset   = other._Offset;
281   _Normal   = other._Normal;
282   _Tangent1 = other._Tangent1;
283   _Tangent2 = other._Tangent2;
284   _Origin   = other._Origin;
285 }
286 
287 // -----------------------------------------------------------------------------
Plane(const Plane & other)288 inline Plane::Plane(const Plane &other)
289 {
290   CopyAttributes(other);
291 }
292 
293 // -----------------------------------------------------------------------------
294 inline Plane &Plane::operator =(const Plane &other)
295 {
296   if (this != &other) {
297     Object::operator =(other);
298     CopyAttributes(other);
299   }
300   return *this;
301 }
302 
303 // -----------------------------------------------------------------------------
~Plane()304 inline Plane::~Plane()
305 {
306 }
307 
308 // -----------------------------------------------------------------------------
Normal(const Vector3 & n)309 inline void Plane::Normal(const Vector3 &n)
310 {
311   _Normal = n;
312   UpdateOrigin();
313   UpdateTangents();
314 }
315 
316 // -----------------------------------------------------------------------------
Normal(double n[3])317 inline void Plane::Normal(double n[3])
318 {
319   _Normal[0] = n[0];
320   _Normal[1] = n[1];
321   _Normal[2] = n[2];
322   UpdateOrigin();
323   UpdateTangents();
324 }
325 
326 // -----------------------------------------------------------------------------
Normal(double nx,double ny,double nz)327 inline void Plane::Normal(double nx, double ny, double nz)
328 {
329   _Normal[0] = nx;
330   _Normal[1] = ny;
331   _Normal[2] = nz;
332   UpdateOrigin();
333   UpdateTangents();
334 }
335 
336 // =============================================================================
337 // Evaluation
338 // =============================================================================
339 
340 // -----------------------------------------------------------------------------
Evaluate(const Point & p)341 inline double Plane::Evaluate(const Point &p) const
342 {
343   return p._x * _Normal[0] + p._y * _Normal[1] + p._z * _Normal[2] - _Offset;
344 }
345 
346 // -----------------------------------------------------------------------------
Evaluate(const double p[3])347 inline double Plane::Evaluate(const double p[3]) const
348 {
349   return p[0] * _Normal[0] + p[1] * _Normal[1] + p[2] * _Normal[2] - _Offset;
350 }
351 
352 // -----------------------------------------------------------------------------
Evaluate(double x,double y,double z)353 inline double Plane::Evaluate(double x, double y, double z) const
354 {
355   return x * _Normal[0] + y * _Normal[1] + z * _Normal[2] - _Offset;
356 }
357 
358 // -----------------------------------------------------------------------------
Distance(const Point & p)359 inline double Plane::Distance(const Point &p) const
360 {
361   return Evaluate(p);
362 }
363 
364 // -----------------------------------------------------------------------------
Distance(const double p[3])365 inline double Plane::Distance(const double p[3]) const
366 {
367   return Evaluate(p);
368 }
369 
370 // -----------------------------------------------------------------------------
Distance(double x,double y,double z)371 inline double Plane::Distance(double x, double y, double z) const
372 {
373   return Evaluate(x, y, z);
374 }
375 
376 // =============================================================================
377 // Projection
378 // =============================================================================
379 
380 // -----------------------------------------------------------------------------
Project(const Point & p,double & u,double & v)381 inline void Plane::Project(const Point &p, double &u, double &v) const
382 {
383   Vector3 d(p._x - _Origin._x, p._y - _Origin._y, p._z - _Origin._z);
384   u = _Tangent1.Dot(d);
385   v = _Tangent2.Dot(d);
386 }
387 
388 // -----------------------------------------------------------------------------
Project(const double p[3],double & u,double & v)389 inline void Plane::Project(const double p[3], double &u, double &v) const
390 {
391   Vector3 d(p[0] - _Origin._x, p[1] - _Origin._y, p[2] - _Origin._z);
392   u = _Tangent1.Dot(d);
393   v = _Tangent2.Dot(d);
394 }
395 
396 // -----------------------------------------------------------------------------
Project(double x,double y,double z,double & u,double & v)397 inline void Plane::Project(double x, double y, double z, double &u, double &v) const
398 {
399   Vector3 d(x - _Origin._x, y - _Origin._y, z - _Origin._z);
400   u = _Tangent1.Dot(d);
401   v = _Tangent2.Dot(d);
402 }
403 
404 // =============================================================================
405 // Debugging
406 // =============================================================================
407 
408 // -----------------------------------------------------------------------------
Print(Indent indent)409 inline void Plane::Print(Indent indent) const
410 {
411   Print(cout, indent);
412 }
413 
414 
415 } // namespace mirtk
416 
417 #endif // MIRTK_Plane_H
418