Easy3D 2.5.3
plane.h
1/********************************************************************
2 * Copyright (C) 2015 Liangliang Nan <liangliang.nan@gmail.com>
3 * https://3d.bk.tudelft.nl/liangliang/
4 *
5 * This file is part of Easy3D. If it is useful in your research/work,
6 * I would be grateful if you show your appreciation by citing it:
7 * ------------------------------------------------------------------
8 * Liangliang Nan.
9 * Easy3D: a lightweight, easy-to-use, and efficient C++ library
10 * for processing and rendering 3D data.
11 * Journal of Open Source Software, 6(64), 3255, 2021.
12 * ------------------------------------------------------------------
13 *
14 * Easy3D is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License Version 3
16 * as published by the Free Software Foundation.
17 *
18 * Easy3D is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 ********************************************************************/
26
27#ifndef EASY3D_CORE_PLANE_H
28#define EASY3D_CORE_PLANE_H
29
30#include <easy3d/core/vec.h>
31#include <easy3d/core/line.h>
32#include <easy3d/util/logging.h>
33
34
35namespace easy3d {
36
37
40 template<typename FT>
42 public:
43 typedef Vec<2, FT> Point2;
44 typedef Vec<3, FT> Point3;
45 typedef Vec<3, FT> Vector3;
48
49 public:
51 GenericPlane(const Point3 &p1, const Point3 &p2, const Point3 &p3);
52
54 GenericPlane(const Point3 &p, const Vector3 &n);
55
57 GenericPlane(FT a, FT b, FT c, FT d) {
58 coeff_[0] = a;
59 coeff_[1] = b;
60 coeff_[2] = c;
61 coeff_[3] = d;
62 }
63
64 GenericPlane() = default;
65
67 inline FT a() const { return coeff_[0]; }
68
70 inline FT b() const { return coeff_[1]; }
71
73 inline FT c() const { return coeff_[2]; }
74
76 inline FT d() const { return coeff_[3]; }
77
79 inline FT &operator[](size_t idx) {
80 assert(idx < 4);
81 return coeff_[idx];
82 }
83
85 inline const FT &operator[](size_t idx) const {
86 assert(idx < 4);
87 return coeff_[idx];
88 }
89
91 Vector3 normal() const;
92
95 Point3 point() const;
96
98 Vector3 base1() const;
99
101 Vector3 base2() const;
102
108 Point2 to_2d(const Point3 &p) const;
109
115 Point3 to_3d(const Point2 &p) const;
116
118 Point3 projection(const Point3 &p) const;
119
121 inline FT value(const Point3 &p) const {
122 return (coeff_[0] * p.x + coeff_[1] * p.y + coeff_[2] * p.z + coeff_[3]);
123 }
124
126 FT squared_distance(const Point3 &p) const;
127
132 bool intersect(const Line3 &line, Point3 &p) const;
133
138 bool intersect(const Line3 &line) const;
139
144 bool intersect(const Point3 &s, const Point3 &t, Point3 &p) const;
145
149 bool intersect(const Point3 &s, const Point3 &t) const;
150
154 bool intersect(const thisclass &another, Line3 &line) const;
155
158 bool intersect(const thisclass &another) const;
159
165 int orient(const Point3 &p) const;
166
168 const FT *data() const { return coeff_; }
169
171 FT *data() { return coeff_; }
172
175 operator const FT *() const { return coeff_; }
176
179 operator FT *() { return coeff_; }
180
181 private:
182 FT coeff_[4]; // representing the a, b, c, and d, respectively
183 };
184
185
186 template<typename FT>
187 std::ostream &operator<<(std::ostream &os, const GenericPlane<FT> &plane);
188
189 template<typename FT>
190 std::istream &operator>>(std::istream &is, GenericPlane<FT> &plane);
191
192
193 template<typename FT>
194 inline
195 GenericPlane<FT>::GenericPlane(const Point3 &p1, const Point3 &p2, const Point3 &p3) {
196 Vector3 n = cross(p2 - p1, p3 - p1);
197 n = normalize(n);
198
199 coeff_[0] = n.x;
200 coeff_[1] = n.y;
201 coeff_[2] = n.z;
202 coeff_[3] = -(coeff_[0] * p1.x + coeff_[1] * p1.y + coeff_[2] * p1.z);
203
204 DLOG_IF(length(n) < 1e-15, ERROR) << "degenerate plane constructed from 3 points:"
205 << "\t(" << p1 << ")"
206 << "\t(" << p2 << ")"
207 << "\t(" << p3 << ")";
208 }
209
210 template<typename FT>
211 inline
213 Vector3 nn = normalize(n);
214 coeff_[0] = nn.x;
215 coeff_[1] = nn.y;
216 coeff_[2] = nn.z;
217 coeff_[3] = -(coeff_[0] * p.x + coeff_[1] * p.y + coeff_[2] * p.z);
218
219 DLOG_IF(length(nn) < 1e-15, ERROR) << "degenerate plane constructed from point ("
220 << p << ") and normal (" << n << ")";
221 }
222
223
224 template<typename FT>
225 inline
227 Vector3 n = normalize(Vector3(coeff_[0], coeff_[1], coeff_[2]));
228 DLOG_IF(length(n) < 1e-15, ERROR) << "degenerate plane with normal: (" << n << ")";
229 return n;
230 }
231
232
233 template<typename FT>
234 inline
236 if (coeff_[0] == 0) // parallel to x-axis
237 return Vector3(FT(1), FT(0), FT(0));
238 else if (coeff_[1] == 0) // parallel to y-axis
239 return Vector3(FT(0), FT(1), FT(0));
240 else if (coeff_[2] == 0) // parallel to z-axis
241 return Vector3(FT(0), FT(0), FT(1));
242 else {
243 Vector3 base(-coeff_[1], coeff_[0], FT(0));
244 return normalize(base);
245 }
246 }
247
248
249 template<typename FT>
250 inline
252 Vector3 base = cross(normal(), base1());
253 return normalize(base);
254 }
255
256 template<typename FT>
257 inline
259 Vector3 vec = p - point();
260 FT x = dot(vec, base1());
261 FT y = dot(vec, base2());
262 return Point2(x, y);
263 }
264
265
266 template<typename FT>
267 inline
269 return point() + base1() * p.x + base2() * p.y;
270 }
271
272
273 template<typename FT>
274 inline
276 Point3 p(FT(0), FT(0), FT(0));
277 if (std::abs(coeff_[0]) >= std::abs(coeff_[1]) && std::abs(coeff_[0]) >= std::abs(coeff_[2]))
278 p.x = -coeff_[3] / coeff_[0];
279 else if (std::abs(coeff_[1]) >= std::abs(coeff_[0]) && std::abs(coeff_[1]) >= std::abs(coeff_[2]))
280 p.y = -coeff_[3] / coeff_[1];
281 else
282 p.z = -coeff_[3] / coeff_[2];
283 return p;
284
285 // the code below is not numerically stable
286 //Point3 p(FT(0), FT(0), FT(0));
287 //if (coeff_[0] != 0)
288 // p.x = -coeff_[3] / coeff_[0];
289 //else if (coeff_[1] != 0)
290 // p.y = -coeff_[3] / coeff_[1];
291 //else
292 // p.z = -coeff_[3] / coeff_[2];
293 //return p;
294 }
295
296
297 // return values:
298 // 1: p is on the positive side
299 // -1: p is on the negative side
300 // 0: the point p is on the plane.
301 template<typename FT>
302 inline
303 int GenericPlane<FT>::orient(const Point3 &p) const {
304 FT v = value(p);
305 if (std::abs(v) < 1e-15)
306 return 0;
307
308 return (v > 0.0 ? 1 : -1);
309 }
310
311
312 template<typename FT>
313 inline
315 // the equation of the plane is Ax+By+Cz+D=0
316 // the normal direction is (A,B,C)
317 // the projected point is p-lambda(A,B,C) where
318 // A(x-lambda*A) + B(y-lambda*B) + C(z-lambda*C) + D = 0
319
320 FT num = coeff_[0] * p.x + coeff_[1] * p.y + coeff_[2] * p.z + coeff_[3];
321 FT den = coeff_[0] * coeff_[0] + coeff_[1] * coeff_[1] + coeff_[2] * coeff_[2];
322 FT lambda = num / den;
323
324 FT x = p.x - lambda * coeff_[0];
325 FT y = p.y - lambda * coeff_[1];
326 FT z = p.z - lambda * coeff_[2];
327 return Point3(x, y, z);
328 }
329
330
331 template<typename FT>
332 inline
334 FT v = value(p);
335 return (v * v) / (coeff_[0] * coeff_[0] + coeff_[1] * coeff_[1] + coeff_[2] * coeff_[2]);
336 }
337
338
339 template<typename FT>
340 inline
341 bool GenericPlane<FT>::intersect(const Line3 &line) const {
342 Vector3 dir = line.direction();
343 FT c = dot(dir, normal());
344 if (std::abs(c) < 1e-15)
345 return false;
346 else
347 return true;
348 }
349
350
351 template<typename FT>
352 inline
353 bool GenericPlane<FT>::intersect(const Line3 &line, Point3 &p) const {
354 const Vector3 &dir = line.direction();
355 FT c = dot(dir, normal());
356 if (std::abs(c) < 1e-15)
357 return false;
358
359 const Point3 &p0 = line.point();
360 // p = p0 + dir * t
361 // equation: p is in the plane (so we first compute t)
362 FT t = -(coeff_[0] * p0.x + coeff_[1] * p0.y + coeff_[2] * p0.z + coeff_[3]) /
363 (coeff_[0] * dir.x + coeff_[1] * dir.y + coeff_[2] * dir.z);
364 p = p0 + dir * t;
365 return true;
366 }
367
368
369 template<typename FT>
370 inline
371 bool GenericPlane<FT>::intersect(const Point3 &s, const Point3 &t) const {
372 int ss = orient(s);
373 int st = orient(t);
374 if ((ss == 1 && st == -1) || (ss == -1 && st == 1))
375 return true;
376 else if (ss == 0 || st == 0)
377 return true;
378 else
379 return false;
380 }
381
382
383 template<typename FT>
384 inline
385 bool GenericPlane<FT>::intersect(const Point3 &s, const Point3 &t, Point3 &p) const {
386 int ss = orient(s);
387 int st = orient(t);
388 if ((ss == 1 && st == -1) || (ss == -1 && st == 1)) {
389 if (intersect(Line3::from_two_points(s, t), p))
390 return true;
391 else {
392 LOG(ERROR) << "fatal error. Should have intersection";
393 return false;
394 }
395 } else {
396 if (ss == 0) {
397 p = s;
398 return true;
399 } else if (st == 0) {
400 p = t;
401 return true;
402 } else {
403 // no intersection with the plane
404 return false;
405 }
406 }
407 }
408
409
410 template<typename FT>
411 inline
412 bool GenericPlane<FT>::intersect(const thisclass &another) const {
413 const FT &a = coeff_[0];
414 const FT &b = coeff_[1];
415 const FT &c = coeff_[2];
416 const FT &d = coeff_[3];
417 const FT &p = another.coeff_[0];
418 const FT &q = another.coeff_[1];
419 const FT &r = another.coeff_[2];
420 const FT &s = another.coeff_[3];
421
422 FT det = a * q - p * b;
423 if (det != 0)
424 return true;
425 det = a * r - p * c;
426 if (det != 0)
427 return true;
428 det = b * r - c * q;
429 if (det != 0)
430 return true;
431
432 // degenerate case
433 if (a != 0 || p != 0)
434 return (a * s == p * d);
435 if (b != 0 || q != 0)
436 return (b * s == q * d);
437 if (c != 0 || r != 0)
438 return (c * s == r * d);
439
440 return true;
441 }
442
443
444 template<typename FT>
445 inline
446 bool GenericPlane<FT>::intersect(const thisclass &another, Line3 &line) const {
447 const FT &a = coeff_[0];
448 const FT &b = coeff_[1];
449 const FT &c = coeff_[2];
450 const FT &d = coeff_[3];
451 const FT &p = another.coeff_[0];
452 const FT &q = another.coeff_[1];
453 const FT &r = another.coeff_[2];
454 const FT &s = another.coeff_[3];
455
456 FT det = a * q - p * b;
457 if (det != 0) {
458 const Point3 pt((b * s - d * q) / det, (p * d - a * s) / det, 0);
459 const Vector3 dir((b * r - c * q), (p * c - a * r), det);
460 line = Line3::from_point_and_direction(pt, dir);
461 return true;
462 }
463 det = a * r - p * c;
464 if (det != 0) {
465 const Point3 pt((c * s - d * r) / det, 0, (p * d - a * s) / det);
466 const Vector3 dir((c * q - b * r), det, (p * b - a * q));
467 line = Line3::from_point_and_direction(pt, dir);
468 return true;
469 }
470 det = b * r - c * q;
471 if (det != 0) {
472 const Point3 pt(0, (c * s - d * r) / det, (d * q - b * s) / det);
473 const Vector3 dir(det, (c * p - a * r), (a * q - b * p));
474 line = Line3::from_point_and_direction(pt, dir);
475 return true;
476 }
477
478 // degenerate case
479 return false; // coplanar
480 }
481
482
484 template<typename FT>
485 inline
486 std::ostream &operator<<(std::ostream &os, const GenericPlane<FT> &plane) {
487 return os << plane[0] << ' ' << plane[1] << ' ' << plane[2] << ' ' << plane[3];
488 }
489
491 template<typename FT>
492 inline
493 std::istream &operator>>(std::istream &is, GenericPlane<FT> &plane) {
494 return is >> plane[0] >> plane[1] >> plane[2] >> plane[3];
495 }
496
497
498 namespace geom {
507 template<typename FT>
508 inline
509 bool intersect(const GenericPlane<FT> &plane1, const GenericPlane<FT> &plane2, const GenericPlane<FT> &plane3,
510 typename GenericPlane<FT>::Point3 &point) {
511 typename GenericPlane<FT>::Line3 line;
512 if (plane1.intersect(plane2, line))
513 return plane3.intersect(line, point);
514 return false;
515 }
516 }
517
518}
519
520
521#endif // EASY3D_CORE_PLANE_H
A generic line representation, which supports both 2D and 3D lines.
Definition: line.h:40
static GenericLine from_two_points(const Point &p, const Point &q)
Constructs a line from two points p and q.
Definition: line.h:50
const Vector & direction() const
Returns the direction of a line.
Definition: line.h:62
const Point & point() const
Returns an arbitrary point on a line.
Definition: line.h:65
static GenericLine from_point_and_direction(const Point &p, const Vector &dir)
Constructs a line from a point p and its direction dir.
Definition: line.h:48
A 3D Plane of equation a*x + b*y + c*z + d = 0.
Definition: plane.h:41
bool intersect(const Line3 &line, Point3 &p) const
Tests if a line intersects with this plane. Returns true if they do intersect. In this case,...
Definition: plane.h:353
GenericPlane(const Point3 &p1, const Point3 &p2, const Point3 &p3)
Constructs a plane from three points p1, p2, and p3.
Definition: plane.h:195
FT * data()
Returns the memory address of the coefficients.
Definition: plane.h:171
FT squared_distance(const Point3 &p) const
Computes the squared distance of a point p to this plane.
Definition: plane.h:333
FT value(const Point3 &p) const
Evaluates the plane (i.e., computes the value of a * x + b * y + c * z + d) for the given point p.
Definition: plane.h:121
FT c() const
Returns plane equation parameter c.
Definition: plane.h:73
Vector3 base2() const
Returns the second ortho-base defined on this plane.
Definition: plane.h:251
bool intersect(const thisclass &another, Line3 &line) const
Tests if this plane intersects with another plane. Returns true if they do intersect....
Definition: plane.h:446
Point2 to_2d(const Point3 &p) const
Converts a 3D point into a 2D point relative to the local coordinate system defined by the three orth...
Definition: plane.h:258
FT b() const
Returns plane equation parameter b.
Definition: plane.h:70
bool intersect(const thisclass &another) const
Tests if this plane intersects with another plane. Returns true if they do intersect and false if the...
Definition: plane.h:412
int orient(const Point3 &p) const
Determines the relative orientation of a point with respect to this plane. The return value is one of...
Definition: plane.h:303
bool intersect(const Point3 &s, const Point3 &t) const
Tests if a line segment (given by its two end points s and t) intersects with this plane....
Definition: plane.h:371
bool intersect(const Line3 &line) const
Tests if a line intersects with this plane. Returns true if they do intersect. Otherwise,...
Definition: plane.h:341
FT a() const
Returns plane equation parameter a.
Definition: plane.h:67
const FT * data() const
Returns the constant memory address of the coefficients.
Definition: plane.h:168
const FT & operator[](size_t idx) const
Returns the idx_th const parameter of the plane equation.
Definition: plane.h:85
Vector3 base1() const
Returns the first ortho-base defined on this plane.
Definition: plane.h:235
FT & operator[](size_t idx)
Returns the idx_th parameter of the plane equation.
Definition: plane.h:79
bool intersect(const Point3 &s, const Point3 &t, Point3 &p) const
Tests if a line segment (given by its two end points s and t) intersects with this plane....
Definition: plane.h:385
Point3 projection(const Point3 &p) const
The projection of a point p on this plane.
Definition: plane.h:314
GenericPlane(FT a, FT b, FT c, FT d)
Constructs a plane from its equation parameters a, b, c, and d.
Definition: plane.h:57
Vector3 normal() const
Returns the normal of the plane.
Definition: plane.h:226
GenericPlane(const Point3 &p, const Vector3 &n)
Constructs a plane from a point p and the plane normal n.
Definition: plane.h:212
Point3 to_3d(const Point2 &p) const
Converts a 2D point in the local coordinate system defined by the three orthogonal vectors base1(),...
Definition: plane.h:268
Point3 point() const
Returns a point lying on this plane.
Definition: plane.h:275
FT d() const
Returns plane equation parameter d.
Definition: plane.h:76
Base class for vector types. It provides generic functionality for N dimensional vectors.
Definition: vec.h:34
bool intersect(const GenericPlane< FT > &plane1, const GenericPlane< FT > &plane2, const GenericPlane< FT > &plane3, typename GenericPlane< FT >::Point3 &point)
Definition: plane.h:509
Definition: collider.cpp:182
std::istream & operator>>(std::istream &is, GenericLine< DIM, FT > &line)
Definition: line.h:133
T length(const Vec< N, T > &v)
Computes the length/magnitude of a vector.
Definition: vec.h:289
std::ostream & operator<<(std::ostream &os, Graph::Vertex v)
Definition: graph.h:920
T det(const Vec< 2, T > &v1, const Vec< 2, T > &v2)
Compute the determinant of the 2x2 matrix formed by the two 2D vectors as the two rows.
Definition: vec.h:405
Vec< 3, T > cross(const Vec< 3, T > &v1, const Vec< 3, T > &v2)
Compute the cross product of two 3D vectors.
Definition: vec.h:534
FT dot(const std::vector< FT > &, const std::vector< FT > &)
Inner product for vectors.
Definition: matrix.h:1803
Vec< N, T > normalize(const Vec< N, T > &v)
Computes and returns the normalized vector (Note: the input vector is not modified).
Definition: vec.h:299