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