Code_TYMPAN  4.4.0
Industrial site acoustic simulation
plan.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
16 #include <cassert>
17 
18 #include <boost/math/special_functions/fpclassify.hpp>
19 
20 #include "plan.h"
21 
22 #include <math.h>
23 
24 OPlan::OPlan() : _a(0.0), _b(0.0), _c(0.0), _d(0.0)
25 {
26  // Do not call this : update_explicit_repr();
27 }
28 
29 OPlan::OPlan(const OPlan& plan)
30 {
31  *this = plan;
33 }
34 
35 OPlan::OPlan(double a, double b, double c, double d) : _a(a), _b(b), _c(c), _d(d)
36 {
38 }
39 
40 OPlan::OPlan(const OPoint3D& pt1, const OPoint3D& pt2, const OPoint3D& pt3)
41 {
42  set(pt1, pt2, pt3);
43 }
44 
45 OPlan::OPlan(const OPoint3D& pt, const OVector3D& normale)
46 {
47  set(pt, normale);
48 }
49 
51 
53 {
54  if (this != &plan)
55  {
56  _a = plan._a;
57  _b = plan._b;
58  _c = plan._c;
59  _d = plan._d;
60  }
61  return *this;
62 }
63 
64 bool OPlan::operator==(const OPlan& plan) const
65 {
66  if (this != &plan)
67  {
68  if (_a != plan._a)
69  {
70  return false;
71  }
72  if (_b != plan._b)
73  {
74  return false;
75  }
76  if (_c != plan._c)
77  {
78  return false;
79  }
80  if (_d != plan._d)
81  {
82  return false;
83  }
84  }
85  return true;
86 }
87 
88 bool OPlan::operator!=(const OPlan& plan) const
89 {
90  return !operator==(plan);
91 }
92 
93 void OPlan::set(double a, double b, double c, double d)
94 {
95  _a = a;
96  _b = b;
97  _c = c;
98  _d = d;
100 }
101 
102 void OPlan::set(const OPoint3D& pt1, const OPoint3D& pt2, const OPoint3D& pt3)
103 {
104  _a = pt1._y * (pt2._z - pt3._z) + pt2._y * (pt3._z - pt1._z) + pt3._y * (pt1._z - pt2._z);
105  _b = pt1._z * (pt2._x - pt3._x) + pt2._z * (pt3._x - pt1._x) + pt3._z * (pt1._x - pt2._x);
106  _c = pt1._x * (pt2._y - pt3._y) + pt2._x * (pt3._y - pt1._y) + pt3._x * (pt1._y - pt2._y);
107  _d = -(pt1._x * (pt2._y * pt3._z - pt3._y * pt2._z) + pt2._x * (pt3._y * pt1._z - pt1._y * pt3._z) +
108  pt3._x * (pt1._y * pt2._z - pt2._y * pt1._z));
110 }
111 
112 void OPlan::set(const OPoint3D& pt, const OVector3D& normale)
113 {
114  _a = normale._x;
115  _b = normale._y;
116  _c = normale._z;
117  _d = -normale.scalar(pt);
119 }
120 
122 {
123  return _a == 0 && _b == 0 && _c == 0;
124 }
125 
127 {
128  return (boost::math::isnan(_a) || boost::math::isnan(_b) || boost::math::isnan(_c) ||
129  boost::math::isnan(_d));
130 }
131 
133 {
134  return !is_NaN() && !is_null();
135 }
136 
137 #define ___XBH_VERSION
138 #ifdef ___XBH_VERSION
139 
140 int OPlan::intersectsSegment(const OPoint3D& pt1, const OPoint3D& pt2, OPoint3D& ptIntersec) const
141 {
142  int res = INTERS_NULLE;
143 
144  double xSeg = pt2._x - pt1._x;
145  double ySeg = pt2._y - pt1._y;
146  double zSeg = pt2._z - pt1._z;
147 
148  double ps = xSeg * _a + ySeg * _b + zSeg * _c;
149  double ps1 = pt1._x * _a + pt1._y * _b + pt1._z * _c;
150  double t = NAN;
151 
152  if (ps != 0)
153  {
154  // La droite par laquelle passe le segment coupe le plan...
155  t = -(ps1 + _d) / ps;
156 
157  // ...mais est-ce que le segment lui-meme coupe le plan ?
158  if ((t >= 0) && (t <= 1))
159  {
160  ptIntersec._x = pt1._x + t * (pt2._x - pt1._x);
161  ptIntersec._y = pt1._y + t * (pt2._y - pt1._y);
162  ptIntersec._z = pt1._z + t * (pt2._z - pt1._z);
163 
164  ptIntersec._x = ABS(ptIntersec._x) > 1E-6 ? ptIntersec._x : 0.00;
165  ptIntersec._y = ABS(ptIntersec._y) > 1E-6 ? ptIntersec._y : 0.00;
166  ptIntersec._z = ABS(ptIntersec._z) > 1E-6 ? ptIntersec._z : 0.00;
167 
168  res = INTERS_OUI;
169  }
170  }
171  else // Le segment est parallele au plan
172  {
173  // Est-il dans le plan ?
174 
175  double z = ps1 + _d;
176 
177  if (ABS(z) < EPSILON_13)
178  {
179  res = INTERS_CONFONDU;
180  }
181  }
182 
183  return res;
184 }
185 
186 #else
187 
188 int OPlan::intersectsSegment(const OPoint3D& pt1, const OPoint3D& pt2, OPoint3D& ptIntersec) const
189 {
190  int res = INTERS_NULLE;
191 
192  OVector3D n(_a, _b, _c);
193  OVector3D vecPt1(pt1);
194  OVector3D vecPt2(pt2);
195  OVector3D vecSeg = vecPt2 - vecPt1;
196 
197  double ps = vecSeg.scalar(n);
198  double t;
199 
200  if (ps != 0)
201  {
202  // La droite par laquelle passe le segment coupe le plan...
203  t = -(vecPt1.scalar(n) + _d) / ps;
204 
205  // ...mais est-ce que le segment lui-meme coupe le plan ?
206  if ((t >= 0) && (t <= 1))
207  {
208  ptIntersec._x = pt1._x + t * (pt2._x - pt1._x);
209  ptIntersec._y = pt1._y + t * (pt2._y - pt1._y);
210  ptIntersec._z = pt1._z + t * (pt2._z - pt1._z);
211 
212  ptIntersec._x = ABS(ptIntersec._x) > 1E-6 ? ptIntersec._x : 0.00;
213  ptIntersec._y = ABS(ptIntersec._y) > 1E-6 ? ptIntersec._y : 0.00;
214  ptIntersec._z = ABS(ptIntersec._z) > 1E-6 ? ptIntersec._z : 0.00;
215  res = INTERS_OUI;
216  }
217  }
218  else // Le segment est parallele au plan
219  {
220  // Est-il dans le plan ?
221 
222  double z = vecPt1.scalar(n) + _d;
223 
224  if (ABS(z) < EPSILON_13)
225  {
226  res = INTERS_CONFONDU;
227  }
228  }
229 
230  return res;
231 }
232 #endif //___XBH_VERSION
233 
234 bool OPlan::isInPlan(const OPoint3D& pt)
235 {
236  OVector3D n(_a, _b, _c);
237  OVector3D vecPt1(pt);
238  bool res = false;
239 
240  double z = vecPt1.scalar(n) + _d;
241 
242  if (ABS(z) < EPSILON_6)
243  {
244  res = true;
245  }
246 
247  return res;
248 }
249 
250 int OPlan::intersectsDroite(const OPoint3D& pt, const OVector3D& vector, OPoint3D& ptIntersec)
251 {
252  int res = INTERS_NULLE;
253 
254  OVector3D n(_a, _b, _c);
255  OVector3D vecPt(pt);
256  double ps = NAN;
257 
258  ps = vector.scalar(n);
259 
260  if (ABS(ps) > 0.0)
261  {
262  double t = -(vecPt.scalar(n) + _d) / ps;
263 
264  ptIntersec._x = pt._x + t * vector._x;
265  ptIntersec._y = pt._y + t * vector._y;
266  ptIntersec._z = pt._z + t * vector._z;
267 
268  res = INTERS_OUI;
269  }
270 
271  return res;
272 }
273 
274 int OPlan::intersectsPlan(const OPlan& plan, OVector3D& vectorIntersec)
275 {
276  int res = INTERS_OUI;
277 
278  double Dxy = _a * plan._b - plan._a * _b;
279  double Dyz = _b * plan._c - plan._b * _c;
280  double Dzx = _c * plan._a - plan._c * _a;
281 
282  if (ABS(Dxy) >= EPSILON_13)
283  {
284  vectorIntersec._x = Dyz / Dxy;
285  vectorIntersec._y = Dzx / Dxy;
286  vectorIntersec._z = 1.0;
287  }
288  else if (ABS(Dyz) >= EPSILON_13)
289  {
290  vectorIntersec._x = 1.0;
291  vectorIntersec._y = Dzx / Dyz;
292  vectorIntersec._z = Dxy / Dyz;
293  }
294  else if (ABS(Dzx) >= EPSILON_13)
295  {
296  vectorIntersec._x = Dyz / Dzx;
297  vectorIntersec._y = 1.0;
298  vectorIntersec._z = Dxy / Dzx;
299  }
300  else
301  {
302  vectorIntersec._x = vectorIntersec._y = vectorIntersec._z = 0;
303  res = INTERS_CONFONDU;
304  }
305 
306  if (res == INTERS_OUI)
307  {
308  // On norme, c'est plus propre...
309  double norme = vectorIntersec.norme();
310 
311  if (norme != 0.0)
312  {
313  vectorIntersec._x /= norme;
314  vectorIntersec._y /= norme;
315  vectorIntersec._z /= norme;
316  }
317  }
318 
319  return res;
320 }
321 
322 int OPlan::intersectsSurface(const TabPoint3D& contour, OSegment3D& seg) const
323 {
324  int res = INTERS_NULLE;
325  bool ptAFind = false, ptBFind = false;
326  OPoint3D ptIntersec;
327 
328  // Contour
329  size_t nbPts = contour.size();
330 
331  // Pour chaque segment composant le contour
332  for (size_t i = 0; i < nbPts; i++)
333  {
334  if (intersectsSegment(contour[i], contour[(i + 1) % nbPts], ptIntersec) == INTERS_OUI)
335  {
336  if (!ptAFind)
337  {
338  // Un 1er point a ete trouve
339  seg._ptA = ptIntersec;
340  ptAFind = true;
341  }
342  else if (!ptBFind)
343  {
344  // Un 2eme point a ete trouve
345  if (ptIntersec == seg._ptA)
346  {
347  continue;
348  } // Cas ou le plan passe exactement par un point
349  seg._ptB = ptIntersec;
350  ptBFind = true;
351 
352  // Si on a trouve point B c'est qu'on a trouve point A on peut sortir victorieusement
353  res = INTERS_OUI;
354  break;
355  }
356  }
357  }
358 
359  return res;
360 }
361 
362 double OPlan::angle(const OPlan& plan)
363 {
364  double cosAngle = (_a * plan._a + _b * plan._b + _c * plan._c) /
365  (OVector3D(_a, _b, _c).norme() * OVector3D(plan._a, plan._b, plan._c).norme());
366 
367  return acos(cosAngle);
368 }
369 
370 double OPlan::distance(const OPoint3D& pt)
371 {
372  return ((_a * pt._x + _b * pt._y + _c * pt._z + _d) / OVector3D(pt).norme());
373 }
374 
376 {
377  OPoint3D ptSym;
378 
379  // D'abord on calcule K
380  double K = -(_a * pt._x + _b * pt._y + _c * pt._z + _d) / (_a * _a + _b * _b + _c * _c);
381 
382  // On calcule les coordonnées du point projeté sur le plan
383  double x1 = K * _a + pt._x;
384  double y1 = K * _b + pt._y;
385  double z1 = K * _c + pt._z;
386 
387  // On calcule enfin les coordonnées du point symétrique
388  ptSym._x = 2 * x1 - pt._x;
389  ptSym._y = 2 * y1 - pt._y;
390  ptSym._z = 2 * z1 - pt._z;
391 
392  return ptSym;
393 }
394 
396 {
397  OPoint3D ptProj;
398  // D'abord on calcule K
399  double K = -(_a * pt._x + _b * pt._y + _c * pt._z + _d) / (_a * _a + _b * _b + _c * _c);
400 
401  // On calcule les coordonnées du point projeté sur le plan
402  ptProj._x = K * _a + pt._x;
403  ptProj._y = K * _b + pt._y;
404  ptProj._z = K * _c + pt._z;
405 
406  return ptProj;
407 }
408 
409 bool OPlan::distancePlanParallel(const OPlan& plan, double& distance)
410 {
411  if (!isParallel(plan))
412  {
413  return false;
414  }
415 
416  distance = ABS(_d - plan._d) / OVector3D(_a, _b, _c).norme();
417 
418  return true;
419 }
420 
421 bool OPlan::isParallel(const OPlan& plan)
422 {
423  if (isOrthogonal(plan))
424  {
425  return false;
426  }
427 
428  if (((_a / plan._a) == (_b / plan._b)) && ((_b / plan._b) == (_c / plan._c)))
429  {
430  return true;
431  }
432 
433  return false;
434 }
435 
436 bool OPlan::isOrthogonal(const OPlan& plan)
437 {
438  if (((_a * plan._a) + (_b * plan._b) + (_c * plan._c)) == 0)
439  {
440  return true;
441  }
442  return false;
443 }
444 
445 void OPlan::update_explicit_repr(OVector3D hint /* = OVector3D(1, 1, 1) */)
446 {
447  // We check the plane is valid
448  // assert(is_valid()); // This is too strong, null planes are crated by TYRectangles e.g.
449  // 'Proper' null planes are silently ignored and planes built from NaN rejected
450  assert(!is_NaN() && "Trying to build a plane from NaN values !");
451  if (is_null())
452  {
453  return;
454  }
455 
456  // The origin of the plane is the projection on the plane of the 3D origin.
457  OVector3D N(_a, _b, _c);
458  N.normalize();
459  // Need to ensure that the hint vector and the normal vectors are NOT colinear
460  hint.normalize();
461  if (N.dot(hint) > 0.9) // Test for near colinearity
462  {
463  hint = OVector3D(0, 1, 0);
464  if (N.dot(hint) > 0.9) // Test for near colinearity
465  {
466  hint = OVector3D(0, 1, 0);
467  }
468  }
469  // Solve l.N belonging to the plane to find an origin
470  double l = -_d / (_a * N._x + _b * N._y + _c * N._z);
471  OPoint3D origin(N * l);
472  // orthogonal component of the hint vector
473  double h = hint.dot(N);
474  OVector3D U(hint - h * N);
475  U.normalize();
476  assert(fabs(N.dot(U)) < 0.001); // Check validity of the construction
477  OVector3D V(N.cross(U));
478  assert(fabs(V.norme() - 1.0) < 0.01); // Check validity of the construction
479  rframe.set(origin, U, V, N);
480 }
481 
482 ::std::ostream& operator<<(::std::ostream& os, const OPlan& p)
483 {
484  return os << "OPlan(" << p._a << ", " << p._b << ", " << p._c << ", " << p._d << ")";
485 }
#define EPSILON_6
Definition: 3d.h:39
#define INTERS_CONFONDU
The elements match.
Definition: 3d.h:31
#define INTERS_OUI
The intersection exists.
Definition: 3d.h:33
#define EPSILON_13
Definition: 3d.h:41
double ABS(double a)
Return the absolute value.
Definition: 3d.h:67
std::vector< OPoint3D > TabPoint3D
Definition: 3d.h:483
#define INTERS_NULLE
No intersection.
Definition: 3d.h:35
NxReal c
Definition: NxVec3.cpp:317
CGAL::Exact_predicates_inexact_constructions_kernel K
double _y
y coordinate of OCoord3D
Definition: 3d.h:283
double _z
z coordinate of OCoord3D
Definition: 3d.h:284
double _x
x coordinate of OCoord3D
Definition: 3d.h:282
Plan defined by its equation : ax+by+cz+d=0.
Definition: plan.h:31
int intersectsSegment(const OPoint3D &pt1, const OPoint3D &pt2, OPoint3D &ptIntersec) const
Calculate the intersection of this plane with a segment defined by two points.
Definition: plan.cpp:140
double _a
The a parameter in the equation ax+by+cz+d=0.
Definition: plan.h:325
double distance(const OPoint3D &pt)
Calculation of the minimal distance between a point and this plane.
Definition: plan.cpp:370
double _c
The c parameter in the equation ax+by+cz+d=0.
Definition: plan.h:329
bool operator!=(const OPlan &plan) const
The inequality operator.
Definition: plan.cpp:88
double _d
The d parameter in the equation ax+by+cz+d=0.
Definition: plan.h:331
bool isInPlan(const OPoint3D &pt)
Check if a point belongs to a plane.
Definition: plan.cpp:234
virtual ~OPlan()
Destructor.
Definition: plan.cpp:50
bool is_NaN()
Definition: plan.cpp:126
bool operator==(const OPlan &plan) const
The equality operator.
Definition: plan.cpp:64
void update_explicit_repr(OVector3D hint=OVector3D(1, 1, 1))
updates the implicit representation of the plane
Definition: plan.cpp:445
bool isOrthogonal(const OPlan &plan)
Check if this plan is perpendicular to another plan.
Definition: plan.cpp:436
ORepere3D rframe
Definition: plan.h:333
OPlan()
Default constructor With a=b=c=d=0.
Definition: plan.cpp:24
double _b
The b parameter in the equation ax+by+cz+d=0.
Definition: plan.h:327
double angle(const OPlan &plan)
Calculation of the angle between this plane and another plane.
Definition: plan.cpp:362
OPoint3D projPtPlan(const OPoint3D &pt)
Calculate the projection of a point on the plane.
Definition: plan.cpp:395
bool isParallel(const OPlan &plan)
Check if this plane is parallel with another plane.
Definition: plan.cpp:421
void set(double a, double b, double c, double d)
Sets a, b, c and d parameters directly.
Definition: plan.cpp:93
bool distancePlanParallel(const OPlan &plan, double &distance)
Calculate the distance between this plan and another parallel plane.
Definition: plan.cpp:409
int intersectsSurface(const TabPoint3D &contour, OSegment3D &segment) const
Compute intersection between a plan and a surface defined by his bounds.
Definition: plan.cpp:322
int intersectsPlan(const OPlan &plan, OVector3D &vectorIntersec)
Calculate the intersection of this plane with another plane.
Definition: plan.cpp:274
int intersectsDroite(const OPoint3D &pt, const OVector3D &vector, OPoint3D &ptIntersec)
Calculate the intersection of this plane with a line defined by a point and a vector.
Definition: plan.cpp:250
bool is_valid()
Check whether the plane is valid.
Definition: plan.cpp:132
bool is_null()
Definition: plan.cpp:121
OPlan & operator=(const OPlan &plan)
Assignment operator.
Definition: plan.cpp:52
OPoint3D symPtPlan(const OPoint3D &pt)
Calculate the symmetrical of a point relative to the plane.
Definition: plan.cpp:375
The 3D point class.
Definition: 3d.h:487
void set(const OPoint3D &origin, const OVector3D &vecI, const OVector3D &vecJ, const OVector3D &vecK)
Sets with a point and 3 vectors.
Definition: 3d.cpp:1427
Class to define a segment.
Definition: 3d.h:1141
OPoint3D _ptA
Point A of the segment.
Definition: 3d.h:1253
OPoint3D _ptB
Point B of the segment.
Definition: 3d.h:1255
The 3D vector class.
Definition: 3d.h:298
double norme() const
Computes the length of this vector.
Definition: 3d.cpp:215
void normalize()
Normalizes this vector.
Definition: 3d.cpp:225
double scalar(const OVector3D &vector) const
Performs the scalar product between this object and another vector.
Definition: 3d.cpp:210
OVector3D cross(const OVector3D &vector) const
Cross product.
Definition: 3d.cpp:196
double dot(const OVector3D &v)
dot product (assuming an orthonormal reference frame)
Definition: 3d.h:362
::std::ostream & operator<<(::std::ostream &os, const OPlan &p)
Definition: plan.cpp:482