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