Easy3D 2.6.1
Loading...
Searching...
No Matches
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
42 template<typename FT>
44 public:
50
51 public:
58 GenericPlane(const Point3 &p1, const Point3 &p2, const Point3 &p3);
59
65 GenericPlane(const Point3 &p, const Vector3 &n);
66
74 GenericPlane(FT a, FT b, FT c, FT d) {
75 coeff_[0] = a;
76 coeff_[1] = b;
77 coeff_[2] = c;
78 coeff_[3] = d;
79 }
80
84 GenericPlane() = default;
85
90 FT a() const { return coeff_[0]; }
91
96 FT b() const { return coeff_[1]; }
97
102 FT c() const { return coeff_[2]; }
103
108 FT d() const { return coeff_[3]; }
109
115 FT &operator[](size_t idx) {
116 assert(idx < 4);
117 return coeff_[idx];
118 }
119
125 const FT &operator[](size_t idx) const {
126 assert(idx < 4);
127 return coeff_[idx];
128 }
129
135
141 Point3 point() const;
142
147 Vector3 base1() const;
148
153 Vector3 base2() const;
154
164 Point2 to_2d(const Point3 &p) const;
165
175 Point3 to_3d(const Point2 &p) const;
176
182 Point3 projection(const Point3 &p) const;
183
189 FT value(const Point3 &p) const {
190 return (coeff_[0] * p.x + coeff_[1] * p.y + coeff_[2] * p.z + coeff_[3]);
191 }
192
198 FT squared_distance(const Point3 &p) const;
199
206 bool intersect(const Line3 &line, Point3 &p) const;
212 bool intersect(const Line3 &line) const;
213
222 bool intersect(const Point3 &s, const Point3 &t, Point3 &p) const;
230 bool intersect(const Point3 &s, const Point3 &t) const;
231
238 bool intersect(const thisclass &another, Line3 &line) const;
244 bool intersect(const thisclass &another) const;
245
251 int orient(const Point3 &p) const;
252
257 const FT *data() const { return coeff_; }
258
263 FT *data() { return coeff_; }
264
270 operator const FT *() const { return coeff_; }
271
277 operator FT *() { return coeff_; }
278
279 private:
280 FT coeff_[4]; // representing the a, b, c, and d, respectively
281 };
282
283
284 template<typename FT>
285 std::ostream &operator<<(std::ostream &os, const GenericPlane<FT> &plane);
286
287 template<typename FT>
288 std::istream &operator>>(std::istream &is, GenericPlane<FT> &plane);
289
290
291 template<typename FT>
292 GenericPlane<FT>::GenericPlane(const Point3 &p1, const Point3 &p2, const Point3 &p3) {
293 Vector3 n = cross(p2 - p1, p3 - p1);
294 n = normalize(n);
295
296 coeff_[0] = n.x;
297 coeff_[1] = n.y;
298 coeff_[2] = n.z;
299 coeff_[3] = -(coeff_[0] * p1.x + coeff_[1] * p1.y + coeff_[2] * p1.z);
300
301 DLOG_IF(length(n) < 1e-15, ERROR) << "degenerate plane constructed from 3 points:"
302 << "\t(" << p1 << ")"
303 << "\t(" << p2 << ")"
304 << "\t(" << p3 << ")";
305 }
306
307 template<typename FT>
309 Vector3 nn = normalize(n);
310 coeff_[0] = nn.x;
311 coeff_[1] = nn.y;
312 coeff_[2] = nn.z;
313 coeff_[3] = -(coeff_[0] * p.x + coeff_[1] * p.y + coeff_[2] * p.z);
314
315 DLOG_IF(length(nn) < 1e-15, ERROR) << "degenerate plane constructed from point ("
316 << p << ") and normal (" << n << ")";
317 }
318
319
320 template<typename FT>
322 Vector3 n = normalize(Vector3(coeff_[0], coeff_[1], coeff_[2]));
323 DLOG_IF(length(n) < 1e-15, ERROR) << "degenerate plane with normal: (" << n << ")";
324 return n;
325 }
326
327
328 template<typename FT>
330 if (coeff_[0] == 0) // parallel to x-axis
331 return Vector3(FT(1), FT(0), FT(0));
332 else if (coeff_[1] == 0) // parallel to y-axis
333 return Vector3(FT(0), FT(1), FT(0));
334 else if (coeff_[2] == 0) // parallel to z-axis
335 return Vector3(FT(0), FT(0), FT(1));
336 else {
337 Vector3 base(-coeff_[1], coeff_[0], FT(0));
338 return normalize(base);
339 }
340 }
341
342
343 template<typename FT>
345 Vector3 base = cross(normal(), base1());
346 return normalize(base);
347 }
348
349 template<typename FT>
351 Vector3 vec = p - point();
352 FT x = dot(vec, base1());
353 FT y = dot(vec, base2());
354 return Point2(x, y);
355 }
356
357
358 template<typename FT>
360 return point() + base1() * p.x + base2() * p.y;
361 }
362
363
364 template<typename FT>
366 Point3 p(FT(0), FT(0), FT(0));
367 if (std::abs(coeff_[0]) >= std::abs(coeff_[1]) && std::abs(coeff_[0]) >= std::abs(coeff_[2]))
368 p.x = -coeff_[3] / coeff_[0];
369 else if (std::abs(coeff_[1]) >= std::abs(coeff_[0]) && std::abs(coeff_[1]) >= std::abs(coeff_[2]))
370 p.y = -coeff_[3] / coeff_[1];
371 else
372 p.z = -coeff_[3] / coeff_[2];
373 return p;
374
375 // the code below is not numerically stable
376 //Point3 p(FT(0), FT(0), FT(0));
377 //if (coeff_[0] != 0)
378 // p.x = -coeff_[3] / coeff_[0];
379 //else if (coeff_[1] != 0)
380 // p.y = -coeff_[3] / coeff_[1];
381 //else
382 // p.z = -coeff_[3] / coeff_[2];
383 //return p;
384 }
385
386
387 // return values:
388 // 1: p is on the positive side
389 // -1: p is on the negative side
390 // 0: the point p is on the plane.
391 template<typename FT>
392 int GenericPlane<FT>::orient(const Point3 &p) const {
393 FT v = value(p);
394 if (std::abs(v) < 1e-15)
395 return 0;
396
397 return (v > 0.0 ? 1 : -1);
398 }
399
400
401 template<typename FT>
403 // the equation of the plane is Ax+By+Cz+D=0
404 // the normal direction is (A,B,C)
405 // the projected point is p-lambda(A,B,C) where
406 // A(x-lambda*A) + B(y-lambda*B) + C(z-lambda*C) + D = 0
407
408 FT num = coeff_[0] * p.x + coeff_[1] * p.y + coeff_[2] * p.z + coeff_[3];
409 FT den = coeff_[0] * coeff_[0] + coeff_[1] * coeff_[1] + coeff_[2] * coeff_[2];
410 FT lambda = num / den;
411
412 FT x = p.x - lambda * coeff_[0];
413 FT y = p.y - lambda * coeff_[1];
414 FT z = p.z - lambda * coeff_[2];
415 return Point3(x, y, z);
416 }
417
418
419 template<typename FT>
421 FT v = value(p);
422 return (v * v) / (coeff_[0] * coeff_[0] + coeff_[1] * coeff_[1] + coeff_[2] * coeff_[2]);
423 }
424
425
426 template<typename FT>
427 bool GenericPlane<FT>::intersect(const Line3 &line) const {
428 Vector3 dir = line.direction();
429 FT c = dot(dir, normal());
430 if (std::abs(c) < 1e-15)
431 return false;
432 else
433 return true;
434 }
435
436
437 template<typename FT>
438 bool GenericPlane<FT>::intersect(const Line3 &line, Point3 &p) const {
439 const Vector3 &dir = line.direction();
440 FT c = dot(dir, normal());
441 if (std::abs(c) < 1e-15)
442 return false;
443
444 const Point3 &p0 = line.point();
445 // p = p0 + dir * t
446 // equation: p is in the plane (so we first compute t)
447 FT t = -(coeff_[0] * p0.x + coeff_[1] * p0.y + coeff_[2] * p0.z + coeff_[3]) /
448 (coeff_[0] * dir.x + coeff_[1] * dir.y + coeff_[2] * dir.z);
449 p = p0 + dir * t;
450 return true;
451 }
452
453
454 template<typename FT>
455 bool GenericPlane<FT>::intersect(const Point3 &s, const Point3 &t) const {
456 int ss = orient(s);
457 int st = orient(t);
458 if ((ss == 1 && st == -1) || (ss == -1 && st == 1))
459 return true;
460 else if (ss == 0 || st == 0)
461 return true;
462 else
463 return false;
464 }
465
466
467 template<typename FT>
468 bool GenericPlane<FT>::intersect(const Point3 &s, const Point3 &t, Point3 &p) const {
469 int ss = orient(s);
470 int st = orient(t);
471 if ((ss == 1 && st == -1) || (ss == -1 && st == 1)) {
472 if (intersect(Line3::from_two_points(s, t), p))
473 return true;
474 else {
475 LOG(ERROR) << "fatal error. Should have intersection";
476 return false;
477 }
478 } else {
479 if (ss == 0) {
480 p = s;
481 return true;
482 } else if (st == 0) {
483 p = t;
484 return true;
485 } else {
486 // no intersection with the plane
487 return false;
488 }
489 }
490 }
491
492
493 template<typename FT>
494 bool GenericPlane<FT>::intersect(const thisclass &another) const {
495 const FT &a = coeff_[0];
496 const FT &b = coeff_[1];
497 const FT &c = coeff_[2];
498 const FT &d = coeff_[3];
499 const FT &p = another.coeff_[0];
500 const FT &q = another.coeff_[1];
501 const FT &r = another.coeff_[2];
502 const FT &s = another.coeff_[3];
503
504 FT det = a * q - p * b;
505 if (det != 0)
506 return true;
507 det = a * r - p * c;
508 if (det != 0)
509 return true;
510 det = b * r - c * q;
511 if (det != 0)
512 return true;
513
514 // degenerate case
515 if (a != 0 || p != 0)
516 return (a * s == p * d);
517 if (b != 0 || q != 0)
518 return (b * s == q * d);
519 if (c != 0 || r != 0)
520 return (c * s == r * d);
521
522 return true;
523 }
524
525
526 template<typename FT>
527 bool GenericPlane<FT>::intersect(const thisclass &another, Line3 &line) const {
528 const FT &a = coeff_[0];
529 const FT &b = coeff_[1];
530 const FT &c = coeff_[2];
531 const FT &d = coeff_[3];
532 const FT &p = another.coeff_[0];
533 const FT &q = another.coeff_[1];
534 const FT &r = another.coeff_[2];
535 const FT &s = another.coeff_[3];
536
537 FT det = a * q - p * b;
538 if (det != 0) {
539 const Point3 pt((b * s - d * q) / det, (p * d - a * s) / det, 0);
540 const Vector3 dir((b * r - c * q), (p * c - a * r), det);
541 line = Line3::from_point_and_direction(pt, dir);
542 return true;
543 }
544 det = a * r - p * c;
545 if (det != 0) {
546 const Point3 pt((c * s - d * r) / det, 0, (p * d - a * s) / det);
547 const Vector3 dir((c * q - b * r), det, (p * b - a * q));
548 line = Line3::from_point_and_direction(pt, dir);
549 return true;
550 }
551 det = b * r - c * q;
552 if (det != 0) {
553 const Point3 pt(0, (c * s - d * r) / det, (d * q - b * s) / det);
554 const Vector3 dir(det, (c * p - a * r), (a * q - b * p));
555 line = Line3::from_point_and_direction(pt, dir);
556 return true;
557 }
558
559 // degenerate case
560 return false; // coplanar
561 }
562
563
565 template<typename FT>
566 std::ostream &operator<<(std::ostream &os, const GenericPlane<FT> &plane) {
567 return os << plane[0] << ' ' << plane[1] << ' ' << plane[2] << ' ' << plane[3];
568 }
569
571 template<typename FT>
572 std::istream &operator>>(std::istream &is, GenericPlane<FT> &plane) {
573 return is >> plane[0] >> plane[1] >> plane[2] >> plane[3];
574 }
575
576
577 namespace geom {
586 template<typename FT>
587 bool intersect(const GenericPlane<FT> &plane1, const GenericPlane<FT> &plane2, const GenericPlane<FT> &plane3,
588 typename GenericPlane<FT>::Point3 &point) {
589 typename GenericPlane<FT>::Line3 line;
590 if (plane1.intersect(plane2, line))
591 return plane3.intersect(line, point);
592 return false;
593 }
594 }
595
596}
597
598
599#endif // EASY3D_CORE_PLANE_H
A generic line representation, which supports both 2D and 3D lines.
Definition line.h:45
static GenericLine from_two_points(const Point &p, const Point &q)
Definition line.h:65
const Vector & direction() const
Returns the direction of the line.
Definition line.h:86
const Point & point() const
Returns an arbitrary point on the line.
Definition line.h:92
static GenericLine from_point_and_direction(const Point &p, const Vector &dir)
Definition line.h:58
A 3D Plane of equation a*x + b*y + c*z + d = 0.
Definition plane.h:43
bool intersect(const Line3 &line, Point3 &p) const
Tests if a line intersects with this plane (both line and the plane are unlimited).
Definition plane.h:438
GenericPlane(const Point3 &p1, const Point3 &p2, const Point3 &p3)
Constructs a plane from three points p1, p2, and p3.
Definition plane.h:292
FT * data()
Returns the memory address of the coefficients.
Definition plane.h:263
FT squared_distance(const Point3 &p) const
Computes the squared distance of a point p to this plane.
Definition plane.h:420
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:189
float c() const
Definition plane.h:102
Vec< 3, FT > Vector3
The type of the 3D vector.
Definition plane.h:47
Vector3 base2() const
Returns the second ortho-base defined on this plane.
Definition plane.h:344
bool intersect(const thisclass &another, Line3 &line) const
Tests if this plane intersects with another plane.
Definition plane.h:527
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:350
float b() const
Definition plane.h:96
bool intersect(const thisclass &another) const
Tests if this plane intersects with another plane.
Definition plane.h:494
int orient(const Point3 &p) const
Determines the relative orientation of a point with respect to this plane.
Definition plane.h:392
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:455
bool intersect(const Line3 &line) const
Tests if a line intersects with this plane (both line and the plane are unlimited).
Definition plane.h:427
float a() const
Definition plane.h:90
const FT * data() const
Returns the constant memory address of the coefficients.
Definition plane.h:257
Vec< 3, FT > Point3
The type of the 3D point.
Definition plane.h:46
const FT & operator[](size_t idx) const
Returns the idx_th const parameter of the plane equation (const version).
Definition plane.h:125
Vector3 base1() const
Returns the first ortho-base defined on this plane.
Definition plane.h:329
GenericPlane< FT > thisclass
The type of this class.
Definition plane.h:49
GenericPlane()=default
Default constructor.
FT & operator[](size_t idx)
Returns the idx_th parameter of the plane equation.
Definition plane.h:115
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:468
Point3 projection(const Point3 &p) const
The projection of a point p on this plane.
Definition plane.h:402
GenericPlane(FT a, FT b, FT c, FT d)
Constructs a plane from its equation parameters a, b, c, and d.
Definition plane.h:74
Vector3 normal() const
Returns the normal of the plane.
Definition plane.h:321
GenericPlane(const Point3 &p, const Vector3 &n)
Constructs a plane from a point p and the plane normal n.
Definition plane.h:308
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:359
Point3 point() const
Returns a point lying on this plane.
Definition plane.h:365
GenericLine< 3, FT > Line3
The type of the 3D line.
Definition plane.h:48
Vec< 2, FT > Point2
The type of the 2D point.
Definition plane.h:45
float d() const
Definition plane.h:108
Base class for vector types. It provides generic functionality for N dimensional vectors.
Definition vec.h:30
bool intersect(const GenericPlane< FT > &plane1, const GenericPlane< FT > &plane2, const GenericPlane< FT > &plane3, typename GenericPlane< FT >::Point3 &point)
Definition plane.h:587
Definition collider.cpp:182
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
T length(const Vec< N, T > &v)
Computes the length/magnitude of a vector.
Definition vec.h:289
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:685
std::ostream & operator<<(std::ostream &os, Graph::Vertex v)
Output stream support for Graph::Vertex.
Definition graph.h:1300
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:481
std::istream & operator>>(std::istream &is, GenericLine< DIM, FT > &line)
Input stream support for GenericLine.
Definition line.h:183
FT dot(const std::vector< FT > &, const std::vector< FT > &)
Inner product for vectors.
Definition matrix.h:1834