SUAPI-CppWrapper
C++WrapperforSketchUpCAPI
Geometry.cpp
1 //
2 // Geometry.cpp
3 //
4 // Sketchup C++ Wrapper for C API
5 // MIT License
6 //
7 // Copyright (c) 2017 Tom Kaneko
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 
16 // The above copyright notice and this permission notice shall be included in all
17 // copies or substantial portions of the Software.
18 
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 // SOFTWARE.
26 //
27 
28 #include <stdio.h>
29 #include <cmath>
30 #include <stdexcept>
31 #include <cassert>
32 
33 #include <SketchUpAPI/model/vertex.h>
34 
35 #include "SUAPI-CppWrapper/Geometry.hpp"
36 
37 #include "SUAPI-CppWrapper/model/Face.hpp"
38 #include "SUAPI-CppWrapper/model/Edge.hpp"
39 
40 //#include "SUAPI-CppWrapper/Plane.h"
41 //#include "SUAPI-CppWrapper/Line.h"
42 //#include "SUAPI-CppWrapper/float3.h"
43 namespace CW {
44 
45 /**
46 * Radians
47 */
48 Radians::Radians(const double &rhs):
49  m_val(rhs)
50 {
51  if(rhs > PI2) {
52  m_val = std::fmod(rhs, PI2);
53  }
54  else if(rhs < 0.0) {
55  m_val = PI2 - std::fmod(std::fabs(rhs), PI2);
56  }
57 }
58 
59 // Copy constructor
60 Radians::Radians(const Radians &radians):
61  m_val(radians.m_val)
62 {}
63 
64 // Cast to double
65 Radians::operator double() const
66 {
67  return m_val;
68 }
69 
71  if (this == &radians)
72  return *this;
73 
74  m_val = radians.m_val;
75  return *this;
76 }
77 
78 // Add
79 Radians Radians::operator+(const double value) const {
80  return Radians(m_val + value);
81 }
82 
83 // Subtract
84 Radians Radians::operator-(const double value) const {
85  return Radians(m_val - value);
86 }
87 
88 // Multiply
89 Radians Radians::operator*(const double multiplier) const {
90  return m_val * multiplier;
91 }
92 
93 // Divide
94 Radians Radians::operator/(const double divider) const {
95  if (std::abs(divider) < EPSILON) {
96  throw std::invalid_argument("CW::Radians::operator/() cannot divide by zero");
97  }
98  return m_val * divider;
99 }
100 
101 Vector3D operator*(const double &lhs, const Vector3D &rhs) {
102  return rhs * lhs;
103 }
104 
105 bool Radians::operator==(const Radians& rhs) const {
106  return (fabs(static_cast<double>(*this) - static_cast<double>(rhs))) < EPSILON;
107 }
108 
109 bool Radians::operator==(const double rhs) const {
110  return (fabs(m_val - rhs)) < EPSILON;
111 }
112 
113 double Radians::difference(const Radians& other) const {
114  double diff = std::abs(m_val - other.m_val);
115  if (diff > PI) {
116  return (2*PI)-diff;
117  }
118  return diff;
119 }
120 
121 // Comparator TODO
122 bool Radians::closest(const Radians& value) {
123  return Radians(m_val - value);
124 }
125 
126 /********
127 * Vector3D
128 *********/
129 
130 constexpr double Vector3D::EPSILON;
131 
132 Vector3D::Vector3D():
133  Vector3D(false)
134 {}
135 
136 Vector3D::Vector3D(SUVector3D su_vector):
137  m_vector(su_vector),
138  x(m_vector.x),
139  y(m_vector.y),
140  z(m_vector.z)
141 {}
142 
143 Vector3D::Vector3D( double x, double y, double z):
144  m_vector(SUVector3D{x,y,z}),
145  x(m_vector.x),
146  y(m_vector.y),
147  z(m_vector.z)
148 {}
149 
150 Vector3D::Vector3D(bool valid):
151  m_vector(SUVector3D{0.0,0.0,0.0}),
152  is_null(!valid),
153  x(m_vector.x),
154  y(m_vector.y),
155  z(m_vector.z)
156 {}
157 
158 
159 Vector3D::Vector3D(const Edge &edge):
160  Vector3D(edge.vector())
161 {}
162 
163 Vector3D::Vector3D(const Vector3D &vector):
164  m_vector(vector.m_vector),
165  is_null(vector.is_null),
166  x(m_vector.x),
167  y(m_vector.y),
168  z(m_vector.z)
169 {}
170 
171 
172 Vector3D::Vector3D(const Point3D& point):
173  Vector3D(SUVector3D{point.x, point.y, point.z})
174 {
175  is_null = !point;
176 }
177 
178 
180  if (this == &vector) {
181  return *this;
182  }
183  x = vector.x;
184  y = vector.y;
185  z = vector.z;
186  is_null = vector.is_null;
187  return *this;
188 }
189 
190 Vector3D& Vector3D::operator=(const SUVector3D &vector) {
191  x = vector.x;
192  y = vector.y;
193  z = vector.z;
194  is_null = false;
195  return *this;
196 }
197 
198 // Casting
199 Vector3D::operator SUVector3D() const {
200  assert(!is_null);
201  return m_vector;
202 }
203 
204 Vector3D::operator const SUVector3D*() const {
205  assert(!is_null);
206  return &m_vector;
207 }
208 
209 Vector3D::operator Point3D() const {
210  Point3D point(!this->is_null);
211  point.x = x;
212  point.y = y;
213  point.z = z;
214  return point;
215 }
216 
217 // Operator overloads
218 Vector3D Vector3D::operator+(const Vector3D &vector) const {
219  assert(!!vector && !is_null);
220  return Vector3D(m_vector.x + vector.x, m_vector.y + vector.y, m_vector.z + vector.z);
221 }
222 
223 Point3D operator+(const Vector3D &lhs, const Point3D& rhs) {
224  return rhs + lhs;
225 }
226 
227 Vector3D Vector3D::operator-() const {
228  return Vector3D(-x, -y, -z);
229 }
230 
231 Vector3D Vector3D::operator-(const Vector3D &vector) const {
232  assert(!!vector && !is_null);
233  return Vector3D(x - vector.x, y - vector.y, z - vector.z);
234 }
235 Vector3D Vector3D::operator*(const double &scalar) const {
236  assert(!is_null);
237  return Vector3D( x * scalar, y * scalar, z * scalar);
238 }
239 Vector3D Vector3D::operator/(const double &scalar) const {
240  assert(!is_null);
241  if (std::abs(scalar) < EPSILON) {
242  throw std::invalid_argument("CW::Vector3D::operator/() - cannot divide by zero");
243  }
244  return Vector3D( x / scalar, y / scalar, z / scalar);
245 }
246 
247 bool operator==(const Vector3D &lhs, const Vector3D &rhs) {
248  if (!lhs && !rhs) {
249  return true;
250  }
251  if (!!lhs && !!rhs &&
252  std::abs(lhs.x - rhs.x) < Vector3D::EPSILON &&
253  std::abs(lhs.y - rhs.y) < Vector3D::EPSILON &&
254  std::abs(lhs.z - rhs.z) < Vector3D::EPSILON) {
255  return true;
256  }
257  return false;
258 }
259 
260 
261 bool operator!=(const Vector3D &lhs, const Vector3D &rhs) {
262  if (lhs == rhs) {
263  return false;
264  }
265  return true;
266 }
267 
268 
269 bool Vector3D::operator!() const {
270  if (this->is_null) {
271  return true;
272  }
273  return false;
274 }
275 
276 
277 double Vector3D::length() const {
278  assert(!is_null);
279  return sqrt(pow(x,2) + pow(y,2) + pow(z,2));
280 }
281 
282 Vector3D Vector3D::unit() const {
283  assert(!is_null);
284  return *this / length();
285 }
286 
287 double Vector3D::angle(const Vector3D& vector_b) const {
288  assert(!is_null);
289  // Check that acos doesn't suffer domain error as a result of being slightly outside the range of -1 to +1
290  double dot_product = unit().dot(vector_b.unit());
291  if (dot_product < -1.0) {
292  dot_product = -1.0;
293  }
294  else if (dot_product > 1.0) {
295  dot_product = 1.0;
296  }
297  return acos(dot_product);
298 }
299 
300 double Vector3D::dot(const Vector3D& vector2) const {
301  assert(!!vector2 && !is_null);
302  return (x * vector2.x) + (y * vector2.y) + (z * vector2.z);
303 }
304 
305 double Vector3D::dot(const Point3D& point) const {
306  assert(!!point && !is_null);
307  return (x * point.x) + (y * point.y) + (z * point.z);
308 }
309 
310 
311 Vector3D Vector3D::cross(const Vector3D& vector2) const {
312  assert(!!vector2 && !is_null);
313  return Vector3D{y * vector2.z - z * vector2.y,
314  z * vector2.x - x * vector2.z,
315  x * vector2.y - y * vector2.x};
316 }
317 
318 Vector3D::Colinearity Vector3D::colinear(const Vector3D& vector_b) const {
319  if (this->length() < EPSILON || vector_b.length() < EPSILON) {
320  return Vector3D::Colinearity::UNDEFINED;
321  }
322  Vector3D combined = (*this) + vector_b;
323  double combined_length = combined.length();
324  double added_length = (*this).length() + vector_b.length();
325  if (std::fabs(added_length - combined_length) < EPSILON) {
326  return Vector3D::Colinearity::COLINEAR_PRO;
327  }
328  double subtracted_length = (*this).length() - vector_b.length();
329  if (std::fabs(subtracted_length - combined_length) < EPSILON) {
330  return Vector3D::Colinearity::COLINEAR_ANTI;
331  }
332  return Vector3D::Colinearity::NO;
333 }
334 
335 
336 Vector3D Vector3D::rotate_about(double angle, const Vector3D& axis) const {
337  // This solution is derived from this page: http://math.stackexchange.com/questions/511370/how-to-rotate-one-vector-about-another
338  double b_dot_b = axis.dot(axis);
339  Vector3D a_component_b_dir = ((*this).dot(axis) * b_dot_b) * axis;
340  Vector3D a_component_b_orth = (*this) - (((*this).dot(axis) / b_dot_b) * axis);
341  Vector3D w = axis.cross(a_component_b_orth);
342  double x1 = cos(angle) / a_component_b_orth.length();
343  double x2 = sin(angle) / w.length();
344  Vector3D a_component_b_orth_rot = a_component_b_orth.length() * ((x1 * a_component_b_orth) + (x2 * w));
345  return a_component_b_orth_rot + a_component_b_dir;
346 }
347 
349  return Vector3D(0.0, 0.0, 0.0);
350 }
351 
352 
353 /********
354 * Point3D
355 *********/
357  Point3D(false)
358 {}
359 
360 Point3D::Point3D(bool valid):
361  m_point(SUPoint3D{0.0,0.0,0.0}),
362  is_null(!valid),
363  x(m_point.x),
364  y(m_point.y),
365  z(m_point.z)
366 {}
367 
368 Point3D::Point3D( SUPoint3D su_point):
369  m_point(su_point),
370  x(m_point.x),
371  y(m_point.y),
372  z(m_point.z)
373 {}
374 
375 Point3D::Point3D( SUVector3D su_vector):
376  Point3D(SUPoint3D{su_vector.x, su_vector.y, su_vector.z})
377 {}
378 
379 Point3D::Point3D(double x, double y, double z):
380  Point3D(SUPoint3D{x, y, z})
381 {}
382 
383 Point3D::Point3D(const Point3D& other):
384  Point3D(other.x, other.y, other.z)
385 {
386  is_null = other.is_null;
387 }
388 
389 
390 Point3D::Point3D( const Vector3D& vector):
391  Point3D(SUPoint3D{vector.x, vector.y, vector.z})
392 {}
393 
395  if (this == &point) {
396  return *this;
397  }
398  x = point.x;
399  y = point.y;
400  z = point.z;
401  is_null = point.is_null;
402  return *this;
403 }
404 
405 
406 Point3D::operator SUPoint3D() const { return SUPoint3D {m_point.x, m_point.y, m_point.z}; }
407 
408 
409 Point3D::operator const SUPoint3D*() const{
410  //m_point = SUPoint3D{m_point.x, m_point.y, m_point.z};
411  return &m_point;
412 }
413 
414 Point3D::operator Vector3D() const { return Vector3D(m_point.x, m_point.y, m_point.z); }
415 
416 // Operator overloads
417 Point3D Point3D::operator+(const Point3D &point) const {
418  assert(!!point && !is_null);
419  return Point3D(m_point.x + point.x, m_point.y + point.y, m_point.z + point.z);
420 }
421 
422 Point3D Point3D::operator+(const Vector3D &vector) const {
423  assert(!!vector && !is_null);
424  return Point3D(m_point.x + vector.x, m_point.y + vector.y, m_point.z + vector.z);
425 }
426 
427 Point3D Point3D::operator+(const SUPoint3D &point) const {
428  assert(!is_null);
429  return (*this) + Point3D(point);
430 }
431 
432 Vector3D Point3D::operator-(const Point3D &point) const {
433  assert(!!point && !is_null);
434  return Vector3D(m_point.x - point.x, m_point.y - point.y, m_point.z - point.z);
435 }
436 
437 Point3D Point3D::operator-(const Vector3D &vector) const {
438  assert(!!vector && !is_null);
439  return (*this) - static_cast<Point3D>(vector);
440 }
441 
442 Point3D Point3D::operator-(const SUPoint3D &point) const {
443  assert(!is_null);
444  return (*this) - Point3D(point);
445 }
446 
447 Point3D Point3D::operator*(const double &scalar) const {
448  assert(!is_null);
449  return Point3D(m_point.x * scalar, m_point.y * scalar, m_point.z * scalar);
450 }
451 
452 Point3D Point3D::operator/(const double &scalar) const {
453  assert(!is_null);
454  if (std::abs(scalar) < EPSILON) {
455  throw std::invalid_argument("Point3D::operator/: cannot divide by zero");
456  }
457  return Point3D(m_point.x / scalar, m_point.y / scalar, m_point.z / scalar);
458 }
459 
460 /**
461 * Comparative operators
462 */
463 bool Point3D::operator!() const {
464  if (is_null) {
465  return true;
466  }
467  return false;
468 }
469 
470 bool operator==(const Point3D &lhs, const Point3D &rhs) {
471  if (!lhs && !rhs) {
472  return true;
473  }
474  if (!!lhs && !!rhs &&
475  std::abs(lhs.x - rhs.x) < Point3D::EPSILON &&
476  std::abs(lhs.y - rhs.y) < Point3D::EPSILON &&
477  std::abs(lhs.z - rhs.z) < Point3D::EPSILON) {
478  return true;
479  }
480  return false;
481 }
482 
483 
484 bool operator!=(const Point3D &lhs, const Point3D &rhs) {
485  if (lhs == rhs) {
486  return false;
487  }
488  return true;
489 }
490 
491 
492 /**
493 * Static method
494 */
495 Point3D Point3D::intersection_between_lines(const Point3D& point_a, const Vector3D& vector_a, const Point3D& point_b, const Vector3D& vector_b, bool return_colinear) {
496  if (vector_a.length() < EPSILON || vector_b.length() < EPSILON) {
497  throw std::invalid_argument("CW::Point3D::intersection_between_lines() - cannot find intersection of lines with zero length");
498  }
499  // Find the closest points according to this solution: http://paulbourke.net/geometry/pointlineplane/
500  // And this: http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
501  Vector3D a_to_b = point_b - point_a;
502  Vector3D vec_a_cross_b = vector_a.unit().cross(vector_b.unit());
503  Vector3D a_to_b_cross_vec_a = a_to_b.unit().cross(vector_a.unit());
504  Vector3D zero_vector(0.0,0.0,0.0);
505  // Check for collinearity
506  if (vec_a_cross_b == zero_vector) {
507  if (a_to_b_cross_vec_a == zero_vector) {
508  // Lines are collinear, so there is no intersection
509  if (!return_colinear) {
510  return Point3D(false);
511  }
512  bool opposite_direction;
513  if (vector_a.unit() == vector_b.unit())
514  opposite_direction = false;
515  else
516  opposite_direction = true;
517  double vec_a_factor_0 = a_to_b.dot(vector_a) / vector_a.dot(vector_a);
518  double vec_a_factor_1 = vec_a_factor_0 + (vector_b.dot(vector_a) / vector_a.dot(vector_a));
519  double vec_a_epsilon = Vector3D::EPSILON / vector_a.length(); // Note accuracy needs to be determined
520  if ((!opposite_direction && vec_a_factor_0 < vec_a_epsilon && vec_a_factor_1 > -vec_a_epsilon) ||
521  (opposite_direction && vec_a_factor_1 < vec_a_epsilon && vec_a_factor_0 > -vec_a_epsilon)) {
522  // The intersection is at the start of line A
523  return point_a;
524  }
525  if ((!opposite_direction && vec_a_factor_0 > -vec_a_epsilon && vec_a_factor_0 < (1 + vec_a_epsilon))) {
526  // The intersection is at the start of line B
527  return point_b;
528  }
529  if (opposite_direction && vec_a_factor_1 > -vec_a_epsilon && vec_a_factor_1 < (1 + vec_a_epsilon)) {
530  // The intersection is at the end of line B
531  return point_b + vector_b;
532  }
533  // Lines are disjoint
534  return Point3D(false);
535 
536  }
537  else {
538  // Lines are parallel, and so there is no intersection.
539  return Point3D(false);
540  }
541  }
542  // We create lines and find the closest points between them.
543  Line3D line_a(point_a, vector_a);
544  Line3D line_b(point_b, vector_b);
545  std::pair<Point3D, Point3D> closest_points = line_a.closest_points(line_b);
546  // Check closest points are actually the same.
547  if (closest_points.first != closest_points.second) {
548  // No intersection
549  return Point3D(false);
550  }
551  // Otherwise, we need to see if the intersection of the lines lie between the line segments
552  Point3D intersection = closest_points.first;
553  Vector3D a_to_int = intersection - point_a;
554  Vector3D b_to_int = intersection - point_b;
555  // Express the point of intersection as a scalar of the vectors from point A and point B
556  double a_direction_factor = 0.0;
557  if (a_to_int != zero_vector)
558  a_direction_factor = vector_a.unit().dot(a_to_int.unit());
559  double b_direction_factor = 0.0;
560  if (b_to_int != zero_vector)
561  b_direction_factor = vector_b.unit().dot(b_to_int.unit());
562 
563  double a_factor = a_direction_factor * a_to_int.length() / vector_a.length();
564  double b_factor = b_direction_factor * b_to_int.length() / vector_b.length();
565  double a_epsilon = Vector3D::EPSILON / vector_a.length();
566  double b_epsilon = Vector3D::EPSILON / vector_b.length();
567  if (a_factor > -a_epsilon && a_factor < 1.0 + a_epsilon &&
568  b_factor > -b_epsilon && b_factor < 1.0 + b_epsilon) {
569  return intersection;
570  }
571  return Point3D(false);
572 }
573 
574 
575 Point3D Point3D::ray_line_intersection(const Point3D& point_a, const Vector3D& vector_a, const Point3D& point_b, const Vector3D& ray_b, bool return_colinear) {
576  // Solution to finding intersection between two line segments derived from this answer: http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
577  Vector3D zero_vector(0.0,0.0,0.0);
578  if (ray_b == zero_vector || vector_a == zero_vector) {
579  throw std::invalid_argument("CW::Point3D::ray_line_intersection() - given ray/line have zero length");
580  }
581  Vector3D a_to_b = point_b - point_a;
582  // Check if the start of the lines touch
583  if (a_to_b == zero_vector) {
584  return point_a;
585  }
586  Vector3D b_to_a = -a_to_b;
587  Vector3D vec_a_cross_b_z_comp = vector_a.unit().cross(ray_b.unit()); // Use unit vectors for easier comparisons with zero vector
588  Vector3D a_to_b_cross_vec_a_z_comp = a_to_b.unit().cross(vector_a.unit()); // Use unit vectors for easier comparisons with zero vector
589  // Check for collinearity
590  if (vec_a_cross_b_z_comp == zero_vector) {
591  if (a_to_b_cross_vec_a_z_comp == zero_vector) {
592  // Lines are collinear, so there is no intersection
593  if (!return_colinear) {
594  return Point3D(false);
595  }
596  double b_to_a_factor = b_to_a.dot(ray_b) / ray_b.dot(ray_b);
597  double b_to_a_end_factor = b_to_a_factor + (vector_a.dot(ray_b) / ray_b.dot(ray_b));
598  if ((b_to_a_factor < 0.0 && b_to_a_end_factor > 0.0) || (b_to_a_factor > 0.0 && b_to_a_end_factor < 0.0)) {
599  // The start of ray B is on line A
600  return point_b;
601  }
602  if (b_to_a_factor > 0.0) {
603  if (b_to_a_factor < b_to_a_end_factor) {
604  // The intersection is at the start of line A
605  return point_a;
606  }
607  else {
608  // The intersection is at the end of line B
609  return point_a + vector_a;
610  }
611  }
612  // Lines are disjoint
613  return Point3D(false);
614 
615  }
616  else {
617  // Lines are parallel, and so there is no intersection.
618  return Point3D(false);
619  }
620  }
621  // We create lines and find the closest points between them.
622  Line3D line_a(point_a, vector_a);
623  Line3D line_b(point_b, ray_b);
624  std::pair<Point3D, Point3D> closest_points = line_a.closest_points(line_b);
625  // Check closest points are actually the same.
626  if (closest_points.first != closest_points.second) {
627  // No intersection
628  return Point3D(false);
629  }
630  // Otherwise, we need to see if the intersection of the lines lie between the line segments
631  Point3D intersection = closest_points.first;
632  Vector3D a_to_int = intersection - point_a;
633  Vector3D b_to_int = intersection - point_b;
634  // Express the point of intersection as a scalar of the vectors from point A and point B
635  double a_direction_factor = 0.0;
636  if (a_to_int != zero_vector)
637  a_direction_factor = vector_a.unit().dot(a_to_int.unit());
638  double b_direction_factor = 0.0;
639  if (b_to_int != zero_vector)
640  b_direction_factor = ray_b.unit().dot(b_to_int.unit());
641 
642  double a_factor = a_direction_factor * a_to_int.length() / vector_a.length();
643  double b_factor = b_direction_factor * b_to_int.length() / ray_b.length();
644  double a_epsilon = Vector3D::EPSILON / vector_a.length();
645  double b_epsilon = Vector3D::EPSILON / ray_b.length();
646  if (a_factor > -a_epsilon && a_factor < 1.0 + a_epsilon &&
647  b_factor > -b_epsilon) {
648  return intersection;
649  }
650  return Point3D(false);
651 
652  /*
653  else if (a_to_b_cross_vec_a_z_comp != zero_vector) {
654  Vector3D vec_a_cross_b = vector_a.cross(ray_b);
655  double line_a_factor = a_to_b.cross(ray_b).length() / vec_a_cross_b.length();
656  double a_epsilon = Vector3D::EPSILON / vector_a.length(); // Note accuracy needs to be determined
657  double line_b_factor = b_to_a.cross(vector_a).length() / vec_a_cross_b.length();
658  double b_epsilon = Vector3D::EPSILON / ray_b.length();
659  if (-a_epsilon <= line_a_factor && line_a_factor <= (1.0 + a_epsilon) &&
660  -b_epsilon <= line_b_factor) {
661  Point3D intersection = point_a + (vector_a * line_a_factor);
662  return intersection;
663  }
664  }
665  // The lines do not intersect
666  return Point3D(false);
667  */
668 }
669 
670 
671 
672 /********
673 * Plane3D
674 *********/
675 Plane3D::Plane3D():
676  Plane3D(SUPlane3D{0.0,0.0,0.0,0.0})
677 {}
678 
679 Plane3D::Plane3D(SUPlane3D plane):
680  m_plane(plane),
681  is_null((m_plane.a == 0.0 && m_plane.b == 0.0 && m_plane.c == 0.0)),
682  a(m_plane.a),
683  b(m_plane.b),
684  c(m_plane.c),
685  d(m_plane.d)
686 {}
687 
688 
689 Plane3D::Plane3D(double a, double b, double c, double d):
690  Plane3D(SUPlane3D{a,b,c,d})
691 {}
692 
693 
694 Plane3D::Plane3D(const Face &face):
695  Plane3D(face.plane())
696 {}
697 
698 
699 Plane3D::Plane3D(const Plane3D &plane):
700  m_plane(plane.m_plane),
701  is_null(plane.is_null),
702  a(m_plane.a),
703  b(m_plane.b),
704  c(m_plane.c),
705  d(m_plane.d)
706 {}
707 
708 
709 Plane3D::Plane3D(const Vector3D& normal, const Point3D& point):
710  Plane3D(SUPlane3D{normal.unit().x, normal.unit().y, normal.unit().z, -normal.unit().dot(point)})
711 {
712 }
713 Plane3D::Plane3D(const Point3D& point, const Vector3D& normal):
714  Plane3D(normal, point)
715 {}
716 
717 
718 Plane3D::Plane3D(bool valid):
719  m_plane(SUPlane3D{1.0,0.0,0.0,0.0}),
720  is_null(!valid),
721  a(m_plane.a),
722  b(m_plane.b),
723  c(m_plane.c),
724  d(m_plane.d)
725 {}
726 
727 
728 
729 Plane3D& Plane3D::operator=(const Plane3D &plane) {
730  if (this == &plane)
731  return *this;
732  a = plane.a;
733  b = plane.b;
734  c = plane.c;
735  d = plane.d;
736  is_null = plane.is_null;
737  return *this;
738 }
739 
740 bool Plane3D::operator!() const {
741  if (is_null) {
742  return true;
743  }
744  return false;
745 }
746 
747 /**
748 * Comparative operators
749 */
750 bool operator==(const Plane3D &lhs, const Plane3D &rhs) {
751  if (!lhs && !rhs) {
752  return true;
753  }
754  if (!!lhs && !!rhs &&
755  std::abs(lhs.a - rhs.a) < Plane3D::EPSILON &&
756  std::abs(lhs.b - rhs.b) < Plane3D::EPSILON &&
757  std::abs(lhs.c - rhs.c) < Plane3D::EPSILON &&
758  std::abs(lhs.d - rhs.d) < Plane3D::EPSILON) {
759  return true;
760  }
761  return false;
762 }
763 
764 bool operator!=(const Plane3D &lhs, const Plane3D &rhs) {
765  if (lhs == rhs) {
766  return false;
767  }
768  return true;
769 }
770 
771 
772 bool Plane3D::coplanar(const Plane3D& test_plane) const {
773  if (this->parallel(test_plane)) {
774  if ((this->normal() * this->d) == (test_plane.normal() * test_plane.d)) {
775  return true;
776  }
777  }
778  return false;
779 }
780 
781 
782 Line3D Plane3D::intersection(const Plane3D& plane2) const {
783  const Vector3D line_vector = (*this).normal().cross(plane2.normal());
784  const double determinant = pow(line_vector.length(), 2);
785 
786  if (determinant < EPSILON) {
787  // Parallel planes
788  return Line3D(false);
789  }
790  Point3D line_point = ((line_vector.cross(plane2.normal()) * (*this).d) +
791  ((*this).normal().cross(line_vector) * plane2.d)) / determinant;
792  return Line3D(line_point, line_vector);
793 }
794 
796  return line.intersection(*this);
797 }
798 
799 
800 Point3D Plane3D::intersection(const Point3D& start_point, const Vector3D& direction) const {
801  // First check that an intersection exists, by checking if the ray is pointing towards the plane
802  Vector3D unit_direction = direction.unit();
803  double combined_length = Vector3D(this->normal() + unit_direction).length();
804  double distance_from_plane = this->distance(start_point);
805  if (combined_length > 1.0) {
806  if (distance_from_plane > EPSILON) {
807  return Point3D(false);
808  }
809  else {
810  return this->intersection(Line3D(start_point, unit_direction));
811  }
812  }
813  else {
814  if (distance_from_plane < -EPSILON) {
815  return Point3D(false);
816  }
817  else {
818  return this->intersection(Line3D(start_point, unit_direction));
819  }
820  }
821 }
822 
823 
824 Point3D Plane3D::intersection_between(const Point3D& point_a, const Point3D& point_b) const {
825  Line3D temp_line(point_a, Vector3D(point_b-point_a));
826  Point3D intersection = this->intersection(temp_line);
827  if (!!intersection && Line3D::on_line_segment(point_a, point_b, intersection)) {
828  return intersection;
829  }
830  return Point3D(false);
831 }
832 
833 
835  return Vector3D{a,b,c};
836 }
837 
838 double Plane3D::distance(const Point3D& point) const {
839  return normal().dot(point) + d;
840 }
841 
842 bool Plane3D::on_plane(const Point3D& point) const {
843  double distance = this->distance(point);
844  if (fabs(distance) < EPSILON) {
845  return true;
846  }
847  return false;
848 }
849 
850 
851 Plane3D Plane3D::offset(double offset_by) const {
852  return Plane3D(a, b, c, (d - offset_by));
853 }
854 
855 
856 bool Plane3D::parallel(const Plane3D& plane2) const {
857  if (!plane2) {
858  throw std::invalid_argument("CW::Plane3D::parallel(): given plane is null");
859  }
860  if (!(*this)) {
861  throw std::logic_error("CW::Plane3D::parallel(): plane is null");
862  }
863  // The following assumes that the plane normals are unit vectors.
864  if (this->normal() == plane2.normal() || this->normal() == -plane2.normal()) {
865  return true;
866  }
867  return false;
868 }
869 
871  if (!(*this)) {
872  throw std::logic_error("CW::Plane3D::inverse(): plane is null");
873  }
874  return Plane3D(a*-1, b*-1, c*-1, d*-1);
875 }
876 
877 double Plane3D::angle_with(const Plane3D& plane2) const {
878  if (!plane2) {
879  throw std::invalid_argument("CW::Plane3D::angle_with(): given plane is null");
880  }
881  if (!(*this)) {
882  throw std::logic_error("CW::Plane3D::angle_with(): plane is null");
883  }
884  // Solution taken form this: https://www.youtube.com/watch?v=C6ElQdRbHaE
885  return acos(std::abs(normal().dot(plane2.normal())));
886 }
887 
888 
889 Plane3D::operator SUPlane3D() const { return m_plane; }
890 
891 
892 Plane3D Plane3D::plane_from_loop(const std::vector<Point3D>& loop_points) {
893  if (loop_points.size() < 3) {
894  throw std::invalid_argument("CW::Plane3D::plane_from_loop(): not enough points given for a valid loop");
895  }
896  /*
897  if(loop_points.size() < 3) {
898  // This is an invalid plane
899  return Plane3D();
900  }
901  // Find 3 points which we can use to create this plane.
902  Point3D point_a = loop_points[0];
903  Point3D point_b = loop_points[1];
904  Line3D ab_line(point_a, Vector3D(point_b - point_a).unit());
905  Point3D point_c; // We first need to find a point that is not colinear with the other two points.
906  for (size_t i=2; i < loop_points.size(); i++) {
907  if (!ab_line.on_line(loop_points[i])) {
908  point_c = loop_points[i];
909  break;
910  }
911  }
912  if (!point_c) {
913  return Plane3D();
914  }
915  // Create a plane from the 3 points;
916  Vector3D normal = Vector3D(point_b-point_a).cross(Vector3D(point_c-point_b));
917  Plane3D temp_plane(point_a, normal);
918  // Check that all points given are on the plane.
919  for (size_t i=2; i < loop_points.size(); i++) {
920  if (!temp_plane.on_plane(loop_points[i])) {
921  return Plane3D();
922  }
923  }
924  return temp_plane;
925  */
926  // Solution for finding the planes here: http://www.euclideanspace.com/maths/algebra/vectors/applications/normals/
927  // We will use two adjacent edges of the the loop to create a plane from. The vertex that is furthest from the centre of the loop is where we will start
928 
929  // Or this solution: https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
930  Vector3D normal(0.0, 0.0, 0.0);
931  for (size_t i=0; i < loop_points.size(); i++) {
932  Point3D next;
933  Point3D current = loop_points[i];
934  if (i == loop_points.size() - 1) {
935  next = loop_points[0];
936  }
937  else {
938  next = loop_points[i+1];
939  }
940  normal.x += (current.y - next.y) * (current.z + next.z);
941  normal.y += (current.z - next.z) * (current.x + next.x);
942  normal.z += (current.x - next.x) * (current.y + next.y);
943  }
944  if (normal == Vector3D::zero_vector()) {
945  return Plane3D(false);
946  }
947  return Plane3D (loop_points[0], normal.unit());
948 }
949 
950 
951 
952 /**
953 * BoundingBox3D
954 */
955 
957  BoundingBox3D(SUBoundingBox3D{Point3D(), Point3D()})
958 {}
959 
961  m_bounding_box(SUBoundingBox3D{Point3D(), Point3D()}),
962  is_null(!valid)
963 {}
964 
965 BoundingBox3D::BoundingBox3D(SUBoundingBox3D bounding_box):
966  m_bounding_box(bounding_box)
967 {}
968 
970  if (is_null) {
971  return true;
972  }
973  return false;
974 }
975 
976 BoundingBox3D::operator SUBoundingBox3D() const {
977  return m_bounding_box;
978 }
979 
981  return Point3D(m_bounding_box.min_point);
982 }
983 
984 void BoundingBox3D::min_point(const Point3D& point) {
985  m_bounding_box.min_point = point;
986 }
987 
989  return Point3D(m_bounding_box.max_point);
990 }
991 
992 void BoundingBox3D::max_point(const Point3D& point) {
993  m_bounding_box.max_point = point;
994 }
995 
996 
997 /**
998 * Line3D
999 */
1000 
1002  Line3D(false)
1003 {}
1004 
1005 
1006 Line3D::Line3D(const Point3D point, const Vector3D direction):
1007  m_point(point),
1008  m_direction(direction.unit()),
1009  point(m_point),
1010  direction(m_direction)
1011 {}
1012 
1013 
1014 Line3D::Line3D(const Vector3D direction, const Point3D point):
1015  Line3D(point, direction)
1016 {}
1017 
1018 
1019 Line3D::Line3D(bool valid):
1020  m_point(Point3D(valid)),
1021  m_direction(Vector3D(valid)),
1022  is_null(!valid),
1023  point(m_point),
1024  direction(m_direction)
1025 {}
1026 
1027 
1028 Line3D::Line3D(const Line3D& other):
1029  m_point(other.m_point),
1030  m_direction(other.m_direction),
1031  is_null(other.is_null),
1032  point(m_point),
1033  direction(m_direction)
1034 {}
1035 
1036 
1037 Line3D& Line3D::operator=(const Line3D &line) {
1038  if (this == &line)
1039  return *this;
1040 
1041  point = line.point;
1042  direction = line.direction;
1043  is_null = line.is_null;
1044  return *this;
1045 }
1046 
1047 
1048 bool Line3D::operator!() const {
1049  if (is_null) {
1050  return true;
1051  }
1052  return false;
1053 }
1054 
1055 
1056 Point3D Line3D::intersection(const Line3D &other_line) const {
1057  if (!other_line) {
1058  throw std::invalid_argument("CW::Line3D::intersection(): given line is null");
1059  }
1060  if (!(*this)) {
1061  throw std::logic_error("CW::Line3D::intersection(): this line is null");
1062  }
1063  // @see http://paulbourke.net/geometry/pointlineplane/
1064  std::pair<Point3D, Point3D> close_points = this->closest_points(other_line);
1065  if (!close_points.first) {
1066  return close_points.first;
1067  }
1068  Vector3D vector_between = close_points.first - close_points.second;
1069  double distance = vector_between.length();
1070  if (distance > EPSILON) {
1071  // The lines do not intersect
1072  return Point3D(false);
1073  }
1074  return close_points.first;
1075 }
1076 
1077 
1078 Point3D Line3D::intersection(const Plane3D &plane) const {
1079  if (!plane) {
1080  throw std::invalid_argument("CW::Line3D::intersection(): given plane is null");
1081  }
1082  if (!(*this)) {
1083  throw std::logic_error("CW::Line3D::intersection(): this line is null");
1084  }
1085  // @see http://paulbourke.net/geometry/pointlineplane/
1086  double numerator = (plane.a * this->point.x) + (plane.b * this->point.y) + (plane.c * this->point.z) + plane.d;
1087  double denominator = -(plane.a * this->direction.x) - (plane.b * this->direction.y) - (plane.c * this->direction.z);
1088  if (std::abs(denominator) < EPSILON) {
1089  // The line is parallel to or on the plane
1090  return Point3D(false);
1091  }
1092  double u = numerator / denominator;
1093  Point3D point_of_intersection = this->point + (u * this->direction);
1094  return point_of_intersection;
1095 }
1096 
1097 
1098 std::pair<Point3D, Point3D> Line3D::closest_points(const Line3D &other_line) const {
1099  if (!other_line) {
1100  throw std::invalid_argument("CW::Line3D::closest_points(): given line is null");
1101  }
1102  if (!(*this)) {
1103  throw std::logic_error("CW::Line3D::closest_points(): this line is null");
1104  }
1105 
1106  // @see http://paulbourke.net/geometry/pointlineplane/
1107  double d1343,d4321,d1321,d4343,d2121;
1108  double numer,denom;
1109  // p13 is a vector between two points on different lines
1110  Vector3D p13 = this->point - other_line.point;
1111  Vector3D p43 = other_line.direction;
1112  if (std::abs(p43.x) < EPSILON && std::abs(p43.y) < EPSILON && std::abs(p43.z) < EPSILON) {
1113  // The two lines are along each other
1114  return std::pair<Point3D,Point3D> (Point3D(false), Point3D(false));
1115  }
1116  Vector3D p21 = this->direction;
1117  //if (std::abs(p21.x) < EPSILON/2 && std::abs(p21.y) < EPSILON/2 && std::abs(p21.z) < EPSILON/2) {
1118  // The vector is zero - should not happen
1119  // return std::pair<Point3D,Point3D> (Point3D(false), Point3D(false));
1120  //}
1121  d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z;
1122  d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z;
1123  d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z;
1124  d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z;
1125  d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z;
1126 
1127  denom = d2121 * d4343 - d4321 * d4321;
1128  if (std::abs(denom) < EPSILON) {
1129  // Lines are parallel
1130  return std::pair<Point3D,Point3D> (Point3D(false), Point3D(false));
1131  }
1132  numer = d1343 * d4321 - d1321 * d4343;
1133 
1134  double mua = numer / denom;
1135  double mub = (d1343 + d4321 * mua) / d4343;
1136  Point3D pa = this->point + (this->direction * mua);
1137  Point3D pb = other_line.point + (other_line.direction * mub);
1138  return std::pair<Point3D,Point3D> (pa, pb);
1139 }
1140 
1141 
1143  if (!point) {
1144  throw std::invalid_argument("CW::Line3D::closest_point(): given point is null");
1145  }
1146  if (!(*this)) {
1147  throw std::logic_error("CW::Line3D::closest_point(): this line is null");
1148  }
1149  // @see http://paulbourke.net/geometry/pointlineplane/
1150  // [P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0 - where U is the factor
1151  Vector3D start_to_point = point - m_point;
1152  double factor = start_to_point.dot(m_direction);
1153  return m_point + (factor * m_direction);
1154 }
1155 
1156 
1157 double Line3D::distance(const Point3D& point) const {
1158  Point3D closest_point = this->closest_point(point);
1159  return Vector3D(point - closest_point).length();
1160 }
1161 
1162 
1163 bool Line3D::on_line(const Point3D& test_point) const {
1164  if (!test_point) {
1165  throw std::invalid_argument("CW::Line3D::on_line(): given point is null");
1166  }
1167  if (!(*this)) {
1168  throw std::logic_error("CW::Line3D::on_line(): this line is null");
1169  }
1170  double factor;
1171  enum class OnLineFactorCoords {
1172  X,
1173  Y,
1174  Z
1175  };
1176  OnLineFactorCoords factor_val; // This is to save extra calculations.
1177  // To get the most accurate factor, use one of the larger values among x, y OR z to calculate the factor. The smallest possible value for all three x, y, z to have (given that direction is a unit vector) is 1 / sqrt(3) = 0.577
1178  if (this->direction.x > 0.56) {
1179  // Get the factor with which to multiply the x value, and see if it is the same for y and z values too.
1180  factor = (test_point.x - this->point.x) / this->direction.x;
1181  factor_val = OnLineFactorCoords::X;
1182  }
1183  else if (this->direction.y > 0.56) {
1184  factor = (test_point.y - this->point.y) / this->direction.y;
1185  factor_val = OnLineFactorCoords::Y;
1186  }
1187  else {
1188  factor = (test_point.z - this->point.z) / this->direction.z;
1189  factor_val = OnLineFactorCoords::Z;
1190  }
1191  if (factor_val != OnLineFactorCoords::X) {
1192  double x_test = this->point.x + (this->direction.x * factor);
1193  if (std::abs(x_test - test_point.x) > EPSILON) {
1194  return false;
1195  }
1196  }
1197  if (factor_val != OnLineFactorCoords::Y) {
1198  double y_test = this->point.y + (this->direction.y * factor);
1199  if (std::abs(y_test - test_point.y) > EPSILON) {
1200  return false;
1201  }
1202  }
1203  if (factor_val != OnLineFactorCoords::Z) {
1204  double z_test = this->point.z + (this->direction.z * factor);
1205  if (std::abs(z_test - test_point.z) > EPSILON) {
1206  return false;
1207  }
1208  }
1209  return true;
1210 }
1211 
1212 
1213 bool Line3D::on_line_segment(const Point3D& point_a, const Point3D& point_b, const Point3D& test_point) {
1214  if (!point_a || !test_point || !point_b) {
1215  throw std::invalid_argument("CW::Line3D::on_line_segment(): given point is null");
1216  }
1217  if (point_a == point_b) {
1218  throw std::invalid_argument("CW::Line3D::on_line_segment(): given points are equal");
1219  }
1220  // From: https://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment
1221  Vector3D a_to_b = point_b - point_a;
1222  Vector3D a_to_c = test_point - point_a;
1223  if (a_to_c == Vector3D::zero_vector()) {
1224  return true;
1225  }
1226  Vector3D crossproduct = a_to_b.unit().cross(a_to_c.unit());
1227  if (fabs(crossproduct.length()) > EPSILON) {
1228  // Not aligned
1229  return false;
1230  }
1231  // Check that the distance matches.
1232  double dotproduct = a_to_b.dot(a_to_c);
1233  if (dotproduct < EPSILON) {
1234  return false;
1235  }
1236 
1237  double squaredlengthba = pow(a_to_b.length()+EPSILON, 2);
1238  if (dotproduct > squaredlengthba) {
1239  return false;
1240  }
1241  return true;
1242 }
1243 
1244 
1245 /**
1246 * Returns true if the Line or vector given is parallel to this line.
1247 */
1248 bool Line3D::parallel(const Line3D &line) const {
1249  if (!line) {
1250  throw std::invalid_argument("CW::Line3D::parallel(): given line is null");
1251  }
1252  if (!(*this)) {
1253  throw std::logic_error("CW::Line3D::parallel(): this line is null");
1254  }
1255  if (line.direction == direction) {
1256  return true;
1257  }
1258  else if (line.direction == (direction * -1)) {
1259  return true;
1260  }
1261  return false;
1262 }
1263 
1264 
1265 bool Line3D::parallel(const Vector3D &vector) const {
1266  if (!vector) {
1267  throw std::invalid_argument("CW::Line3D::parallel(): given vector is null");
1268  }
1269  if (vector.length() < EPSILON) {
1270  throw std::invalid_argument("CW::Line3D::parallel(): given vector has zero length");
1271  }
1272  if (!(*this)) {
1273  throw std::logic_error("CW::Line3D::parallel(): this line is null");
1274  }
1275  Vector3D difference = this->direction.unit() - vector.unit();
1276  double length = difference.length();
1277  if (length < EPSILON || (length - 2.0) < EPSILON) {
1278  return true;
1279  }
1280  return false;
1281 }
1282 
1283 
1284 bool operator==(const Line3D& lhs, const Line3D& rhs) {
1285  if (lhs.parallel(rhs)) {
1286  // lines are parallel - check if they overlap
1287  if (lhs.m_point == rhs.m_point) {
1288  return true;
1289  }
1290  Vector3D l_to_r = rhs.m_point - lhs.m_point;
1291  if (l_to_r.colinear(lhs.m_direction) != Vector3D::Colinearity::NO) {
1292  return true;
1293  }
1294  }
1295  return false;
1296 }
1297 
1298 
1299 } /* namespace CW */
Line3D intersection(const Plane3D &plane2) const
Definition: Geometry.cpp:782
Vector3D normal() const
Definition: Geometry.cpp:834
Radians operator+(const double value) const
Definition: Geometry.cpp:79
double distance(const Point3D &point) const
Definition: Geometry.cpp:1157
static Point3D intersection_between_lines(const Point3D &point_a, const Vector3D &vector_a, const Point3D &point_b, const Vector3D &vector_b, bool return_colinear=false)
Definition: Geometry.cpp:495
friend bool operator==(const Vector3D &lhs, const Vector3D &rhs)
Definition: Geometry.cpp:247
static Point3D ray_line_intersection(const Point3D &point_a, const Vector3D &vector_a, const Point3D &point_b, const Vector3D &ray_b, bool return_colinear=false)
Definition: Geometry.cpp:575
Plane3D inverse() const
Definition: Geometry.cpp:870
double dot(const Vector3D &vector2) const
Definition: Geometry.cpp:300
Vector3D operator+(const Vector3D &vector) const
Definition: Geometry.cpp:218
friend bool operator==(const Plane3D &lhs, const Plane3D &rhs)
Definition: Geometry.cpp:750
Point3D intersection_between(const Point3D &point_a, const Point3D &point_b) const
Definition: Geometry.cpp:824
bool coplanar(const Plane3D &test_plane) const
Definition: Geometry.cpp:772
double difference(const Radians &other) const
Definition: Geometry.cpp:113
Plane3D offset(double offset_by) const
Definition: Geometry.cpp:851
static bool on_line_segment(const Point3D &point_a, const Point3D &point_b, const Point3D &test_point)
Definition: Geometry.cpp:1213
bool parallel(const Line3D &line) const
Definition: Geometry.cpp:1248
bool operator!() const
Definition: Geometry.cpp:269
bool operator!() const
Definition: Geometry.cpp:969
Point3D & operator=(const Point3D &point)
Definition: Geometry.cpp:394
Point3D operator+(const Point3D &point) const
Definition: Geometry.cpp:417
Point3D min() const
Definition: Geometry.cpp:980
bool operator!() const
Definition: Geometry.cpp:1048
void max_point(const Point3D &point)
Definition: Geometry.cpp:992
bool parallel(const Plane3D &plane2) const
Definition: Geometry.cpp:856
Point3D closest_point(const Point3D &point) const
Definition: Geometry.cpp:1142
bool on_line(const Point3D &point) const
Definition: Geometry.cpp:1163
Colinearity colinear(const Vector3D &vector_b) const
Definition: Geometry.cpp:318
static Vector3D zero_vector()
Definition: Geometry.cpp:348
friend bool operator==(const Line3D &lhs, const Line3D &rhs)
Definition: Geometry.cpp:1284
Definition: Color.hpp:34
bool on_plane(const Point3D &point) const
Definition: Geometry.cpp:842
Vector3D cross(const Vector3D &vector2) const
Definition: Geometry.cpp:311
Point3D max() const
Definition: Geometry.cpp:988
bool operator!() const
Definition: Geometry.cpp:463
double distance(const Point3D &point) const
Definition: Geometry.cpp:838
Radians & operator=(const Radians &radians)
Definition: Geometry.cpp:70
Vector3D rotate_about(double angle, const Vector3D &axis) const
Definition: Geometry.cpp:336
Vector3D & operator=(const Vector3D &vector)
Definition: Geometry.cpp:179
static Plane3D plane_from_loop(const std::vector< Point3D > &loop_points)
Definition: Geometry.cpp:892
bool operator!() const
Definition: Geometry.cpp:740
void min_point(const Point3D &point)
Definition: Geometry.cpp:984
std::pair< Point3D, Point3D > closest_points(const Line3D &line) const
Definition: Geometry.cpp:1098