Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYAcousticModel.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 <deque>
17 #include <list>
18 #include <cmath>
19 #include <algorithm>
20 #include "Tympan/core/defines.h"
26 #include "TYAcousticModel.h"
27 #include "TYSolver.h"
28 #include "TYSolverHelper.h"
29 #include "TYFaceSelector.h"
30 
32  : _useSol(true), _useReflex(false), _propaCond(0), _interference(false), _paramH(10.0), _solver(solver)
33 {
35  _absoNulle.setType(SPECTRE_TYPE_ABSO); // Spectre d'absorption
36 }
37 
39 
41 {
43  // Calcul avec sol reel
44  _useSol = config->UseRealGround;
45  // Calcul avec reflexion sur les parois verticales
46  _useReflex = config->UseReflection;
47  // Calcul en conditions favorables
48  _propaCond = config->PropaConditions;
49  // Definit l'atmosphere courante du site
50  double pression = config->AtmosPressure;
51  double temperature = config->AtmosTemperature;
52  double hygrometrie = config->AtmosHygrometry;
53 
54  pSolverAtmos =
55  std::unique_ptr<AtmosphericConditions>(new AtmosphericConditions(pression, temperature, hygrometrie));
56  // Calcul avec interference
57  _interference = config->ModSummation;
58 
59  // Compute wave length
60  double c_9613_2 = 340.0;
62  // Coefficient multiplicateur pour le calcul des reflexions supplementaires en condition favorable
63  _paramH = config->H1parameter;
64 }
65 
66 void TYAcousticModel::compute(const std::deque<TYSIntersection>& tabIntersect, TYTrajet& trajet,
67  TabPoint3D& ptsTop, TabPoint3D& ptsLeft, TabPoint3D& ptsRight)
68 {
69  bool vertical = true, horizontal = false;
70  bool left = true, right = false;
71 
72  // Construction du rayon SR
73  OSegment3D rayon;
74  trajet.getPtSetPtRfromOSeg3D(rayon);
75  bool conditionFav = false;
76 
77  // Calcul des conditions de propagation suivant la direction du vent
79  assert(config->DSWindDirection >= 0 && config->DSWindDirection <= 360);
80 
81  double windRadian = DEGTORAD(config->DSWindDirection);
82  OVector3D windDirection = OVector3D(-sin(windRadian), -cos(windRadian), 0);
83  OVector3D propaDirection = rayon.toVector3D();
84  propaDirection._z = 0;
85  double angle =
86  RADTODEG(acos(windDirection.dot(propaDirection) /
87  (windDirection.norme() * propaDirection.norme()))); // Angle always between 0-180
88  assert(180 >= angle >= 0);
89  assert(180 >= config->AngleFavorable >= 0);
90 
91  if (angle <= config->AngleFavorable)
92  {
93  conditionFav = true;
94  }
95  else
96  {
97  conditionFav = false;
98  }
99 
100  // Recuperation de la source
101  tympan::AcousticSource& source = trajet.asrc;
102 
103  // Distance de la source au recepteur
104  double distance = trajet.getDistance();
105 
106  TYTabChemin& tabChemins = trajet.getChemins();
107 
108  // Calcul du chemin direct
109  computeCheminSansEcran(tabIntersect, rayon, source, tabChemins, distance, conditionFav);
110 
111  if (ptsTop.size() > 1 || ptsLeft.size() > 1 || ptsRight.size() > 1)
112  {
113  // Calcul des parcours lateraux
114  // 1. Vertical
115  computeCheminsAvecEcran(rayon, source, ptsTop, vertical, tabChemins, distance, right);
116 
117  // 2. Horizontal gauche
118  computeCheminsAvecEcran(rayon, source, ptsLeft, horizontal, tabChemins, distance, left);
119 
120  // 3. Horizontal droite
121  computeCheminsAvecEcran(rayon, source, ptsRight, horizontal, tabChemins, distance, right);
122  }
123 
124  // Calcul des reflexions si necessaire
125  computeCheminReflexion(tabIntersect, rayon, source, tabChemins, distance);
126 
127  // Calcul la pression cumulee de tous les chemins au point de reception du trajet
128  solve(trajet);
129 
130  // Le calcul est fini pour ce trajet, on peut effacer les tableaux des chemins
131  tabChemins.clear();
132 }
133 
135  TYTabChemin& TabChemins, double distance) const
136 {
137  TYTabEtape tabEtapes;
138 
139  // Calcul de la pente moyenne sur le trajet source-recepteur
140  OSegment3D penteMoyenne;
141  meanSlope(rayon, penteMoyenne);
142 
143  // Etape directe Source-Recepteur
144  TYEtape etape1;
145  TYChemin chemin1;
146 
147  etape1._pt = rayon._ptA;
148  etape1._type = TYSOURCE;
149  etape1._Absorption =
150  source.directivity->lwAdjustment(OVector3D(rayon._ptA, rayon._ptB), rayon.longueur());
151 
153 
154  tabEtapes.push_back(etape1); // Ajout de l'etape directe
155  chemin1.setLongueur(distance); // Dans ce cas, la longueur = la distance source/recepteur
156  chemin1.setDistance(distance);
157  chemin1.calcAttenuation(tabEtapes, *pSolverAtmos);
158 
159  TabChemins.push_back(chemin1);
160  tabEtapes.clear(); // Vide le tableau des etapes
161 
162  // Liaison avec reflexion
163  // 1. Calcul du point de reflexion
164 
165  // Ajout du chemin reflechi
166  TYEtape etape2;
167  TYChemin chemin2;
169 
170  etape2.setPoint(rayon._ptA);
171  etape2._type = TYSOURCE;
172 
173  OPoint3D ptSym;
174  int symOK = 0;
175  if (penteMoyenne.longueur() > 0) // Si la pente moyenne est definie, on prend le point symetrique
176  {
177  symOK = penteMoyenne.symetrieOf(rayon._ptA, ptSym);
178  }
179 
180  if (symOK == 0) // Sinon on prend une simple symetrie par rapport a z
181  {
182  ptSym = rayon._ptA;
183  ptSym._z = 2 * penteMoyenne._ptA._z - ptSym._z;
184  }
185 
186  // Calcul du point de reflexion
187  OPoint3D ptReflex;
188  penteMoyenne.intersects(OSegment3D(ptSym, rayon._ptB), ptReflex, TYSEUILCONFONDUS);
189 
190  // 2. Etape avant la reflexion
191  OSegment3D seg1(rayon._ptA, ptReflex); // On part de la source vers le point de reflexion
192  double rr = seg1.longueur();
193 
194  // Directivite de la source
195  etape2._Absorption = source.directivity->lwAdjustment(OVector3D(seg1._ptA, seg1._ptB), seg1.longueur());
196 
197  tabEtapes.push_back(etape2); // Ajout de l'etape avant reflexion
198 
199  // 3. Etape apres la reflexion
200 
201  TYEtape etape3;
202  etape3._pt = ptReflex;
203  etape3._type = TYREFLEXIONSOL;
204 
205  OSegment3D seg2 = OSegment3D(ptReflex, rayon._ptB); // Segment Point de reflexion->Point de reception
206  rr += seg2.longueur(); // Longueur parcourue sur le trajet reflechi
207 
208  if (_useSol)
209  {
210  etape3._Absorption = getReflexionSpectrumAt(seg1, rr, penteMoyenne, source);
211  }
212  else // Sol totalement reflechissant
213  {
214  etape3._Absorption = _absoNulle;
215  }
216 
217  tabEtapes.push_back(etape3); // Ajout de l'etape apres reflexion
218 
219  chemin2.setLongueur(rr);
220  chemin2.setDistance(distance);
221  chemin2.calcAttenuation(tabEtapes, *pSolverAtmos);
222  TabChemins.push_back(chemin2);
223 
224  tabEtapes.clear(); // Vide le tableau des etapes
225 }
226 
228  const TabPoint3D& pts, const bool vertical,
229  TYTabChemin& tabPaths, double distance, const bool left) const
230 {
231  /* ============================================================================================================
232  In 9613, no reflexion on the ground is computed
233  ==============================================================================================================*/
234  if (pts.size() <= 1)
235  {
236  tabPaths[0].setAttenuationBarWhenNoPath(vertical, left);
237  return false;
238  }
239 
240  double dss{0.0}; // Length between source and first edge of diffraction
241  double dsr{0.0}; // Length between last edge of diffraction and receptor
242 
243  OPoint3D firstPt(pts[1]);
244  OPoint3D lastPt(pts[pts.size() - 1]);
245 
246  TYTabEtape tabSteps;
247  double pathLength = 0.0;
248 
249  /*--- BEFORE OBSTACLE ---*/
250 
251  TYTabEtape steps;
252  OSegment3D curSegment(ray._ptA, firstPt);
253  double tempLength = curSegment.longueur();
254 
255  bool bPathOk = addStep(ray._ptA, firstPt, source, true, steps); // Add step before obstacle
256 
257  // If a problem has occurred, stop path creation
258  if (!bPathOk)
259  {
260  return true;
261  }
262 
263  tabSteps.push_back(steps[0]); // Add source step to table of steps
264  pathLength += tempLength;
265  dss = tempLength;
266 
267  steps.clear(); // Clear steps content
268 
269  /*--- BYPASS OF THE OBSTACLE ---*/
270 
271  double width = 0.0;
272  TYEtape step;
273 
274  for (unsigned int i = 1; i < pts.size() - 1; i++)
275  {
276  width += (OSegment3D(pts[i], pts[i + 1])).longueur();
277 
278  step._pt = pts[i];
279  step._type = TYDIFFRACTION;
280  step._Absorption = _absoNulle;
281 
282  tabSteps.push_back(step);
283  }
284 
285  pathLength += width;
286 
287  /*--- AFTER OBSTACLE ---*/
288  curSegment = OSegment3D(lastPt, ray._ptB);
289  tempLength = curSegment.longueur();
290 
291  addStep(lastPt, ray._ptB, source, false, steps);
292 
293  tabSteps.push_back(steps[0]);
294  pathLength += tempLength;
295  dsr = tempLength;
296 
297  steps.clear();
298 
299  /*--- COMPUTE SCREEN EFFECT ATTENUATION ON THE CURRENT PATH ---*/
300 
301  OSpectreOctave Dz;
302 
303  step._pt = ray._ptB;
304  step._Absorption = _absoNulle;
305 
306  Dz = calculAttDiffraction(ray, pathLength, dss, dsr, width, vertical);
307  step._Attenuation = Dz;
308  tabSteps.push_back(step);
309 
310  /*--- ADD PATH TO the table of paths ---*/
311 
312  TYChemin path;
314  path.setDistance(distance);
315  path.setLongueur(pathLength);
316 
317  tabPaths.push_back(path);
318 
319  // Compute barrier attenuation
320  tabPaths[0].computeBarAttenuation(Dz, vertical, left);
321 
322  // Build equivalent path for rays
323  path.build_eq_path(tabSteps);
324 
325  tabSteps.clear();
326  steps.clear();
327 
328  return true;
329 }
330 
331 bool TYAcousticModel::addStep(const OPoint3D& ptStart, const OPoint3D& ptEnd,
332  const tympan::AcousticSource& source, const bool& fromSource,
333  TYTabEtape& steps) const
334 {
335  bool res = true;
336 
337  TYEtape curStep;
338 
339  // === BUILD DIRECT TRIP ptStart-ptEnd
340  curStep._pt = ptStart;
341 
342  if (fromSource) // If we start from source, its directivity is considered
343  {
344  curStep._type = TYSOURCE;
345  curStep._Absorption =
346  source.directivity->lwAdjustment(OVector3D(ptStart, ptEnd), ptStart.distFrom(ptEnd));
347  }
348  else
349  {
350  curStep._type = TYDIFFRACTION;
351  curStep._Absorption = _absoNulle;
352  }
353 
354  steps.push_back(curStep);
355 
356  return res;
357 }
358 
359 void TYAcousticModel::computeCheminSansEcran(const std::deque<TYSIntersection>& tabIntersect,
360  const OSegment3D& ray, const tympan::AcousticSource& source,
361  TYTabChemin& TabChemin, double distance, bool conditionFav) const
362 {
363  /*
364  COMPUTATION FOR A ROUTE WITHOUT OBSTACLE CONSISTS OF ONE DIRECT PATH
365  */
366  TYTabEtape tabEtapes;
367 
368  // Compute mean slope on source-receptor route
369  OSegment3D segMeanSlope;
370  meanSlope(ray, segMeanSlope);
371 
372  OPoint3D S2D{ray._ptA._x, ray._ptA._y, 0.0};
373  OPoint3D R2D{ray._ptB._x, ray._ptB._y, 0.0};
374  OSegment3D SR2D{S2D, R2D};
375  double dp = SR2D.longueur();
376 
377  TYTabEtape Etapes;
378  double Gs{0.0}, Gm{0.0}, Gr{0.0};
379  double hs{0.0}, hr{0.0};
380 
381  computeSegmentEdgesHeights(hs, hr, segMeanSlope, ray);
382 
383  addStep(ray._ptA, ray._ptB, source, true, Etapes);
384  getGroundfactors(tabIntersect, SR2D, hs, hr, Gs, Gm, Gr);
385 
386  // Add direct path
387  TYChemin chemin;
389  tabEtapes.push_back(Etapes[0]); // Add direct step
390  chemin.setLongueur(distance); // In this case, lenght = source/receptor distance
391  chemin.setDistance(distance);
392  chemin.calcAttenuation(tabEtapes, *pSolverAtmos, dp, hs, hr, Gs, Gm, Gr);
393  TabChemin.push_back(chemin); // Add path in array of paths
394 
395  tabEtapes.clear(); // Empty array of steps
396 }
397 
398 bool TYAcousticModel::getGroundfactors(const std::deque<TYSIntersection>& tabIntersect,
399  const OSegment3D& ray2D, double hs, double hr, double& Gs, double& Gm,
400  double& Gr) const
401 {
402  double heightRatio = 30.0;
403 
404  bool res = true;
405 
406  // === CONSTRUCTION OF DIRECT ROUTE ABOVE HORIZONTAL PLANE
407  OPoint3D ptStartProj = ray2D._ptA; // PtDebut projected on horizontal plane
408  OPoint3D ptEndProj = ray2D._ptB; // PtFin projected on horizontal plane
409 
410  // === COMPUTE SOURCE, MIDDLE AND RECEPTOR ZONES
411  OVector3D SR{ray2D._ptA, ray2D._ptB};
412  double dp = SR.norme(); // Distance in meter, between source and receptor, projected on ground plan
413  SR.normalize();
414  OPoint3D ptGSrcZone;
415  OPoint3D ptGRcpZone;
416  OPoint3D ptGMidZone;
417 
418  // Source zone must not exceed receptor
419  if (heightRatio * hs < dp)
420  {
421  ptGSrcZone = ptStartProj + SR * heightRatio * hs;
422  }
423  else
424  {
425  ptGSrcZone = ptStartProj + SR * dp;
426  }
427 
428  // Receptor zone must not exceed source
429  if (heightRatio * hr < dp)
430  {
431  ptGRcpZone = ptEndProj + (-1.0) * SR * heightRatio * hr;
432  }
433  else
434  {
435  ptGRcpZone = ptEndProj + (-1.0) * SR * dp;
436  }
437 
438  // === COMPUTE GROUND FACTOR FOR EACH ZONE
439  double GZone{0.0}, dpZone{0.0};
440  computeGZone(ptStartProj, ptGSrcZone, GZone, dpZone, tabIntersect);
441  if (dpZone != 0.0)
442  {
443  Gs = GZone / dpZone;
444  }
445  else
446  {
447  Gs = 0.5;
448  }
449  computeGZone(ptGRcpZone, ptEndProj, GZone, dpZone, tabIntersect);
450  if (dpZone != 0.0)
451  {
452  Gr = GZone / dpZone;
453  }
454  else
455  {
456  Gr = 0.5;
457  }
458  computeGZone(ptGSrcZone, ptGRcpZone, GZone, dpZone, tabIntersect);
459  if (dpZone != 0.0)
460  {
461  Gm = GZone / dpZone;
462  }
463  else
464  {
465  Gm = 0.5;
466  }
467 
468  return res;
469 }
470 
471 bool TYAcousticModel::getGroundfactors(const std::deque<TYSIntersection>& tabIntersectUpSegment,
472  const std::deque<TYSIntersection>& tabIntersectDownSegment,
473  const OSegment3D& SO2D, const OSegment3D& OR2D, double hs, double hr,
474  double& Gs, double& Gm, double& Gr) const
475 {
476  double heightRatio = 30.0;
477  bool res = true;
478 
479  // Construction of points from segments parameters
480  OPoint3D ptSrc2D = SO2D._ptA;
481  OPoint3D ptO2D = SO2D._ptB;
482  OPoint3D ptRcp2D = OR2D._ptB;
483 
484  // Computation of 2D distance and construction of unit vectors
485  OVector3D SO{SO2D._ptA, SO2D._ptB};
486  double dpSO =
487  SO.norme(); // Distance in meter, between source and reflexion point, projected on ground plan
488  SO.normalize();
489 
490  OVector3D OR{OR2D._ptA, OR2D._ptB};
491  double dpOR =
492  OR.norme(); // Distance in meter, between reflexion point and receptor, projected on ground plan
493  OR.normalize();
494 
495  double dp = dpSO + dpOR; // Distance in meter, between source and receptor, projected on ground plan
496 
497  // === COMPUTE GROUND FACTOR FOR EACH ZONE
498  OPoint3D ptGSrcZone;
499  OPoint3D ptGRcpZone;
500  OPoint3D ptGMidZone;
501 
502  bool bPtGSrcZoneInSO{false}; // True if ptGSrcZone in [SO] segment
503  bool bPtGRcpZoneInOR{false}; // True if ptGRcpZone in [OR] segment
504 
505  // == COMPUTE GROUND FACTOR FOR SOURCE ZONE
506  if (heightRatio * hs < dpSO)
507  {
508  // ptGSrcZone belongs to [SO]
509  bPtGSrcZoneInSO = true;
510  ptGSrcZone = ptSrc2D + (SO)*heightRatio * hs;
511  }
512  else if (heightRatio * hs < dp)
513  {
514  // ptGSrcZone belongs to [OR]
515  ptGSrcZone = ptO2D + (OR) * (heightRatio * hs - dpSO);
516  }
517  else
518  { // Source Zone must not exceed receptor
519  ptGSrcZone = ptO2D + (OR)*dpOR;
520  }
521 
522  // Compute Gs
523  double GZone{0.0}, dpZone{0.0};
524  if (bPtGSrcZoneInSO)
525  {
526  computeGZone(ptSrc2D, ptGSrcZone, GZone, dpZone, tabIntersectUpSegment);
527  }
528  else
529  {
530  double Gs1{0.0}, dp1{0.0}, Gs2{0.0}, dpOGs{0.0};
531  computeGZone(ptSrc2D, ptO2D, Gs1, dp1, tabIntersectUpSegment); // Gs1 = G(Src2D->ptO2D) / dpSO
532  computeGZone(ptO2D, ptGSrcZone, Gs2, dpOGs, tabIntersectDownSegment); // Gs2 = G(ptO2D->Gs2D) / dpOGs
533  GZone = Gs1 + Gs2;
534  dpZone = dp1 + dpOGs;
535  }
536 
537  if (dpZone != 0)
538  {
539  Gs = GZone / dpZone;
540  }
541  else
542  {
543  Gs = 0.5;
544  }
545 
546  // == COMPUTE GROUND FACTOR FOR RECEPTOR ZONE
547  if (heightRatio * hr < dpOR)
548  {
549  // ptGRcpZone belongs to [OR]
550  bPtGRcpZoneInOR = true;
551  ptGRcpZone = ptRcp2D + (-1.0) * OR * heightRatio * hr;
552  }
553  else if (heightRatio * hr < dp)
554  {
555  // ptGSrcZone belongs to [SO]
556  ptGRcpZone = ptO2D + (-1.0) * SO * (heightRatio * hr - dpOR);
557  }
558  else
559  { // Source Zone must not exceed receptor
560  ptGRcpZone = ptO2D + (-1.0) * SO * dpSO;
561  }
562 
563  // Compute Gr
564  dpZone = 0.0;
565  if (bPtGRcpZoneInOR)
566  {
567  computeGZone(ptGRcpZone, ptRcp2D, GZone, dpZone, tabIntersectDownSegment);
568  }
569  else
570  {
571  double Gr1{0.0}, dp2{0.0}, Gr2{0.0}, dpGrO{0.0};
572  computeGZone(ptGRcpZone, ptO2D, Gr1, dpGrO, tabIntersectUpSegment); // Gr1 = G(Gr2D->ptO2D) / dpGrO
573  computeGZone(ptO2D, ptRcp2D, Gr2, dp2, tabIntersectDownSegment); // Gr2 = G(ptO2D->ptRcp2D) / dpOR
574 
575  GZone = Gr1 + Gr2;
576  dpZone = dpGrO + dp2;
577  }
578 
579  if (dpZone != 0)
580  {
581  Gr = GZone / dpZone;
582  }
583  else
584  {
585  Gr = 0.5;
586  }
587 
588  // == COMPUTE GROUND FACTOR FOR MIDDLE ZONE
589  // If GSrc and GRcp belong to [SO]
590  if (bPtGSrcZoneInSO && !bPtGRcpZoneInOR)
591  {
592  computeGZone(ptGSrcZone, ptGRcpZone, GZone, dpZone, tabIntersectUpSegment);
593  }
594  // Else, if GSrc and GRcp belong to [OR]
595  else if (!bPtGSrcZoneInSO && bPtGRcpZoneInOR)
596  {
597  computeGZone(ptGSrcZone, ptGRcpZone, GZone, dpZone, tabIntersectDownSegment);
598  }
599  // Else, if GSrc belongs to [SO], therefore GRcp belongs to [OR]
600  else if (bPtGSrcZoneInSO)
601  {
602  double Gm1{0.0}, dpm1{0.0}, Gm2{0.0}, dpm2{0.0};
603  computeGZone(ptGSrcZone, ptO2D, Gm1, dpm1, tabIntersectUpSegment);
604  computeGZone(ptO2D, ptGRcpZone, Gm2, dpm2, tabIntersectDownSegment);
605  GZone = Gm1 + Gm2;
606  dpZone = dpm1 + dpm2;
607  }
608  // Else if GSrc belongs to [OR], therefore GRcp belongs to [SO]
609  else
610  {
611  double Gm1{0.0}, dpm1{0.0}, Gm2{0.0}, dpm2{0.0};
612  computeGZone(ptGRcpZone, ptO2D, Gm1, dpm1, tabIntersectUpSegment);
613  computeGZone(ptO2D, ptGSrcZone, Gm2, dpm2, tabIntersectDownSegment);
614  GZone = Gm1 + Gm2;
615  dpZone = dpm1 + dpm2;
616  }
617 
618  if (dpZone != 0)
619  {
620  Gm = GZone / dpZone;
621  }
622  else
623  {
624  Gm = 0.5;
625  }
626 
627  return res;
628 }
629 
631  const OSpectreOctave& Abar_left,
632  const OSpectreOctave& Abar_right)
633 {
634  OSpectreOctave Abar;
635  for (unsigned int i = 0; i < TY_SPECTRE_OCT_NB_ELMT; i++)
636  {
637  Abar.getTabValReel()[i] = -10 * log10(pow(10, -0.1 * Abar_top.getTabValReel()[i]) +
638  pow(10, -0.1 * Abar_left.getTabValReel()[i]) +
639  pow(10, -0.1 * Abar_right.getTabValReel()[i]));
640  if (Abar.getTabValReel()[i] < 0)
641  {
642  Abar.getTabValReel()[i] = 0;
643  }
644  }
645  return Abar;
646 }
647 
649 {
650  OPoint3D pt1{penteMoyenne._ptA};
651  OPoint3D pt2{penteMoyenne._ptB};
652  OPoint3D pt3{};
653  pt3._z = pt1._z;
654 
655  if (pt2._x != pt1._x)
656  {
657  pt3._y = pt1._y + 1;
658  pt3._x = (pt1._y - pt2._y) * (pt3._y - pt1._y) / (pt2._x - pt1._x) + (pt1._x);
659  }
660  else
661  {
662  if (pt1._y != pt2._y)
663  {
664  pt3._x = pt1._x + 1;
665  pt3._y = (pt2._x - pt1._x) * (pt3._x - pt1._x) / (pt1._y - pt2._y) + (pt1._y);
666  }
667  else // pt1 and pt2 coincide, we shift pt2, building an horizontal plane
668  {
669  pt2._x = pt1._x + 1;
670  pt2._y = pt1._y - 1;
671  pt3._y = pt1._y + 1;
672  pt3._x = (pt1._y - pt2._y) * (pt3._y - pt1._y) / (pt2._x - pt1._x) + (pt1._x);
673  }
674  }
675 
676  return OPlan{pt1, pt2, pt3};
677 }
678 
679 bool TYAcousticModel::computeGZone(const OPoint3D& ptDebut, const OPoint3D& ptFin, double& GZone,
680  double& dpZone, const std::deque<TYSIntersection>& tabIntersect) const
681 {
682  bool ret = true;
683  OSegment3D segZone(ptDebut, ptFin);
684  OVector3D DF(ptDebut, ptFin);
685 
686  // Loop on intersections of Topography triangles with EV plane.
687  // For each triangle, we search the intersection between the intersecting segment and the zone segment.
688  // The intersecting segment has an homogeneous ground factor G.
689  // It is used to compute a balanced ground factor over the zone segment.
690  size_t nbTriangles = tabIntersect.size();
691  double currentG = 0.0;
692  GZone = 0.0;
693 
694  // Edges of current intersecting segment
695  OPoint3D ptDebutResult;
696  OPoint3D ptFinResult;
697 
698  for (unsigned int i = 0; i < nbTriangles; i++)
699  {
700  TYSIntersection inter = tabIntersect[i];
701 
702  // If triangle is not topography or does not intersect EV plane, then continue with following triangle
703  if ((inter.isInfra) || !(inter.bIntersect[0]))
704  {
705  continue;
706  }
707 
708  OSegment3D currentSeg = tabIntersect[i].segInter[0];
709  currentG = tabIntersect[i].material->get_ISO9613_G();
710 
711  // We build AB segment the projection of the topography segment on the horizontal plane
712  OPoint3D ptDebutCurrentProj{currentSeg._ptA._x, currentSeg._ptA._y, 0.0};
713  OPoint3D ptFinCurrentProj{currentSeg._ptB._x, currentSeg._ptB._y, 0.0};
714 
715  OSegment3D segAB{ptDebutCurrentProj, ptFinCurrentProj};
716  OVector3D AB{ptDebutCurrentProj, ptFinCurrentProj};
717  // Orientate AB segment as zone segment DF
718  if (AB.scalar(DF) <= 0)
719  {
720  segAB = segAB.swap();
721  }
722  OVector3D AD(segAB._ptA, segZone._ptA);
723  OVector3D AF(segAB._ptA, segZone._ptB);
724  OVector3D BD(segAB._ptB, segZone._ptA);
725  OVector3D BF(segAB._ptB, segZone._ptB);
726 
727  bool intersect = true;
728 
729  // If A belongs to zone segment DF
730  if (AD.scalar(AF) <= 0)
731  {
732  // then A is the starting edge of the intersecting segment
733  ptDebutResult = segAB._ptA;
734 
735  // If B belongs to zone segment DF
736  if (BD.scalar(BF) <= 0)
737  {
738  // then B is the ending edge of the intersecting segment
739  ptFinResult = segAB._ptB;
740  }
741  else
742  // else F is the ending edge of the intersecting segment
743  {
744  ptFinResult = segZone._ptB;
745  }
746  }
747  else
748  {
749  // Else A does not belong to zone segment DF
750  // If B does not belong to zone segment either
751  if (BD.scalar(BF) >= 0)
752  {
753  // and if A and B are from each side of zone segment
754  if (AD.scalar(BF) <= 0)
755  {
756  // then intersecting segment is the zone segment DF itself
757  ptDebutResult = segZone._ptA;
758  ptFinResult = segZone._ptB;
759  }
760  else
761  {
762  // Else A and B are on the same side of segment zone, so no intersection
763  intersect = false;
764  }
765  }
766  else
767  // Else B belong to segment zone DF but not A
768  {
769  ptDebutResult = segZone._ptA;
770  ptFinResult = segAB._ptB;
771  }
772  }
773 
774  if (intersect)
775  {
776  OVector3D result{ptDebutResult, ptFinResult};
777  GZone = GZone + result.norme() * currentG;
778  }
779  }
780  OVector3D zone{ptDebut, ptFin};
781  dpZone = zone.norme();
782  return ret;
783 }
784 
785 void TYAcousticModel::computeCheminReflexion(const std::deque<TYSIntersection>& tabIntersect,
786  const OSegment3D& ray, const tympan::AcousticSource& source,
787  TYTabChemin& TabChemins, double distance) const
788 {
789  if (!_useReflex)
790  {
791  return;
792  }
793 
794  OSegment3D segInter;
795  OSegment3D rayonTmp;
796  OPoint3D ptSym;
797  OSpectreOctave SpectreAbso;
798 
799  OSegment3D seg; // Image source -> receptor segment
800  OSegment3D upwardSeg; // Source -> reflexion point segment
801  OSegment3D downwardSeg; // Reflexion point -> receptor segment
802 
803  OPoint3D pt; // Intersection (reflexion) point
804 
805  size_t nbFaces = tabIntersect.size();
806 
807  // For each face test reflexion
808  for (unsigned int i = 0; i < nbFaces; i++)
809  {
810  TYSIntersection inter = tabIntersect[i];
811 
812  // If face cannot interact skip it
813  if ((!inter.isInfra) || !(inter.bIntersect[1]))
814  {
815  continue;
816  }
817 
818  segInter = inter.segInter[1];
819 
820  // Compute symmetric of A with respect to the segment
821  segInter.symetrieOf(ray._ptA, ptSym); // We don't deal with this function return value
822  seg._ptA = ptSym;
823  seg._ptB = ray._ptB; // Image source -> receptor segment
824 
825  if (segInter.intersects(seg, pt, TYSEUILCONFONDUS))
826  {
827  // Construction of reflexion point -> source segment
828  upwardSeg._ptA = ray._ptA;
829  upwardSeg._ptB = pt;
830  // Construction of reflexion point -> receptor segment
831  downwardSeg._ptA = upwardSeg._ptB;
832  downwardSeg._ptB = ray._ptB;
833 
834  bool intersect = false;
835  size_t j = 0;
836 
837  // If we cross another face, which can be topography, the reflexion path is not taken into account
838  while ((j < nbFaces) && (!intersect))
839  {
840  if (j == i)
841  {
842  j++;
843  continue; // If face cannot interact skip it
844  }
845 
846  segInter = tabIntersect[j].segInter[1];
847 
848  // We test whether segInter intersects upward segment or
849  // downward segment in global plane.
850  // Point pt is not use, we only care about testing intersection
851  if ((segInter.intersects(upwardSeg, pt, TYSEUILCONFONDUS)) ||
852  (segInter.intersects(downwardSeg, pt, TYSEUILCONFONDUS)))
853  {
854  // Intersection found, exit from the loop
855  intersect = true;
856  break;
857  }
858 
859  j++;
860  }
861 
862  // If reflected path is not intersected, reflexion can be computed
863  if (!intersect)
864  {
865  SpectreAbso = dynamic_cast<tympan::AcousticBuildingMaterial*>(inter.material)->spectrum;
866 
867  TYTabEtape tabEtapes;
868 
869  double pathLength = upwardSeg.longueur() + downwardSeg.longueur();
870 
871  TYEtape Etape;
872  // First step : from source to reflexion point
873  Etape._pt = ray._ptA;
874  Etape._type = TYSOURCE;
875  Etape._Absorption = source.directivity->lwAdjustment(
876  OVector3D(upwardSeg._ptA, upwardSeg._ptB),
877  upwardSeg.longueur()); // Directivity factor toward receptor image
878 
879  tabEtapes.push_back(Etape);
880 
881  // Second step : from reflexion point to end of ray
882  Etape._pt = downwardSeg._ptA;
883  Etape._type = TYREFLEXION;
884  Etape._Absorption = SpectreAbso;
885 
886  tabEtapes.push_back(Etape);
887 
888  // Compute mean slope on source-receptor route
889  OSegment3D segMeanSlope;
890  meanSlope(ray, segMeanSlope);
891 
892  OPoint3D S2D{upwardSeg._ptA._x, upwardSeg._ptA._y, 0.0};
893  OPoint3D O2D{upwardSeg._ptB._x, upwardSeg._ptB._y, 0.0};
894  OPoint3D R2D{downwardSeg._ptB._x, downwardSeg._ptB._y, 0.0};
895  OSegment3D raySO{S2D, O2D};
896  OSegment3D rayOR{O2D, R2D};
897  double dp = raySO.longueur() + rayOR.longueur();
898 
899  TYTabEtape Etapes;
900  double Gs{0.0}, Gm{0.0}, Gr{0.0};
901  double hs{0.0}, hr{0.0};
902 
903  computeSegmentEdgesHeights(hs, hr, segMeanSlope, ray);
904 
905  // Compute intersecting segments for reflected ray
906  std::deque<TYSIntersection> tabIntersectUpSegment, tabIntersectDownSegment;
907  _solver.getFaceSelector()->selectFaces(tabIntersectUpSegment, upwardSeg, source.volume_id);
908  _solver.getFaceSelector()->selectFaces(tabIntersectDownSegment, downwardSeg,
909  source.volume_id);
910 
911  // Compute ground factors for reflected ray
912  getGroundfactors(tabIntersectUpSegment, tabIntersectDownSegment, raySO, rayOR, hs, hr, Gs, Gm,
913  Gr);
914 
915  TYChemin Chemin;
917  Chemin.setLongueur(pathLength);
918  Chemin.setDistance(distance);
919  Chemin.calcAttenuation(tabEtapes, *pSolverAtmos, dp, hs, hr, Gs, Gm, Gr);
920 
921  TabChemins.push_back(Chemin); // Put the reflected path in paths table
922  tabEtapes.clear();
923  }
924  }
925  }
926 }
927 
928 OSpectreOctave TYAcousticModel::calculC3(const double& width) const
929 {
930  // C3 = (1 + (5 * lambda / width)^2) / (1 / 3 + (5 * lambda / width)^2)
931 
933  OSpectreOctave opLambda;
934 
935  if (width < 0.5)
936  {
937  C3.setDefaultValue(1.0);
938  }
939  else
940  {
941  const double oneThird = 1.0 / 3.0;
942 
943  opLambda = _lambda * (5.0 / width); // (5*lambda/e)
944  opLambda = opLambda * opLambda; // (5*lambda/e)^2
945 
946  C3 = opLambda + 1.0; // 1 + (5*lambda/e)^2
947  C3 = C3.div(opLambda + oneThird); // (1 + (5*lambda/e)^2) / (1/3 + (5*lambda/e)^2)
948  }
949 
950  C3.setType(SPECTRE_TYPE_AUTRE); // Neither Attenuation, nor Absorption
951 
952  return C3;
953 }
954 
956  const double& dss, const double& dsr,
957  const double& width, const bool& vertical) const
958 {
959  double rd;
960 
961  OSpectreOctave s, Dz;
962 
963  OSpectreOctave C3 = calculC3(width); // Corrective factor linked with screen width
964 
965  double C2{20.0};
966 
967  rd = ray.longueur();
968 
969  double z = re - rd; // Path-length difference
970  z = z <= 0 ? 0.0 : z;
971 
972  double Kmeteo = 1.0;
973  if (z > 0.0 && vertical)
974  {
975  Kmeteo = exp(-(1.0 / 2000.0) * sqrt(dss * dsr * rd / (2 * z)));
976  }
977 
978  // Attenuation brought by diffraction Dz = 10 * log [3 + (C2 / lambda) * C3 * delta * Kmeteo] dB
979 
980  s = _lambda.invMult(C2 * z); // =C2*z/lambda
981  s = s * C3 * Kmeteo; // C2*z*C3*Kmeteo/lambda
982  s = s + 3.0;
983  Dz = s.log() * 10.0;
984  // If diffraction occurs in vertical plane (horizontal edge)
985  // minimal and amaximal attenuations are limited respectively
986  // to 0 dB and 20 or 25 dB (whether screen is thin or wide).
987  if (vertical)
988  {
989  Dz = limAttDiffraction(Dz, C3);
990  }
991 
992  return Dz;
993 }
994 
996 {
998 
999  double lim20dB = 20.0;
1000  double lim25dB = 25.0;
1001  double lim0dB = 0.0;
1002 
1003  double valeur;
1004 
1005  for (unsigned int i = 0; i < sNC.getNbValues(); i++)
1006  {
1007  valeur = sNC.getTabValReel()[i];
1008 
1009  valeur = valeur < lim0dB ? lim0dB : valeur; // L'attenuation ne peut etre inferieure a 0 dB
1010 
1011  if ((C.getTabValReel()[i] - 1) <= 1e-2) // Comportement ecran mince
1012  {
1013  valeur = valeur > lim20dB ? lim20dB : valeur;
1014  }
1015  else // Comportement ecran epais ou multiple
1016  {
1017  valeur = valeur > lim25dB ? lim25dB : valeur;
1018  }
1019 
1020  s.getTabValReel()[i] = valeur;
1021  }
1022 
1023  return s;
1024 }
1025 
1027 {
1028  // Get results for each path
1029 #ifdef _DEBUG
1030  std::vector<PathResults> pathsResults;
1031 #endif
1032  PathResults currentPathResults;
1033  // Global sound level pressure
1034  OSpectreOctave& SLp = trajet.getSpectreOct();
1035  SLp.setType(SPECTRE_TYPE_LP); // Receptor spectrum is a pressure spectrum
1036 
1037  for (unsigned int i = 0; i < trajet.getNbChemins(); i++)
1038  {
1039  currentPathResults.path_id = i;
1040  currentPathResults.pathType = trajet.getChemin(i).getType();
1041  double longueur = trajet.getChemin(i).getLongueur();
1042 
1043  // Screen and ground paths results are held by direct path
1044  if (currentPathResults.pathType == TYTypeChemin::CHEMIN_ECRAN ||
1045  currentPathResults.pathType == TYTypeChemin::CHEMIN_SOL)
1046  {
1047  continue;
1048  }
1049  // Direct Ray computations
1051 
1052  // Compute attenuations
1053  currentPathResults.Adiv = OSpectreOctave(20.0 * log10(longueur) + 11.0);
1054  currentPathResults.Aatm = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::ATTENUATION_ATM);
1055  currentPathResults.Agr_s = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::ATTENUATION_GND_S);
1056  currentPathResults.Agr_r = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::ATTENUATION_GND_R);
1057  currentPathResults.Agr_m = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::ATTENUATION_GND_M);
1058  currentPathResults.Dz_top = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::DZ_TOP);
1059  currentPathResults.Dz_left = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::DZ_LEFT);
1060  currentPathResults.Dz_right = trajet.getChemin(i).getAttenuation(TYTypeAttenuation::DZ_RIGHT);
1061  currentPathResults.Abar_top =
1063  currentPathResults.Abar_left =
1065  currentPathResults.Abar_right =
1067  currentPathResults.Abar = computeEffectiveBarAttenuation(
1068  currentPathResults.Abar_top, currentPathResults.Abar_left, currentPathResults.Abar_right);
1069 
1070  currentPathResults.A = currentPathResults.Adiv + currentPathResults.Aatm + currentPathResults.Agr_s +
1071  currentPathResults.Agr_r + currentPathResults.Agr_m + currentPathResults.Abar;
1072 
1073  // Get source power level and source directivity LW + DC
1074  currentPathResults.LW = OSpectreOctave(trajet.asrc.spectrum).round(); // Round spectrum to 2 digits
1075  // for compliance with ISO
1076  // TR 17534-3 values
1077 
1078  // Get source directivity correction
1079  currentPathResults.Dc =
1081 
1082  // If path is reflected one, then compute LW_image
1083  if (currentPathResults.pathType == TYTypeChemin::CHEMIN_REFLEX)
1084  {
1085  currentPathResults.LW =
1086  currentPathResults.LW +
1088  }
1089  currentPathResults.L = currentPathResults.LW + currentPathResults.Dc - currentPathResults.A;
1090  currentPathResults.L.setType(SPECTRE_TYPE_LP); // L is a pressure spectrum
1091  SLp = SLp.sumdB(currentPathResults.L);
1092 
1093 #ifdef _DEBUG
1094  pathsResults.push_back(currentPathResults);
1095 #endif
1096  }
1097 
1098  // Trace results
1099  // TODO Remove trace or keep it only in Debug
1100 #ifdef _DEBUG
1102  pathsResults, SLp,
1103  *pSolverAtmos); // Export results in a csv file for comparison with 17534-3 standard
1104 #endif
1105 
1106  trajet.build_tab_rays();
1107  trajet.reset(); // Erase paths array to (try to) spare memory
1108  return true;
1109 }
1110 
1112  const OSegment3D& segPente,
1113  const tympan::AcousticSource& source) const
1114 {
1115  OSpectreOctave spectre;
1116 
1117  // Search for material at reflexion point
1118  // Set position of ray at the same high as the source
1119  vec3 start = OPoint3Dtovec3(incident._ptB);
1120  start.z = (decimal)incident._ptA._z;
1121  Ray ray1(start, vec3(0., 0., -1.));
1122  ray1.setMaxt(20000);
1123 
1124  std::list<Intersection> LI;
1125 
1126  static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray1, LI));
1127 
1128  if (LI.empty())
1129  {
1130  start.z = (decimal)(incident._ptB._z + 1000);
1131  Ray ray1(start, vec3(0., 0., -1.));
1132  ray1.setMaxt(20000);
1133  static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray1, LI));
1134  }
1135 
1136  assert(!LI.empty());
1137  unsigned int indexFace = LI.begin()->p->getPrimitiveId();
1138  tympan::AcousticMaterialBase* mat = _solver.getTabPolygon()[indexFace].material;
1139 
1140  // Avoid cases where the reflexion point is below a "floating" volumic source
1141  while (_solver.getTabPolygon()[indexFace].is_infra() &&
1142  source.volume_id == _solver.getTabPolygon()[indexFace].volume_id)
1143  {
1144  start.z = (decimal)min(min(_solver.getTabPolygon()[indexFace].tabPoint[0]._z,
1145  _solver.getTabPolygon()[indexFace].tabPoint[1]._z),
1146  _solver.getTabPolygon()[indexFace].tabPoint[2]._z);
1147  Ray ray(start, vec3(0, 0, -1));
1148  ray.setMaxt(20000);
1149  std::list<Intersection> LI2;
1150  static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray, LI2));
1151  // assert( !LI2.empty() );
1152  if (LI2.empty())
1153  break;
1154  indexFace = LI2.begin()->p->getPrimitiveId();
1155  mat = _solver.getTabPolygon()[indexFace].material;
1156  }
1157 
1158  // Angle estimation
1159  OVector3D direction(incident._ptA, incident._ptB);
1160  direction.normalize();
1161 
1162  // This is kept commented for the time being, even though it's the best solution
1163  // double angle = ( direction * -1 ).angle( _solver.getTabPolygon()[indexFace].normal );
1164  // angle = ABS(M_PI/2. - angle);
1165  double angle = (direction * -1).angle(OVector3D(incident._ptB, segPente._ptA));
1166  // Compute reflexion spectrum
1167  spectre = mat->get_absorption(angle, length);
1168 
1169  return spectre;
1170 }
1171 
1172 void TYAcousticModel::meanSlope(const OSegment3D& director, OSegment3D& slope) const
1173 {
1174  // Search for primitives under the two segment extremities
1175 
1176  // To begin : initialize slope
1177  slope = director;
1178 
1179  // first one
1180  OPoint3D pt = director._ptA;
1181  pt._z += 1000.;
1182  vec3 start = OPoint3Dtovec3(pt);
1183  Ray ray1(start, vec3(0., 0., -1.));
1184 
1185  std::list<Intersection> LI;
1186 
1187  double distance1 = static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray1, LI));
1188  assert(distance1 > 0.);
1189  assert(!LI.empty());
1190 
1191  unsigned int indexFace = LI.begin()->p->getPrimitiveId();
1192 
1193  // Avoid cases where the extremities are above infrastructure elements
1194  while (_solver.getTabPolygon()[indexFace].is_infra())
1195  {
1196  start.z = (decimal)min(min(_solver.getTabPolygon()[indexFace].tabPoint[0]._z,
1197  _solver.getTabPolygon()[indexFace].tabPoint[1]._z),
1198  _solver.getTabPolygon()[indexFace].tabPoint[2]._z);
1199  Ray ray(start, vec3(0, 0, -1));
1200  ray.setMaxt(20000);
1201  std::list<Intersection> LI2;
1202  double distance = static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray, LI2));
1203  // assert(distance > 0.);
1204  if (LI2.empty() || distance < 0.)
1205  break;
1206  distance1 += distance;
1207  indexFace = LI2.begin()->p->getPrimitiveId();
1208  }
1209 
1210  // Second one
1211  LI.clear();
1212  pt = director._ptB;
1213  pt._z += 1000.;
1214  start = OPoint3Dtovec3(pt);
1215  Ray ray2(start, vec3(0., 0., -1.));
1216 
1217  double distance2 = static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray2, LI));
1218  // An error can occur if some elements are outside of the grip (emprise)
1219  assert(distance2 > 0.);
1220  assert(!LI.empty());
1221 
1222  indexFace = LI.begin()->p->getPrimitiveId();
1223 
1224  // Avoid cases where the extremities are above infrastructure elements
1225  while (_solver.getTabPolygon()[indexFace].is_infra())
1226  {
1227  start.z = (decimal)min(min(_solver.getTabPolygon()[indexFace].tabPoint[0]._z,
1228  _solver.getTabPolygon()[indexFace].tabPoint[1]._z),
1229  _solver.getTabPolygon()[indexFace].tabPoint[2]._z);
1230  Ray ray(start, vec3(0, 0, -1));
1231  ray.setMaxt(20000);
1232  std::list<Intersection> LI2;
1233  double distance = static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray, LI2));
1234  // assert(distance > 0.);
1235  if (LI2.empty() || distance < 0.)
1236  break;
1237  distance2 += distance;
1238  indexFace = LI2.begin()->p->getPrimitiveId();
1239  }
1240 
1241  // Compute projection on the ground of segment points suppose sol is under the points ...
1242  slope._ptA._z = director._ptA._z - (distance1 - 1000.);
1243  slope._ptB._z = director._ptB._z - (distance2 - 1000.);
1244 }
1245 
1246 bool TYAcousticModel::computeSegmentEdgesHeights(double& hauteurA, double& hauteurB,
1247  const OSegment3D& meanSlope, const OSegment3D& ray) const
1248 {
1249  bool res = true;
1250  hauteurA = ray._ptA._z - meanSlope._ptA._z;
1251  hauteurB = ray._ptB._z - meanSlope._ptB._z;
1252  return res;
1253 }
double RADTODEG(double a)
Converts an angle from radians to degrees.
Definition: 3d.h:137
#define TYSEUILCONFONDUS
Definition: 3d.h:47
double DEGTORAD(double a)
Converts an angle from degrees to radians.
Definition: 3d.h:126
std::vector< OPoint3D > TabPoint3D
Definition: 3d.h:483
std::deque< TYChemin > TYTabChemin
TYChemin collection.
Definition: TYChemin.h:255
std::deque< TYEtape > TYTabEtape
TYEtape collection.
Definition: TYEtape.h:193
NxReal s
Definition: NxVec3.cpp:317
#define min(a, b)
@ TYREFLEXION
Definition: acoustic_path.h:25
@ TYSOURCE
Definition: acoustic_path.h:28
@ TYREFLEXIONSOL
Definition: acoustic_path.h:26
@ TYDIFFRACTION
Definition: acoustic_path.h:24
virtual decimal traverse(Ray *r, std::list< Intersection > &result) const
Run this accelerator.
Definition: Accelerator.h:68
Class for the definition of atmospheric conditions.
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
The 3D point class.
Definition: 3d.h:487
double distFrom(const OPoint3D &pt) const
Computes the distance from this point to another.
Definition: 3d.cpp:371
Class to define a segment.
Definition: 3d.h:1089
virtual double longueur() const
Return the segment length.
Definition: 3d.cpp:1238
virtual int symetrieOf(const OPoint3D &pt, OPoint3D &ptSym) const
Return the symmetrical of a point.
Definition: 3d.cpp:1243
OPoint3D _ptA
Point A of the segment.
Definition: 3d.h:1201
virtual OVector3D toVector3D() const
Build a OVector3D from a segment used for the direction of the sources.
Definition: 3d.h:1188
virtual int intersects(const OSegment3D &seg, OPoint3D &pt, double seuilConfondus) const
Return the intersection point with another segment.
Definition: 3d.cpp:1267
OPoint3D _ptB
Point B of the segment.
Definition: 3d.h:1203
OSpectreAbstract & log(const double &base=10.0) const
Compute the log base n of this spectrum (n=10 by default).
Definition: spectre.cpp:404
unsigned int getNbValues() const
Number of values in the spectrum.
Definition: spectre.cpp:182
OSpectreAbstract & invMult(const double &coefficient=1.0) const
Division of a double constant by this spectrum.
Definition: spectre.cpp:345
void setType(TYSpectreType type)
Set the spectrum type.
Definition: spectre.h:152
OSpectreAbstract & div(const OSpectreAbstract &spectre) const
Division of two spectrums.
Definition: spectre.cpp:273
void setDefaultValue(const double &valeur=TY_SPECTRE_DEFAULT_VALUE)
Definition: spectre.cpp:197
OSpectreAbstract & round()
Definition: spectre.cpp:573
OSpectreAbstract & sumdB(const OSpectreAbstract &spectre) const
Energetic sum of two spectrums.
Definition: spectre.cpp:171
static OSpectreOctave getLambda(const double &c)
Definition: spectre.cpp:1591
static OSpectreOctave getEmptyLinSpectre(const double &valInit=1.0E-20)
Create a physical quantity spectrum.
Definition: spectre.cpp:1616
double * getTabValReel() override
Get an array of the real values of the spectrum.
Definition: spectre.h:613
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
double dot(const OVector3D &v)
dot product (assuming an orthonormal reference frame)
Definition: 3d.h:362
: Describes a ray by a pair of unsigned int. The first one gives the source number (in the range 0-40...
Definition: Ray.h:38
void setMaxt(decimal _maxt)
set the maxt
Definition: Ray.h:406
Accelerator * getAccelerator() const
Get the accelerator.
Definition: Scene.h:82
OSpectreOctave limAttDiffraction(const OSpectreOctave &sNC, const OSpectreOctave &C) const
Limit the screen attenuation value with a frequency dependent criteria.
std::unique_ptr< AtmosphericConditions > pSolverAtmos
void computeCheminSansEcran(const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &rayon, const tympan::AcousticSource &source, TYTabChemin &TabChemins, double distance, bool conditionFav=false) const
Compute the main path between source and receptor. In 9613 solver, this path includes all attenuation...
bool computeSegmentEdgesHeights(double &hauteurA, double &hauteurB, const OSegment3D &meanSlope, const OSegment3D &ray) const
Compute heights relative to real ground, of the edges of a segment.
TYSolver & _solver
Reference to the solver.
void init()
Initialize the acoustic model.
void computeCheminAPlat(const OSegment3D &rayon, const tympan::AcousticSource &source, TYTabChemin &TabChemins, double distance) const
Compute the list of paths for a perfectly flat and reflective ground.
OSpectreOctave calculAttDiffraction(const OSegment3D &ray, const double &re, const double &dss, const double &dsr, const double &width, const bool &vertical) const
Compute the attenuation from the diffraction on the screen.
TYAcousticModel(TYSolver &solver)
OSpectreOctave computeEffectiveBarAttenuation(const OSpectreOctave &Abar_top, const OSpectreOctave &Abar_left, const OSpectreOctave &Abar_right)
OSpectreOctave getReflexionSpectrumAt(const OSegment3D &incident, double length, const OSegment3D &segPente, const tympan::AcousticSource &source) const
Find Reflexion spectrum at point defined by the end of an incident segment.
OSpectreOctave calculC3(const double &epaisseur) const
Compute the spectrum of the C3 factor used in the diffraction calculation.
void meanSlope(const OSegment3D &director, OSegment3D &slope) const
Create a segment corresponding to the projection of "director" segment on the ground.
bool computeGZone(const OPoint3D &ptDebut, const OPoint3D &ptFin, double &GZone, double &dpZone, const std::deque< TYSIntersection > &tabIntersect) const
Compute GZone and dpZone for the segment between ptDebut and ptFin.
virtual ~TYAcousticModel()
bool solve(TYTrajet &trajet)
Compute the source contributions to the receptor point.
virtual void compute(const std::deque< TYSIntersection > &tabIntersect, TYTrajet &trajet, TabPoint3D &ptsTop, TabPoint3D &ptsLeft, TabPoint3D &ptsRight)
Main entry point, trigger acoustic computations.
OPlan buildMeanSlopePlan(const OSegment3D &penteMoyenne) const
void computeCheminReflexion(const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &ray, const tympan::AcousticSource &source, TYTabChemin &TabChemins, double distance) const
Compute the list of path generated by reflection on the vertical walls.
OSpectreOctave _absoNulle
OSpectreOctave _lambda
virtual bool computeCheminsAvecEcran(const OSegment3D &rayon, const tympan::AcousticSource &source, const TabPoint3D &pts, const bool vertical, TYTabChemin &TabChemins, double distance, const bool left) const
Compute barrier attenuation effect on the direct path for the considered geometrical path (top,...
bool getGroundfactors(const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &ray2D, double hs, double hr, double &Gs, double &Gm, double &Gr) const
Get ground factors for source, middle and receptor zones.
bool addStep(const OPoint3D &ptStart, const OPoint3D &ptEnd, const tympan::AcousticSource &source, const bool &fromSource, TYTabEtape &Etapes) const
Compute the different steps from a point to another via a reflection and a direct view.
Representation of one of the most optimal path between source and receptor: S—>R. The class TYChemin ...
Definition: TYChemin.h:71
double getLongueur()
Get/Set the path length.
Definition: TYChemin.h:166
const TYTypeChemin getType() const
Definition: TYChemin.h:216
void calcAttenuation(const TYTabEtape &tabEtapes, const AtmosphericConditions &atmos, double dp=0.0, double hs=0.0, double hr=0.0, double Gs=0.5, double Gm=0.5, double Gr=0.5)
Definition: TYChemin.cpp:87
OSpectreOctave & getAttenuation(TYTypeAttenuation type)
Definition: TYChemin.cpp:163
void setType(const TYTypeChemin &type)
Change the path type.
Definition: TYChemin.h:206
void setDistance(const double &distance)
Definition: TYChemin.h:197
void setLongueur(const double &longueur)
Definition: TYChemin.h:175
void build_eq_path(const TYTabEtape &tabEtapes)
Definition: TYChemin.cpp:187
The TYEtape class is used to describe a part (a step) of a path (TYChemin) for the computation of tra...
Definition: TYEtape.h:47
OPoint3D _pt
The starting point of this step.
Definition: TYEtape.h:186
ACOUSTIC_EVENT_TYPES _type
Acoustic event type.
Definition: TYEtape.h:185
void setPoint(const OPoint3D &pt)
Definition: TYEtape.h:116
OSpectreOctave _Absorption
absorption Spectrum
Definition: TYEtape.h:187
OSpectreOctave _Attenuation
attenuation Spectrum
Definition: TYEtape.h:188
virtual void selectFaces(std::deque< TYSIntersection > &tabIntersect, const OSegment3D &rayon, const string &sourceVolumeId)
Build the array of intersections.
static void exportResults17534(const std::vector< PathResults > pathsResults, const OSpectreOctave &SLp, const AtmosphericConditions &atmos)
9613 Solver
Definition: TYSolver.h:38
const Scene * getScene() const
Get the Scene.
Definition: TYSolver.h:72
const std::vector< TYStructSurfIntersect > & getTabPolygon() const
Get the array of polygons.
Definition: TYSolver.h:53
TYFaceSelector * getFaceSelector()
Get the face selector.
Definition: TYSolver.h:58
This class TYTrajet (journey) links a couple Source-Receptor and a collection of paths,...
Definition: TYTrajet.h:35
double getDistance()
Get/Set the distance between source and receptor.
Definition: TYTrajet.h:77
TYChemin getChemin(int index)
Return a path thanks to its index.
Definition: TYTrajet.h:138
void getPtSetPtRfromOSeg3D(OSegment3D &seg) const
Definition: TYTrajet.h:175
void build_tab_rays()
Definition: TYTrajet.cpp:198
TYTabChemin & getChemins()
Return the collection of paths of *this.
Definition: TYTrajet.h:106
size_t getNbChemins()
Return the number of path in *this (in addition to the direct path).
Definition: TYTrajet.h:96
OSpectreOctave & getSpectreOct()
Get the spectrum in octave band at the receptor point \Used to compute the pressure spectrum in octav...
Definition: TYTrajet.h:189
void reset()
Reset method.
Definition: TYTrajet.cpp:47
tympan::AcousticSource & asrc
Business source.
Definition: TYTrajet.h:225
3D vector Vector defined with 3 float numbers
Definition: mathlib.h:108
Describes building material.
Definition: entities.hpp:49
Base class for material.
Definition: entities.hpp:22
virtual ComplexSpectrum get_absorption(double incidence_angle, double length)
Virtual method to return material absorption at reflection point.
Definition: entities.hpp:27
Describes an acoustic source.
Definition: entities.hpp:366
string volume_id
Volume id.
Definition: entities.hpp:376
SourceDirectivityInterface * directivity
Pointer to the source directivity.
Definition: entities.hpp:375
Spectrum spectrum
Associated spectrum.
Definition: entities.hpp:374
static LPSolverConfiguration get()
Get the configuration.
Definition: config.cpp:93
virtual Spectrum lwAdjustment(Vector direction, double distance)=0
< Pure virtual method to return directivity of the Source
This file provides class for solver configuration.
Math library.
float decimal
Definition: mathlib.h:45
vec3 OPoint3Dtovec3(const OPoint3D &_p)
Converts a OPoint3D to vec3.
Definition: mathlib.h:440
base_vec3< decimal > vec3
Definition: mathlib.h:381
boost::shared_ptr< SolverConfiguration > LPSolverConfiguration
Definition: interfaces.h:25
@ SPECTRE_TYPE_LP
Definition: spectre.h:31
@ SPECTRE_TYPE_AUTRE
Definition: spectre.h:32
@ SPECTRE_TYPE_ABSO
Definition: spectre.h:29
OSpectreOctave Dz_top
OSpectreOctave Abar_left
OSpectreOctave Aatm
OSpectreOctave Agr_r
OSpectreOctave A
OSpectreOctave Abar
OSpectreOctave Abar_top
OSpectreOctave L
OSpectreOctave Agr_s
OSpectreOctave Dc
OSpectreOctave Abar_right
OSpectreOctave Adiv
OSpectreOctave Dz_right
TYTypeChemin pathType
OSpectreOctave LW
OSpectreOctave Agr_m
OSpectreOctave Dz_left
Data structure for intersections.
bool isInfra
Flag to define if is a infrastructure face.
OSegment3D segInter[2]
bool bIntersect[2]
Flag to indicate the face cuts vertical plane ([0]) or horizontal plane ([1])
tympan::AcousticMaterialBase * material
Pointer to a material.