Code_TYMPAN  4.4.0
Industrial site acoustic simulation
delaunay_maker.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 <math.h>
17 
18 #include "delaunay_maker.h"
19 
20 ODelaunayMaker::ODelaunayMaker(double triangulatePrecision)
21 {
22  _xEcartType = 0;
23  _yEcartType = 0;
24  _zEcartType = 0;
25  _xdecim = triangulatePrecision;
26  _ydecim = triangulatePrecision;
27  _zdecim = 0.0;
28  _xMin = 0;
29  _yMin = 0;
30  _zMin = 0;
31  _xMax = 0;
32  _yMax = 0;
33  _zMax = 0;
34  _dx = 0;
35  _dy = 0;
36  _dz = 0;
37  _triangulatePrecision = triangulatePrecision;
38 }
39 
41 
43 {
44  _triangleOut.clear();
45  _vertexInOut.clear();
46 
47  _xEcartType = 0;
48  _yEcartType = 0;
49  _zEcartType = 0;
50  _xdecim = 0.01;
51  _ydecim = 0.01;
52  _zdecim = 0.0;
53 
54  _xMin = 0;
55  _yMin = 0;
56  _zMin = 0;
57  _xMax = 0;
58  _yMax = 0;
59  _zMax = 0;
60 
61  _dx = 0;
62  _dy = 0;
63  _dz = 0;
64 }
65 
66 void ODelaunayMaker::setDecimation(double xdecim, double ydecim, double zdecim)
67 {
68  _xdecim = xdecim;
69  _ydecim = ydecim;
70  _zdecim = zdecim;
71 }
72 
74 {
75  _triangleOut.clear();
76 
77  decimate();
78  triangulate();
79  return true;
80 }
81 
82 void ODelaunayMaker::getBoundaries(double& xmin, double& ymin, double& zmin, double& xmax, double& ymax,
83  double& zmax)
84 {
85  xmin = _xMin;
86  ymin = _yMin;
87  zmin = _zMin;
88  xmax = _xMax;
89  ymax = _yMax;
90  zmax = _zMax;
91 }
92 
93 QList<OTriangle> ODelaunayMaker::getFaces(void)
94 {
95  return _triangleOut;
96 }
97 
98 QList<OPoint3D> ODelaunayMaker::getVertex(void)
99 {
100  return _vertexInOut;
101 }
102 
104 {
105  double cx = NAN, cy = NAN;
106 
107  if (fabs(p2._y - p1._y) < _triangulatePrecision)
108  {
109  double mx2 = 0.5 * (p2._x + p3._x);
110  double my2 = 0.5 * (p2._y + p3._y);
111  cx = 0.5 * (p2._x + p1._x);
112  cy = my2 - (p3._x - p2._x) * (cx - mx2) / (p3._y - p2._y);
113  }
114  else if (fabs(p3._y - p2._y) < _triangulatePrecision)
115  {
116  double mx1 = 0.5 * (p1._x + p2._x);
117  double my1 = 0.5 * (p1._y + p2._y);
118  cx = 0.5 * (p3._x + p2._x);
119  cy = my1 - (p2._x - p1._x) * (cx - mx1) / (p2._y - p1._y);
120  }
121  else
122  {
123  double m1 = -(p2._x - p1._x) / (p2._y - p1._y);
124  double m2 = -(p3._x - p2._x) / (p3._y - p2._y);
125  double mx1 = 0.5 * (p1._x + p2._x);
126  double mx2 = 0.5 * (p2._x + p3._x);
127  double my1 = 0.5 * (p1._y + p2._y);
128  double my2 = 0.5 * (p2._y + p3._y);
129  cx = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
130  cy = m1 * (cx - mx1) + my1;
131  }
132 
133  double dx = p2._x - cx;
134  double dy = p2._y - cy;
135 
136  return (OPoint3D(cx, cy, sqrt(dx * dx + dy * dy)));
137 }
138 
140 {
141  _vertexInOut.append(vertex);
142 }
143 
145 {
146  unsigned int i = 0, j = 0;
147 
148  _triangleOut.clear();
149 
150  unsigned int nb = _vertexInOut.count();
151 
152  if (!nb)
153  {
154  return;
155  }
156 
157  double xmin = NAN, xmax = NAN, ymin = NAN, ymax = NAN, zmin = NAN, zmax = NAN; // compute bounding box
158  xmin = xmax = _vertexInOut.back()._x;
159  ymin = ymax = _vertexInOut.back()._y;
160  zmin = zmax = _vertexInOut.back()._z;
161 
162  // VERTEX DECIMATION
163  for (i = 0; i < nb - 1; i++) // remove multiple vertices and compute bounding box
164  {
165  OPoint3D tmp(0, 0, 0);
166  unsigned int nbSame = 0;
167 
168  _xEcartType++;
169  _yEcartType++;
170  _zEcartType++;
171 
172  for (j = i + 1; j < nb; j++)
173  {
174  _xEcartType += fabs(_vertexInOut[j]._x - _vertexInOut[i]._x);
175  _yEcartType += fabs(_vertexInOut[j]._y - _vertexInOut[i]._y);
176  _zEcartType += fabs(_vertexInOut[j]._z - _vertexInOut[i]._z);
177  if (((fabs(_vertexInOut[j]._x - _vertexInOut[i]._x) < _xdecim) &&
178  (fabs(_vertexInOut[j]._y - _vertexInOut[i]._y) < _ydecim)) ||
179  (fabs(_vertexInOut[j]._z - _vertexInOut[i]._z) < _zdecim))
180  {
181  if (!nbSame)
182  {
183  tmp = _vertexInOut[i];
184  nbSame++;
185  }
186  tmp._x += _vertexInOut[j]._x;
187  tmp._y += _vertexInOut[j]._y;
188  tmp._z += _vertexInOut[j]._z;
189  nbSame++;
190  _vertexInOut[j] = _vertexInOut.back();
191  _vertexInOut.pop_back();
192  j--;
193  nb--;
194  }
195  }
196 
197  _xEcartType = _xEcartType / (nb - i + 1);
198  _yEcartType = _yEcartType / (nb - i + 1);
199  _zEcartType = _zEcartType / (nb - i + 1);
200 
201  if (nbSame)
202  {
203  _vertexInOut[i]._x = tmp._x / nbSame;
204  _vertexInOut[i]._y = tmp._y / nbSame;
205  _vertexInOut[i]._z = tmp._z / nbSame;
206  }
207  if (_vertexInOut[i]._x < xmin)
208  {
209  xmin = _vertexInOut[i]._x;
210  }
211  else if (_vertexInOut[i]._x > xmax)
212  {
213  xmax = _vertexInOut[i]._x;
214  }
215  if (_vertexInOut[i]._y < ymin)
216  {
217  ymin = _vertexInOut[i]._y;
218  }
219  else if (_vertexInOut[i]._y > ymax)
220  {
221  ymax = _vertexInOut[i]._y;
222  }
223  if (_vertexInOut[i]._z < zmin)
224  {
225  zmin = _vertexInOut[i]._z;
226  }
227  else if (_vertexInOut[i]._z > zmax)
228  {
229  zmax = _vertexInOut[i]._z;
230  }
231  }
232  _xEcartType = _xEcartType / nb;
233  _yEcartType = _yEcartType / nb;
234  _zEcartType = _zEcartType / nb;
235 
236  if (_vertexInOut.back()._x < xmin)
237  {
238  xmin = _vertexInOut.back()._x;
239  }
240  else if (_vertexInOut.back()._x > xmax)
241  {
242  xmax = _vertexInOut.back()._x;
243  }
244  if (_vertexInOut.back()._y < ymin)
245  {
246  ymin = _vertexInOut.back()._y;
247  }
248  else if (_vertexInOut.back()._y > ymax)
249  {
250  ymax = _vertexInOut.back()._y;
251  }
252  if (_vertexInOut.back()._z < zmin)
253  {
254  zmin = _vertexInOut.back()._z;
255  }
256  else if (_vertexInOut.back()._z > zmax)
257  {
258  zmax = _vertexInOut.back()._z;
259  }
260  double dx = xmax - xmin;
261  double dy = ymax - ymin;
262  double dz = zmax - zmin;
263 
264  // Save bounding box
265  _dx = dx;
266  _dy = dy;
267  _dz = dz;
268  _xMin = xmin;
269  _xMax = xmax;
270  _yMin = ymin;
271  _yMax = ymax;
272  _zMin = zmin;
273  _zMax = zmax;
274 }
275 
277 {
278  double dx = NAN, dy = NAN, xmin = NAN, xmax = NAN, ymin = NAN, ymax = NAN;
279 
280  int i = 0, j = 0, k = 0;
281  int nb = _vertexInOut.count();
282  if (!nb)
283  {
284  return;
285  }
286 
287  dx = _dx;
288  dy = _dy;
289  xmin = _xMin;
290  xmax = _xMax;
291  ymin = _yMin;
292  ymax = _yMax;
293 
294  bool xMain = (dx >= dy);
295  double dmax = (xMain ? dx : dy);
296  if (dmax < _triangulatePrecision)
297  {
298  return;
299  }
300  double xmid = 0.5 * (xmax + xmin);
301  double ymid = 0.5 * (ymax + ymin);
302  if (xMain)
303  {
304  for (i = 0; i < nb - 1; i++) // sort along x coordinate
305  {
306  k = i;
307  for (j = i + 1; j < nb; j++)
308  {
309  if (_vertexInOut[j]._x < _vertexInOut[k]._x)
310  {
311  k = j;
312  }
313  }
314  if (k != i)
315  {
316  OPoint3D tmp(_vertexInOut[k]);
317  _vertexInOut[k] = _vertexInOut[i];
318  _vertexInOut[i] = tmp;
319  }
320  }
321  }
322 
323  else
324  {
325  for (i = 0; i < nb - 1; i++) // sort along y coordinate
326  {
327  k = i;
328  for (j = i + 1; j < nb; j++)
329  {
330  if (_vertexInOut[j]._y < _vertexInOut[k]._y)
331  {
332  k = j;
333  }
334  }
335  if (k != i)
336  {
337  OPoint3D tmp(_vertexInOut[k]);
338  _vertexInOut[k] = _vertexInOut[i];
339  _vertexInOut[i] = tmp;
340  }
341  }
342  }
343  // add bounding // triangle vertices
344  _vertexInOut.push_back(OPoint3D(xmid - 2.0 * dmax, ymid - dmax, 0.0));
345  _vertexInOut.push_back(OPoint3D(xmid + 2.0 * dmax, ymid - dmax, 0.0));
346  _vertexInOut.push_back(OPoint3D(xmid, ymid + 2.0 * dmax, 0.0));
347 
348  QList<OPoint3D> circle;
349  QList<bool> complete;
350  QList<OTriangle> edge;
351 
352  _triangleOut.push_back(OTriangle(nb, nb + 1, nb + 2)); // add bounding triangle
353  complete.push_back(false);
354  circle.push_back(computeCircle(_vertexInOut[nb], _vertexInOut[nb + 1], _vertexInOut[nb + 2]));
355  for (i = 0; i < nb; i++) // include each vertex
356  {
357  for (j = 0; j < _triangleOut.size(); j++)
358  {
359  if (!complete[j])
360  {
361  if (xMain)
362  {
363  if (circle[j]._x + circle[j]._z < _vertexInOut[i]._x)
364  {
365  complete[j] = true;
366  }
367  }
368  else
369  {
370  if (circle[j]._y + circle[j]._z < _vertexInOut[i]._y)
371  {
372  complete[j] = true;
373  }
374  }
375  double dx = _vertexInOut[i]._x - circle[j]._x;
376  double dy = _vertexInOut[i]._y - circle[j]._y;
377 
378  if (dx * dx + dy * dy <= circle[j]._z * circle[j]._z)
379  {
380  // add edges
381  edge.push_back(OTriangle(_triangleOut[j]._p1, _triangleOut[j]._p2, 1));
382  edge.push_back(OTriangle(_triangleOut[j]._p2, _triangleOut[j]._p3, 1));
383  edge.push_back(OTriangle(_triangleOut[j]._p3, _triangleOut[j]._p1, 1));
384  _triangleOut[j] = _triangleOut.back(); // remove triangle
385  _triangleOut.pop_back();
386  complete[j] = complete.back();
387  complete.pop_back();
388  circle[j] = circle.back();
389  circle.pop_back();
390  j--;
391  }
392  }
393  }
394  for (j = 0; j < edge.size() - 1; j++) // remove multiple edge
395  {
396  for (k = j + 1; k < edge.size(); k++)
397  {
398  if ((edge[j]._p1 == edge[k]._p2) && (edge[j]._p2 == edge[k]._p1))
399  {
400  edge[j]._p3 = edge[k]._p3 = 0;
401  }
402  }
403  }
404  while (edge.size()) // build new triangles with edges
405  {
406  if (edge.back()._p3)
407  {
408  _triangleOut.push_back(OTriangle(edge.back()._p1, edge.back()._p2, i));
409  complete.push_back(false);
410  circle.push_back(computeCircle(_vertexInOut[_triangleOut.back()._p1],
411  _vertexInOut[_triangleOut.back()._p2],
412  _vertexInOut[_triangleOut.back()._p3]));
413  }
414  edge.pop_back();
415  }
416  }
417  for (i = 0; i < _triangleOut.size(); i++) // remove bounding triangle
418  {
419  if ((_triangleOut[i]._p1 >= nb) || (_triangleOut[i]._p2 >= nb) || (_triangleOut[i]._p3 >= nb))
420  {
421  _triangleOut[i] = _triangleOut.back();
422  _triangleOut.pop_back();
423  i--;
424  }
425  }
426  _vertexInOut.pop_back(); // remove bounding triangle vertices
427  _vertexInOut.pop_back();
428  _vertexInOut.pop_back();
429 }
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
bool compute(void)
Compute the triangulation.
QList< OTriangle > _triangleOut
Triangles list.
void getBoundaries(double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Define boundaries.
ODelaunayMaker(double triangulatePrecision)
Constructor.
QList< OTriangle > getFaces(void)
Return faces list.
void decimate(void)
void triangulate(void)
void setDecimation(double xdecim, double ydecim, double zdecim)
Set decimation.
QList< OPoint3D > getVertex(void)
Return the vertexes list.
QList< OPoint3D > _vertexInOut
Vertexes list.
void reinitParameters(void)
Re-initialization all parameters to zero.
double _triangulatePrecision
virtual ~ODelaunayMaker()
Destructor.
OPoint3D computeCircle(const OPoint3D &p1, const OPoint3D &p2, const OPoint3D &p3)
void addVertex(OPoint3D vertex)
Add a vertex.
The 3D point class.
Definition: 3d.h:487
Triangle class.
Definition: triangle.h:28