Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYAcousticModelDefaultSolver.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 <deque>
17 #include <list>
18 #include <cmath>
19 #include <algorithm>
20 #include "Tympan/core/defines.h"
25 #include "TYSolverDefaultSolver.h"
26 
28  : TYAcousticModel(), _solver(solver)
29 {
31  _absoNulle.setType(SPECTRE_TYPE_ABSO); // Spectre d'absorption
32 }
33 
35 {
37  // On calcul tout de suite le spectre de longueur d'onde
39 }
40 
41 void TYAcousticModelDefaultSolver::compute(const std::deque<TYSIntersection>& tabIntersect,
42  TYTrajetDefaultSolver& trajet, TabPoint3D& ptsTop,
43  TabPoint3D& ptsLeft, TabPoint3D& ptsRight)
44 {
45  bool vertical = true, horizontal = false;
46 
47  // Construction du rayon SR
48  OSegment3D rayon;
49  trajet.getPtSetPtRfromOSeg3D(rayon);
50  bool conditionFav = false;
51 
52  // Calcul des conditions de propagation suivant la direction du vent
54  assert(config->DSWindDirection >= 0 && config->DSWindDirection <= 360);
55 
56  double windRadian = DEGTORAD(config->DSWindDirection);
57  OVector3D windDirection = OVector3D(-sin(windRadian), -cos(windRadian), 0);
58  OVector3D propaDirection = rayon.toVector3D();
59  propaDirection._z = 0;
60  double angle =
61  RADTODEG(acos(windDirection.dot(propaDirection) /
62  (windDirection.norme() * propaDirection.norme()))); // Angle always between 0-180
63  assert(180 >= angle >= 0);
64  assert(180 >= config->AngleFavorable >= 0);
65 
66  if (angle <= config->AngleFavorable)
67  {
68  conditionFav = true;
69  }
70  else
71  {
72  conditionFav = false;
73  }
74 
75  // Recuperation de la source
76  tympan::AcousticSource& source = trajet.asrc;
77 
78  // Distance de la source au recepteur
79  double distance = trajet.getDistance();
80 
81  TYTabCheminDefaultSolver& tabChemins = trajet.getChemins();
82 
83  // Calcul des parcours lateraux
84  // 1. Vertical
85  computeCheminsAvecEcran(rayon, source, ptsTop, vertical, tabChemins, distance, conditionFav);
86 
87  // 2. Horizontal gauche
88  computeCheminsAvecEcran(rayon, source, ptsLeft, horizontal, tabChemins, distance, conditionFav);
89 
90  // 3. Horizontal droite
91  computeCheminsAvecEcran(rayon, source, ptsRight, horizontal, tabChemins, distance, conditionFav);
92 
93  if (tabChemins.size() == 0)
94  {
95  computeCheminSansEcran(rayon, source, tabChemins, distance, conditionFav);
96  }
97 
98  // Calcul des reflexions si necessaire
99  computeCheminReflexion(tabIntersect, rayon, source, tabChemins, distance);
100 
101  // On calcule systematiquement le chemin a plat sans obstacle
102  // pour limiter l'effet d'ecran a basse frequence
103  TYTabCheminDefaultSolver& tabCheminsSansEcran = trajet.getCheminsDirect();
104  computeCheminAPlat(rayon, source, tabCheminsSansEcran, distance);
105 
106  // Calcul la pression cumulee de tous les chemins au point de reception du trajet
107  solve(trajet);
108 
109  // Le calcul est fini pour ce trajet, on peut effacer les tableaux des chemins
110  tabChemins.clear();
111  tabCheminsSansEcran.clear();
112 }
113 
115  const tympan::AcousticSource& source,
116  TYTabCheminDefaultSolver& TabChemins,
117  double distance) const
118 {
119  TYTabEtapeDefaultSolver tabEtapes;
120 
121  // Calcul de la pente moyenne sur le trajet source-recepteur
122  OSegment3D penteMoyenne;
123  meanSlope(rayon, penteMoyenne);
124 
125  // Etape directe Source-Recepteur
126  TYEtapeDefaultSolver etape1;
127  TYCheminDefaultSolver chemin1;
128 
129  etape1._pt = rayon._ptA;
130  etape1._type = TYSOURCE;
131  etape1._Absorption =
132  (source.directivity->lwAdjustment(OVector3D(rayon._ptA, rayon._ptB), rayon.longueur())).racine();
133 
135 
136  tabEtapes.push_back(etape1); // Ajout de l'etape directe
137  chemin1.setLongueur(distance); // Dans ce cas, la longueur = la distance source/recepteur
138  chemin1.setDistance(distance);
139  chemin1.calcAttenuation(tabEtapes, *_pSolverAtmos);
140 
141  TabChemins.push_back(chemin1);
142  tabEtapes.clear(); // Vide le tableau des etapes
143 
144  // Liaison avec reflexion
145  // 1. Calcul du point de reflexion
146 
147  // Ajout du chemin reflechi
148  TYEtapeDefaultSolver etape2;
149  TYCheminDefaultSolver chemin2;
151 
152  etape2.setPoint(rayon._ptA);
153  etape2._type = TYSOURCE;
154 
155  OPoint3D ptSym;
156  int symOK = 0;
157  if (penteMoyenne.longueur() > 0) // Si la pente moyenne est definie, on prend le point symetrique
158  {
159  symOK = penteMoyenne.symetrieOf(rayon._ptA, ptSym);
160  }
161 
162  if (symOK == 0) // Sinon on prend une simple symetrie par rapport a z
163  {
164  ptSym = rayon._ptA;
165  ptSym._z = 2 * penteMoyenne._ptA._z - ptSym._z;
166  }
167 
168  // Calcul du point de reflexion
169  OPoint3D ptReflex;
170  penteMoyenne.intersects(OSegment3D(ptSym, rayon._ptB), ptReflex, TYSEUILCONFONDUS);
171 
172  // 2. Etape avant la reflexion
173  OSegment3D seg1(rayon._ptA, ptReflex); // On part de la source vers le point de reflexion
174  double rr = seg1.longueur();
175 
176  // Directivite de la source
177  etape2._Absorption =
178  (source.directivity->lwAdjustment(OVector3D(seg1._ptA, seg1._ptB), seg1.longueur())).racine();
179 
180  tabEtapes.push_back(etape2); // Ajout de l'etape avant reflexion
181 
182  // 3. Etape apres la reflexion
183 
184  TYEtapeDefaultSolver etape3;
185  etape3._pt = ptReflex;
186  etape3._type = TYREFLEXIONSOL;
187 
188  OSegment3D seg2 = OSegment3D(ptReflex, rayon._ptB); // Segment Point de reflexion->Point de reception
189  rr += seg2.longueur(); // Longueur parcourue sur le trajet reflechi
190 
191  if (_useSol)
192  {
193  etape3._Absorption = getReflexionSpectrumAt(seg1, rr, penteMoyenne, source);
194  }
195  else // Sol totalement reflechissant
196  {
197  etape3._Absorption = _absoNulle;
198  }
199 
200  tabEtapes.push_back(etape3); // Ajout de l'etape apres reflexion
201 
202  chemin2.setLongueur(rr);
203  chemin2.setDistance(distance);
204  chemin2.calcAttenuation(tabEtapes, *_pSolverAtmos);
205  TabChemins.push_back(chemin2);
206 
207  tabEtapes.clear(); // Vide le tableau des etapes
208 }
209 
211  const tympan::AcousticSource& source,
212  TYTabCheminDefaultSolver& TabChemin,
213  double distance, bool conditionFav) const
214 {
215  /*
216  LE CALCUL POUR UN TRAJET SANS OBSTACLE COMPORTE UN CHEMIN DIRECT
217  ET DE UN (CONDITIONS NORMALES) A TROIS (CONDITIONS FAVORABLES) TRAJETS
218  REFLECHIS
219  */
220  OSegment3D seg1, seg2;
221  TYTabEtapeDefaultSolver tabEtapes;
222  double rr = 0.0; // Longueur du chemin reflechi
223 
224  // Calcul de la pente moyenne sur le trajet source-recepteur
225  OSegment3D penteMoyenne;
226  meanSlope(rayon, penteMoyenne);
227 
228  // 1. Conditions homogenes sans vegetation
230  addGroundSteps(rayon._ptA, rayon._ptB, penteMoyenne, source, true, true, Etapes, rr);
231 
232  // Ajout du chemin direct
233  TYCheminDefaultSolver cheminDirect;
234  cheminDirect.setType(TYTypeChemin::CHEMIN_DIRECT);
235  tabEtapes.push_back(Etapes[0]); // Ajout de l'etape directe
236  cheminDirect.setLongueur(distance); // Dans ce cas, la longueur = la distance source/recepteur
237  cheminDirect.setDistance(distance);
238  cheminDirect.calcAttenuation(tabEtapes, *_pSolverAtmos);
239  TabChemin.push_back(cheminDirect); // (4) Ajout du chemin dans le tableau des chemins de la frequence
240 
241  tabEtapes.clear(); // Vide le tableau des etapes
242 
243  // Ajout du chemin reflechi
244  TYCheminDefaultSolver cheminReflechi;
245  cheminReflechi.setType(TYTypeChemin::CHEMIN_SOL);
246  tabEtapes.push_back(Etapes[1]); // Ajout de l'etape avant reflexion
247  tabEtapes.push_back(Etapes[2]); // Ajout de l'etape apres reflexion
248  cheminReflechi.setLongueur(rr);
249  cheminReflechi.setDistance(distance);
250  cheminReflechi.calcAttenuation(tabEtapes, *_pSolverAtmos);
251  TabChemin.push_back(cheminReflechi);
252 
253  tabEtapes.clear(); // Vide le tableau des etapes
254 
255  // 2. Conditions faborables
256  // on s'assure que les reflexions n'iront pas se faire au dela de la source et
257  // du recepteur
258 
259  if ((_propaCond == 1) || (_propaCond == 2 && conditionFav))
260  {
261  OPoint3D ptProj;
262  int res = 0;
263  double hauteurA = 0.0, hauteurB = 0.0;
264  if (penteMoyenne.longueur() > 0)
265  {
266  res = penteMoyenne.projection(rayon._ptA, ptProj, TYSEUILCONFONDUS);
267  if (res == 0)
268  {
269  ptProj = penteMoyenne._ptA;
270  }
271  hauteurA = rayon._ptA._z - ptProj._z;
272  res = penteMoyenne.projection(rayon._ptB, ptProj, TYSEUILCONFONDUS);
273  if (res == 0)
274  {
275  ptProj = penteMoyenne._ptB;
276  }
277  hauteurB = rayon._ptB._z - ptProj._z;
278  }
279  else
280  {
281  ptProj = rayon._ptA;
282  ptProj._z = penteMoyenne._ptA._z;
283  hauteurA = rayon._ptA._z - ptProj._z;
284  ptProj = rayon._ptB;
285  ptProj._z = penteMoyenne._ptB._z;
286  hauteurB = rayon._ptB._z - ptProj._z;
287  }
288 
289  // On s'assure que le calcul en conditions favorable ne va pas provoquer
290  // des reflexions au dela de la source et du recepteur
291  if (rayon.longueur() > (10 * (hauteurA + hauteurB)))
292  {
293  // 2.1 Conditions favorables
294 
295  // En conditions favorables, le chemin possede deux points de reflexion supplementaires
296  // Le premier a n fois la hauteur du point de reception (n = 10 en general) a proximite
297  // de la source, le second est aussi a n fois la hauteur du point de reception; cote recepteur
298 
299  // 2.1.1 Premier chemin
300  TYCheminDefaultSolver cheminSupp1;
301  cheminSupp1.setType(TYTypeChemin::CHEMIN_SOL);
302 
303  // Premiere etape
304  TYEtapeDefaultSolver etape; // Etape 1.1
305  etape._pt = rayon._ptA;
306  etape._type = TYSOURCE;
307 
308  // Calcul du point de reflexion
309  OPoint3D projA, projB;
310 
311  double distRef = _paramH * hauteurA; // distance =H1*hauteur de la source
312 
313  if (penteMoyenne.longueur() > 0)
314  {
315  res = penteMoyenne.projection(rayon._ptA, projA, TYSEUILCONFONDUS);
316  if (res == 0)
317  {
318  projA = penteMoyenne._ptA;
319  }
320  }
321  else
322  {
323  projA = rayon._ptA;
324  projA._z = penteMoyenne._ptA._z;
325  }
326 
327  OVector3D vect(projA, penteMoyenne._ptB);
328  vect.normalize();
329  OPoint3D ptReflex(OVector3D(projA) + vect * distRef);
330 
331  seg1 = OSegment3D(rayon._ptA, ptReflex);
332 
333  rr = seg1.longueur(); // Longueur du chemin reflechi
334 
335  etape._Absorption =
336  (source.directivity->lwAdjustment(OVector3D(rayon._ptA, rayon._ptB), rayon.longueur()))
337  .racine();
338 
339  tabEtapes.push_back(etape);
340 
341  // Deuxieme etape
342  etape._pt = ptReflex;
343  etape._type = TYREFLEXIONSOL;
344 
345  seg2 = OSegment3D(ptReflex, rayon._ptB);
346  rr = rr + seg2.longueur(); // Longueur totale du chemin reflechi
347 
348  // Prise en compte du terrain au point de reflexion
349  // 3 cas :
350  if (_useSol)
351  {
352  etape._Absorption = getReflexionSpectrumAt(seg1, rr, penteMoyenne, source);
353  }
354  else // Calcul sol reflechissant
355  {
356  etape._Absorption = _absoNulle;
357  }
358 
359  tabEtapes.push_back(etape);
360 
361  // Ajout du premier chemin au trajet
362  cheminSupp1.setLongueur(rr);
363  cheminSupp1.setDistance(distance);
364  cheminSupp1.calcAttenuation(tabEtapes, *_pSolverAtmos);
365  TabChemin.push_back(
366  cheminSupp1); // (2) Ajout du chemin dans le tableau des chemins de la frequence
367 
368  tabEtapes.clear(); // On s'assure que le tableau des etapes est vide
369 
370  // 2.1.2. Deuxieme chemin
371  TYCheminDefaultSolver cheminSupp2;
372  cheminSupp2.setType(TYTypeChemin::CHEMIN_SOL);
373 
374  // Premiere etape
375  etape._pt = rayon._ptA;
376  etape._type = TYSOURCE;
377 
378  // Calcul du point de reflexion
379  if (penteMoyenne.longueur() > 0)
380  {
381  res = penteMoyenne.projection(rayon._ptB, projB, TYSEUILCONFONDUS);
382  if (res == 0)
383  {
384  projB = penteMoyenne._ptB;
385  }
386  }
387  else
388  {
389  projB = rayon._ptB;
390  projB._z = penteMoyenne._ptB._z;
391  }
392 
393  distRef = _paramH * hauteurB;
394  ptReflex = OPoint3D(OVector3D(projB) - vect * distRef);
395 
396  seg1 = OSegment3D(rayon._ptA, ptReflex);
397  rr = seg1.longueur(); // Longueur du chemin reflechi
398 
399  etape._Absorption =
400  (source.directivity->lwAdjustment(OVector3D(rayon._ptA, rayon._ptB), rayon.longueur()))
401  .racine();
402 
403  tabEtapes.push_back(etape);
404 
405  // Deuxieme etape
406  etape._pt = ptReflex;
407  etape._type = TYREFLEXIONSOL;
408 
409  seg2 = OSegment3D(ptReflex, rayon._ptB);
410  rr = rr + seg2.longueur(); // Longueur totale du chemin reflechi
411 
412  // Prise en compte du terrain au point de reflexion
413 
414  // 3 cas :
415  if (_useSol)
416  {
417  etape._Absorption = getReflexionSpectrumAt(seg1, rr, penteMoyenne, source);
418  }
419  else // Calcul sol reflechissant
420  {
421  etape._Absorption = _absoNulle;
422  }
423 
424  tabEtapes.push_back(etape);
425 
426  // Ajout du deuxieme chemin
427  cheminSupp2.setDistance(distance);
428  cheminSupp2.setLongueur(rr);
429  cheminSupp2.calcAttenuation(tabEtapes, *_pSolverAtmos);
430  TabChemin.push_back(
431  cheminSupp2); // (3) Ajout du chemin dans le tableau des chemins de la frequence
432  tabEtapes.clear();
433  Etapes.clear();
434  }
435  }
436 }
437 
439  const tympan::AcousticSource& source,
440  const TabPoint3D& pts, const bool vertical,
441  TYTabCheminDefaultSolver& TabChemins,
442  double distance, bool conditionFav) const
443 {
444  /* ============================================================================================================
445  07/03/2005 : Suppression du calcul ddes pentes moyennes avant et apres l'obstacle.
446  On utilise uniquement la pente moyenne totale qui est prise comme la projection au sol de
447  la source et du recepteur.
448  ==============================================================================================================*/
449  if (pts.size() <= 1)
450  {
451  return false;
452  }
453 
454  double rr = 0.0; // Longueur parcourue lors de la reflexion sur le sol
455 
456  OSegment3D penteMoyenneTotale; //, penteMoyenneAvant, penteMoyenneApres;
457  OPoint3D firstPt(pts[1]);
458  OPoint3D lastPt(pts[pts.size() - 1]);
459 
460  TYTabEtapeDefaultSolver tabTwoReflex;
461  double longTwoReflex = 0.0;
462 
463  TYTabEtapeDefaultSolver tabOneReflexBefore;
464  double longOneReflexBefore = 0.0;
465 
466  TYTabEtapeDefaultSolver tabOneReflexAfter;
467  double longOneReflexAfter = 0.0;
468 
469  TYTabEtapeDefaultSolver tabNoReflex;
470  double longNoReflex = 0.0;
471 
473  meanSlope(rayon, penteMoyenneTotale);
474 
475  // /*--- AVANT L'OBSTACLE ---*/
476 
478  OSegment3D segCourant(rayon._ptA, firstPt);
479  double tempLong = segCourant.longueur();
480 
481  bool bCheminOk = addGroundSteps(rayon._ptA, firstPt, penteMoyenneTotale, source, true, false, Etapes,
482  rr); // Calcul des etapes avant l'obstacle
483 
484  // Si le parcours du rayon rencontre le sol (hors des reflexions), on ne continue pas la creation du
485  // chemin
486  if (!bCheminOk)
487  {
488  return true;
489  }
490 
491  tabNoReflex.push_back(Etapes[0]); // Ajoute le trajet direct au chemin sans reflexion
492  longNoReflex += tempLong;
493 
494  tabOneReflexAfter.push_back(Etapes[0]); // Ajoute le trajet direct au chemin une reflexion apres
495  longOneReflexAfter += tempLong;
496 
497  tabOneReflexBefore.push_back(Etapes[1]); // Ajoute les trajets reflechis
498  tabOneReflexBefore.push_back(Etapes[2]);
499  longOneReflexBefore += rr;
500 
501  tabTwoReflex.push_back(Etapes[1]); // Ajoute les trajets reflechis
502  tabTwoReflex.push_back(Etapes[2]);
503  longTwoReflex += rr;
504 
505  Etapes.clear(); // Efface le contenu de Etapes
506 
507  /*--- CONTOURNEMENT DE L'OBSTACLE ---*/
508 
509  double epaisseur = 0.0;
510  TYEtapeDefaultSolver Etape;
511 
512  for (unsigned int i = 1; i < pts.size() - 1; i++)
513  {
514  epaisseur += (OSegment3D(pts[i], pts[i + 1])).longueur();
515 
516  Etape._pt = pts[i];
517  Etape._type = TYDIFFRACTION;
518  Etape._Absorption = _absoNulle;
519 
520  tabTwoReflex.push_back(Etape);
521  tabOneReflexBefore.push_back(Etape);
522  tabOneReflexAfter.push_back(Etape);
523  tabNoReflex.push_back(Etape);
524  }
525 
526  longNoReflex += epaisseur;
527  longOneReflexAfter += epaisseur;
528  longOneReflexBefore += epaisseur;
529  longTwoReflex += epaisseur;
530 
531  /*--- APRES L'OBSTACLE ---*/
532  segCourant = OSegment3D(lastPt, rayon._ptB);
533  tempLong = segCourant.longueur();
534 
535  addGroundSteps(lastPt, rayon._ptB, penteMoyenneTotale, source, false, true, Etapes, rr);
536 
537  tabNoReflex.push_back(Etapes[0]);
538  longNoReflex += tempLong;
539 
540  tabOneReflexBefore.push_back(Etapes[0]);
541  longOneReflexBefore += tempLong;
542 
543  tabOneReflexAfter.push_back(Etapes[1]);
544  tabOneReflexAfter.push_back(Etapes[2]);
545  longOneReflexAfter += rr;
546 
547  tabTwoReflex.push_back(Etapes[1]);
548  tabTwoReflex.push_back(Etapes[2]);
549  longTwoReflex += rr;
550 
551  Etapes.clear();
552 
553  /*--- PRISE EN COMPTE DE L'EFFET DE DIFFRACTION APPORTE PAR L'ECRAN SUR CHAQUE CHEMIN ---*/
554 
555  OSpectre Diff;
556  bool bDiffOk = true; // Sera mis a false si la difference de marche devient <=0
557 
558  Etape._pt = rayon._ptB;
559  Etape._type = TYRECEPTEUR;
560  Etape._Absorption = _absoNulle;
561 
562  // 4.1. Chemin sans reflexion
563  Diff = calculAttDiffraction(rayon, penteMoyenneTotale, false, longNoReflex, epaisseur, vertical, false,
564  bDiffOk, conditionFav);
565  Etape._Attenuation = Diff;
566  tabNoReflex.push_back(Etape);
567 
568  // 4.2. Chemin 2 reflexions
569  Diff = calculAttDiffraction(rayon, penteMoyenneTotale, false, longTwoReflex, epaisseur, vertical, false,
570  bDiffOk, conditionFav);
571  Etape._Attenuation = Diff;
572  tabTwoReflex.push_back(Etape);
573 
574  // 4.3. Chemin une reflexion avant
575  Diff = calculAttDiffraction(rayon, penteMoyenneTotale, true, longOneReflexBefore, epaisseur, vertical,
576  false, bDiffOk, conditionFav);
577  Etape._Attenuation = Diff;
578  tabOneReflexBefore.push_back(Etape);
579 
580  // 4.4. Chemin une reflexion apres
581  Diff = calculAttDiffraction(rayon, penteMoyenneTotale, true, longOneReflexAfter, epaisseur, vertical,
582  true, bDiffOk, conditionFav);
583  Etape._Attenuation = Diff;
584  tabOneReflexAfter.push_back(Etape);
585 
586  /*--- AJOUT DES CHEMINS AU au tableau des chemins ---*/
587 
588  TYCheminDefaultSolver cheminEcranTwoReflex;
589  cheminEcranTwoReflex.setType(TYTypeChemin::CHEMIN_ECRAN);
590  cheminEcranTwoReflex.setDistance(distance);
591 
592  // Chemin reflexion au sol avant et apres l'obstacle
593  cheminEcranTwoReflex.setLongueur(longTwoReflex);
594  cheminEcranTwoReflex.calcAttenuation(tabTwoReflex, *_pSolverAtmos);
595  TabChemins.push_back(cheminEcranTwoReflex);
596 
597  // Chemin avec une reflexion avant
598  TYCheminDefaultSolver cheminOneReflexBefore;
599  cheminOneReflexBefore.setType(TYTypeChemin::CHEMIN_ECRAN);
600  cheminOneReflexBefore.setDistance(distance);
601 
602  cheminOneReflexBefore.setLongueur(longOneReflexBefore);
603  cheminOneReflexBefore.calcAttenuation(tabOneReflexBefore, *_pSolverAtmos);
604  TabChemins.push_back(cheminOneReflexBefore);
605 
606  // Chemin avec une reflexion apres
607  TYCheminDefaultSolver cheminOneReflexAfter;
608  cheminOneReflexAfter.setType(TYTypeChemin::CHEMIN_ECRAN);
609  cheminOneReflexAfter.setDistance(distance);
610 
611  cheminOneReflexAfter.setLongueur(longOneReflexAfter);
612  cheminOneReflexAfter.calcAttenuation(tabOneReflexAfter, *_pSolverAtmos);
613  TabChemins.push_back(cheminOneReflexAfter);
614 
615  // Chemin sans reflexion sur le sol
616  TYCheminDefaultSolver cheminNoReflex;
617  cheminNoReflex.setType(TYTypeChemin::CHEMIN_ECRAN);
618  cheminNoReflex.setDistance(distance);
619 
620  cheminNoReflex.setLongueur(longNoReflex);
621  cheminNoReflex.calcAttenuation(tabNoReflex, *_pSolverAtmos);
622  TabChemins.push_back(cheminNoReflex);
623 
624  tabTwoReflex.clear();
625  tabOneReflexBefore.clear();
626  tabOneReflexAfter.clear();
627  tabNoReflex.clear();
628  Etapes.clear();
629 
630  return true;
631 }
632 
634  const OSegment3D& penteMoyenne,
635  const tympan::AcousticSource& source,
636  const bool& fromSource, const bool& toRecepteur,
637  TYTabEtapeDefaultSolver& Etapes, double& rr) const
638 {
639  /* =========================================================================================
640  0001 : 10/03/2005 : Modification du calcul des points symetriques
641  ========================================================================================= */
642  bool res = true;
643 
644  OSegment3D segDirect(ptDebut, ptFin);
645  OPoint3D ptSym, ptReflex, pt3;
646 
647  TYEtapeDefaultSolver EtapeCourante;
648 
649  // === CONSTRUCTION DU TRAJET DIRECT ptDebut-ptFin
650  EtapeCourante._pt = ptDebut;
651 
652  if (fromSource) // Si on part d'une source, on tient compte de la directivite de celle-ci
653  {
654  EtapeCourante._type = TYSOURCE;
655  EtapeCourante._Absorption =
656  (source.directivity->lwAdjustment(OVector3D(ptDebut, ptFin), ptDebut.distFrom(ptFin))).racine();
657  }
658  else
659  {
660  EtapeCourante._type = TYDIFFRACTION;
661  EtapeCourante._Absorption = _absoNulle;
662  }
663 
664  Etapes.push_back(EtapeCourante);
665 
666  // === CONSTRUCTION DU TRAJET REFLECHI
667 
668  // Construction du plan correspondant a la pente moyenne.
669  OPlan planPenteMoyenne = buildMeanSlopePlan(penteMoyenne);
670 
671  // On construit le segment correspondant a la projection des points sur le plan
672  OPoint3D ptDebutProj; // PtDebut projete sur le plan
673  planPenteMoyenne.intersectsSegment(OPoint3D(ptDebut._x, ptDebut._y, +100000),
674  OPoint3D(ptDebut._x, ptDebut._y, -100000), ptDebutProj);
675 
676  OPoint3D ptFinProj; // PtFin projete sur le plan
677  planPenteMoyenne.intersectsSegment(OPoint3D(ptFin._x, ptFin._y, +100000),
678  OPoint3D(ptFin._x, ptFin._y, -100000), ptFinProj);
679 
680  OSegment3D segPente(ptDebutProj, ptFinProj);
681 
682  // Liaison avec reflexion
683  // Calcul du point de reflexion
684  int symOK = 0;
685 
686  EtapeCourante._pt = ptDebut;
687  if (segPente.longueur() > 0) // Si la pente moyenne est definie, on prend le point symetrique
688  {
689  symOK = segPente.symetrieOf(ptDebut, ptSym);
690  }
691 
692  if (symOK == 0) // Sinon on prend une simple symetrie par rapport a z
693  {
694  ptSym = ptDebut;
695  ptSym._z = 2 * segPente._ptA._z - ptSym._z;
696  }
697 
698  int result = segPente.intersects(OSegment3D(ptSym, ptFin), ptReflex, TYSEUILCONFONDUS);
699 
700  if (result == 0) // Si pas d'intersection trouvee, on passe au plan B
701  {
702  OPoint3D ptSymFin;
703  symOK = 0;
704 
705  if (segPente.longueur() > 0) // Si la pente moyenne est definie, on prend le point symetrique
706  {
707  symOK = segPente.symetrieOf(ptFin, ptSymFin);
708  }
709 
710  if (symOK == 0) // Sinon on prend une simple symetrie par rapport a z
711  {
712  ptSymFin = ptFin;
713  ptSymFin._z = 2 * segPente._ptB._z - ptSymFin._z;
714  }
715 
716  // Calcul du coefficient lie au rapport des hauteurs
717  // Distance de du point symetrique a la droite de pente moyenne
718  double d1 = ptSym.distFrom(segPente._ptA);
719  double d2 = ptSymFin.distFrom(segPente._ptB);
720 
721  double coefH = (d1 + d2) != 0 ? d1 / (d2 + d1) : 0.0;
722 
723  // Calcul des coordommees du point de reflexion
724  ptReflex._x = (ptSymFin._x - ptSym._x) * coefH + ptSym._x;
725  ptReflex._y = (ptSymFin._y - ptSym._y) * coefH + ptSym._y;
726  ptReflex._z = (ptSymFin._z - ptSym._z) * coefH + ptSym._z;
727  }
728 
729  // On traie deux cas :
730  // 1/ le depart et l'arrivee ne sont pas sur le sol
731  // 2/ le depart ou l'arrivee sont sur le sol et sont soit la source, soit le recepteur
732  // 3/ ni 1, ni 2, dans ce cas, les segments ne sont pas produits
733  if ((ptSym.distFrom(ptReflex) > TYSEUILCONFONDUS) && (ptFin.distFrom(ptReflex) > TYSEUILCONFONDUS))
734  {
735  // Etape avant la reflexion
736  OSegment3D seg1(ptDebut, ptReflex);
737 
738  rr = seg1.longueur();
739 
740  if (fromSource) // Si on part d'une source, on tient compte de la directivite de celle-ci
741  {
742  EtapeCourante._type = TYSOURCE;
743  EtapeCourante._Absorption =
744  (source.directivity->lwAdjustment(OVector3D(ptDebut, ptReflex), ptDebut.distFrom(ptReflex)))
745  .racine();
746  }
747  else
748  {
749  EtapeCourante._type = TYDIFFRACTION;
750  EtapeCourante._Absorption = _absoNulle;
751  }
752 
753  Etapes.push_back(EtapeCourante);
754 
755  // Etape Apres reflexion
756  EtapeCourante._pt = ptReflex;
757  EtapeCourante._type = TYREFLEXIONSOL;
758 
759  OSegment3D seg2 = OSegment3D(ptReflex, ptFin); // Segment Point de reflexion->Point de reception
760  rr = rr + seg2.longueur(); // Longueur parcourue sur le trajet reflechi
761 
762  // 3 cas :
763  if (_useSol)
764  {
765  EtapeCourante._Absorption = getReflexionSpectrumAt(seg1, rr, segPente, source);
766  }
767  else // Sol totalement reflechissant
768  {
769  EtapeCourante._Absorption = _absoNulle;
770  }
771 
772  Etapes.push_back(EtapeCourante);
773  }
774  else if (fromSource || toRecepteur)
775  {
776  // Etape avant la reflexion
777  OSegment3D seg1(ptDebut, ptReflex);
778  rr = seg1.longueur();
779 
780  EtapeCourante._Absorption = _absoNulle;
781 
782  Etapes.push_back(EtapeCourante);
783 
784  // Etape Apres reflexion
785  EtapeCourante._pt = ptReflex;
786  EtapeCourante._type = TYREFLEXIONSOL;
787 
788  OSegment3D seg2 = OSegment3D(ptReflex, ptFin); // Segment Point de reflexion->Point de reception
789  rr = rr + seg2.longueur(); // Longueur parcourue sur le trajet reflechi
790 
791  // 3 cas :
792  if (_useSol)
793  {
794  EtapeCourante._Absorption = getReflexionSpectrumAt(seg1, rr, segPente, source);
795  }
796  else // Sol totalement reflechissant
797  {
798  EtapeCourante._Absorption = _absoNulle;
799  }
800 
801  Etapes.push_back(EtapeCourante);
802  }
803  else
804  {
805  Etapes.clear();
806  res = false;
807  }
808 
809  return res;
810 }
811 
812 void TYAcousticModelDefaultSolver::computeCheminReflexion(const std::deque<TYSIntersection>& tabIntersect,
813  const OSegment3D& rayon,
814  const tympan::AcousticSource& source,
815  TYTabCheminDefaultSolver& TabChemins,
816  double distance) const
817 {
818  if (!_useReflex)
819  {
820  return;
821  }
822 
823  OSegment3D segInter;
824  OSegment3D rayonTmp;
825  OPoint3D ptSym;
826  OSpectre SpectreAbso;
827 
828  OSegment3D seg; // Segment source image->recepteur
829  OSegment3D segMontant; // Segment source-> point de reflexion
830  OSegment3D segDescendant; // Segment point de reflexion->recepteur
831 
832  OPoint3D pt; // Point d'intersection
833 
834  size_t nbFaces = tabIntersect.size();
835 
836  // Pour chaque face test de la reflexion
837  for (unsigned int i = 0; i < nbFaces; i++)
838  {
839  TYSIntersection inter = tabIntersect[i];
840 
841  // Si la face ne peut interagir on passe a la suivante
842  if ((!inter.isInfra) || !(inter.bIntersect[1]))
843  {
844  continue;
845  }
846 
847  segInter = inter.segInter[1];
848 
849  // Calcul du symetrique de A par rapport au segment
850  segInter.symetrieOf(rayon._ptA, ptSym); // On ne s'occupe pas de la valeur de retour de cette fonction
851  seg._ptA = ptSym;
852  seg._ptB = rayon._ptB; // Segment source image->recepteur
853 
854  if (segInter.intersects(seg, pt, TYSEUILCONFONDUS))
855  {
856  // Construction du segment source->pt de reflexion
857  segMontant._ptA = rayon._ptA;
858  segMontant._ptB = pt;
859  // Construction du segment pt de reflexion-> recepteur
860  segDescendant._ptA = segMontant._ptB;
861  segDescendant._ptB = rayon._ptB;
862 
863  bool intersect = false;
864  size_t j = 0;
865 
866  // Si on traverse un autre ecran, qui peut etre de la topo, le chemin de reflexion n'est pas pris
867  // en compte
868  while ((j < nbFaces) && (!intersect))
869  {
870  if (j == i)
871  {
872  j++;
873  continue; // Si la face ne peut interagir on passe a la suivante
874  }
875 
876  segInter = tabIntersect[j].segInter[1];
877 
878  // On teste si segInter intersecte le segment montant ou
879  // le segment descendant dans le plan global).
880  // point bidon seul vaut l'intersection ou non
881  if ((segInter.intersects(segMontant, pt, TYSEUILCONFONDUS)) ||
882  (segInter.intersects(segDescendant, pt, TYSEUILCONFONDUS)))
883  {
884  // intersection trouvee, la boucle peut etre interrompue;
885  intersect = true;
886  break;
887  }
888 
889  j++;
890  }
891 
892  // Si le chemin reflechi n'est pas coupe, on peut calculer la reflexion
893  if (!intersect)
894  {
895  SpectreAbso = dynamic_cast<tympan::AcousticBuildingMaterial*>(inter.material)->asEyring();
896  SpectreAbso = SpectreAbso.mult(-1.0).sum(1.0);
897 
901  // TYAcousticCylinder* pCyl = NULL;
902  // if (pSurfaceGeoNode) { pCyl =
903  // dynamic_cast<TYAcousticCylinder*>(pSurfaceGeoNode->getParent()); } rayonTmp = rayon *
904  // SI.matInv; if (pCyl)
905  //{
906  // OPoint3D centre(pCyl->getCenter());
907  // OVector3D SC(rayonTmp._ptA, centre);
908  // OVector3D CR(centre, rayonTmp._ptB);
909  // double diametre = pCyl->getDiameter();
910  // double dSC = SC.norme(); // Norme du vecteur
911  // double phi = SC.angle(CR);
912 
913  // SpectreAbso = SpectreAbso.mult(diametre * sin(phi / 2) / (2 * dSC));
914  //}
915 
916  // Premiere etape : du debut du rayon au point de reflexion sur la face
917  TYTabEtapeDefaultSolver tabEtapes;
918 
919  double rr = segMontant.longueur() + segDescendant.longueur();
920 
921  TYEtapeDefaultSolver Etape;
922  Etape._pt = rayon._ptA;
923  Etape._type = TYSOURCE;
924  Etape._Absorption = (source.directivity->lwAdjustment(
925  OVector3D(segMontant._ptA, segMontant._ptB), segMontant.longueur()))
926  .racine();
927 
928  tabEtapes.push_back(Etape);
929 
930  // Deuxieme etape : du point de reflexion a la fin du rayon
931  Etape._pt = segDescendant._ptA;
932  Etape._type = TYREFLEXION;
933  Etape._Absorption = SpectreAbso;
934 
935  tabEtapes.push_back(Etape);
936 
937  TYCheminDefaultSolver Chemin;
939  Chemin.setLongueur(rr);
940  Chemin.setDistance(distance);
941  Chemin.calcAttenuation(tabEtapes, *_pSolverAtmos);
942 
943  TabChemins.push_back(Chemin); // Mise en place du chemin dans la table des chemins
944  tabEtapes.clear();
945  }
946  }
947  }
948 }
949 
950 OSpectre TYAcousticModelDefaultSolver::calculC(const double& epaisseur) const
951 {
952  // C = (1 + (5*lambda/epaisseur)²) / (1/3 + (5*lambda/epaisseur)²)
953 
955  OSpectre opLambda;
956 
957  if (epaisseur < 1.0E-2)
958  {
959  C.setDefaultValue(1.0);
960  }
961  else
962  {
963  const double unTiers = 1.0 / 3.0;
964 
965  opLambda = _lambda.mult(5.0 / epaisseur); // (5*lambda/e)
966  opLambda = opLambda.mult(opLambda); // (5*lambda/e)²
967 
968  C = opLambda.sum(1.0); // 1 + (5*lambda/e)²
969  C = C.div(opLambda.sum(unTiers)); // (1 + (5*lambda/e)²) / (1/3 + (5*lambda/epaisseur)²)
970  }
971 
972  C.setType(SPECTRE_TYPE_AUTRE); // Ni Attenuation, ni Absorption
973 
974  return C;
975 }
976 
978  const OSegment3D& penteMoyenne,
979  const bool& miroir, const double& re,
980  const double& epaisseur, const bool& vertical,
981  const bool& avantApres, bool& bDiffOk,
982  bool conditionFav) const
983 {
984  double rd = NAN;
985 
986  OSpectre s;
987 
988  OSpectre C = calculC(epaisseur); // Facteur correctif lie a l'epaisseur de l'ecran
989 
990  // Si le chemin comporte une reflexion sur le sol (et une seule), on prend le trajet source image
991  // recepteur
992  if (miroir)
993  {
994  OPoint3D ptSym;
995  if (!avantApres) // On est avant l'obstacle, on calcul le symetrique du point A
996  {
997  if (penteMoyenne.longueur() > 0) // On peut calculer la symetrie
998  {
999  penteMoyenne.symetrieOf(rayon._ptA, ptSym);
1000  }
1001  else // On se contente de prendre le symetrique par rapport a z
1002  {
1003  ptSym = rayon._ptA;
1004  ptSym._z = 2 * penteMoyenne._ptA._z - ptSym._z;
1005  }
1006 
1007  OSegment3D segReflex(ptSym, rayon._ptB);
1008  rd = segReflex.longueur();
1009  }
1010  else // On est apres l'obstacle, on calcule le symetrique du point B
1011  {
1012  if (penteMoyenne.longueur() > 0) // On peut calculer la symetrie
1013  {
1014  penteMoyenne.symetrieOf(rayon._ptB, ptSym);
1015  }
1016  else // On se contente de prendre le symetrique par rapport a z
1017  {
1018  ptSym = rayon._ptB;
1019  ptSym._z = 2 * penteMoyenne._ptB._z - ptSym._z;
1020  }
1021 
1022  OSegment3D segReflex(rayon._ptA, ptSym);
1023  rd = segReflex.longueur();
1024  }
1025  }
1026  else
1027  {
1028  rd = rayon.longueur();
1029  }
1030 
1031  // Dans le cas du calcul en conditions favorables on considere un trajet direct courbe
1032  if ((((_propaCond == 1) || (_propaCond == 2 && conditionFav))) && (vertical))
1033  {
1034  double gamma = rd * 8.0;
1035  gamma = (gamma > 1000 ? gamma : 1000.0); // Rayon minimum 1000 metres
1036 
1037  double alpha = 2 * asin(rd / (2 * gamma));
1038 
1039  rd = gamma * alpha; // Longueur de l'arc de rayon gamma passant par les points extreme du segment de
1040  // longueur rd
1041  }
1042 
1043  double delta = re - rd; // difference de marche
1044  delta = delta <= 0 ? 0.0 : delta;
1045 
1046  // Attenuation apportee par la diffraction = sqrt(3 + (40 * C * delta)/lambda)
1047 
1048  s = _lambda.invMult(40 * delta); // =40*delta/lambda
1049  s = s.mult(C); // 40*delta*C/lambda
1050  s = s.sum(3.0);
1051 
1052  // Si la diffraction a lieu dans le plan vertical (arete horizontale),
1053  // les attenuations minimales et maximales sont limitees respectivement
1054  // a 0 dB et 20 ou 25 dB (selon que l'on est en ecran mince ou epais).
1055  if (vertical)
1056  {
1057  s = limAttDiffraction(s, C);
1058  }
1059 
1060  s.setType(SPECTRE_TYPE_ATT);
1061 
1062  return s.racine();
1063 }
1064 
1066 {
1068  s.setType(SPECTRE_TYPE_ATT);
1069 
1070  double lim20dB = pow(10.0, (20.0 / 10.0));
1071  double lim25dB = pow(10.0, (25.0 / 10.0));
1072  double lim0dB = pow(10.0, (0.0 / 10.0));
1073 
1074  double valeur = NAN;
1075 
1076  for (unsigned int i = 0; i < sNC.getNbValues(); i++)
1077  {
1078  valeur = sNC.getTabValReel()[i];
1079 
1080  valeur = valeur < lim0dB ? lim0dB : valeur; // L'attenuation ne peut etre inferieure a 1
1081 
1082  if ((C.getTabValReel()[i] - 1) <= 1e-2) // Comportement ecran mince
1083  {
1084  valeur = valeur > lim20dB ? lim20dB : valeur;
1085  }
1086  else // Comportement ecran epais ou multiple
1087  {
1088  valeur = valeur > lim25dB ? lim25dB : valeur;
1089  }
1090 
1091  s.getTabValReel()[i] = valeur;
1092  }
1093 
1094  return s;
1095 }
1096 
1098 {
1099  const double PIM4 = 4.0 * M_PI;
1100 
1102  float minSRDistance = config->MinSRDistance;
1103  double rD2 = (minSRDistance > trajet.getDistance()) ? minSRDistance : trajet.getDistance();
1104 
1105  rD2 = rD2 * rD2;
1106 
1107  double divGeom = _pSolverAtmos->compute_z() / (PIM4 * rD2);
1108 
1109  OSpectre& SLp = trajet.getSpectre();
1110 
1111  // W.rho.c / (4pi*rd²)
1112  SLp = trajet.asrc.spectrum.mult(divGeom);
1113 
1114  // (W.rho.c/4.pi.Rd²)*Attenuations du trajet
1115  if (_interference)
1116  {
1117  SLp = SLp.mult(trajet.getPInterference(*_pSolverAtmos));
1118  }
1119  else
1120  {
1121  SLp = SLp.mult(trajet.getPEnergetique(*_pSolverAtmos));
1122  }
1123  SLp.setType(SPECTRE_TYPE_LP); // Le spectre au point est bien un spectre de pression !
1124 
1125  return true;
1126 }
1127 
1130  const OSegment3D& segPente,
1131  const tympan::AcousticSource& source) const
1132 {
1133  OSpectreComplex spectre;
1134 
1135  // Search for material at reflexion point
1136  // Set position of ray at the same high as the source plus a little increment to avoid being just under
1137  // the ground cause to rounding issues for sources set on the ground
1138  vec3 start = OPoint3Dtovec3(incident._ptB);
1139  start.z = (decimal)incident._ptA._z;
1140  Ray ray1(start, vec3(0., 0., -1.));
1141  ray1.setMaxt(20000);
1142 
1143  std::list<Intersection> LI;
1144 
1145  static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray1, LI));
1146 
1147  if (LI.empty())
1148  {
1149  start.z = (decimal)(incident._ptB._z + 10000);
1150  Ray ray1(start, vec3(0., 0., -1.));
1151  ray1.setMaxt(20000);
1152  static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray1, LI));
1153  }
1154 
1155  assert(!LI.empty());
1156  unsigned int indexFace = LI.begin()->p->getPrimitiveId();
1157  tympan::AcousticMaterialBase* mat = _solver.getTabPolygon()[indexFace].material;
1158 
1159  // Avoid cases where the reflexion point is below a "floating" volumic source
1160  while (_solver.getTabPolygon()[indexFace].is_infra() &&
1161  source.volume_id == _solver.getTabPolygon()[indexFace].volume_id)
1162  {
1163  start.z = (decimal)std::min(std::min(_solver.getTabPolygon()[indexFace].tabPoint[0]._z,
1164  _solver.getTabPolygon()[indexFace].tabPoint[1]._z),
1165  _solver.getTabPolygon()[indexFace].tabPoint[2]._z);
1166  Ray ray(start, vec3(0, 0, -1));
1167  ray.setMaxt(20000);
1168  std::list<Intersection> LI2;
1169  static_cast<double>(_solver.getScene()->getAccelerator()->traverse(&ray, LI2));
1170  // assert( !LI2.empty() );
1171  if (LI2.empty())
1172  break;
1173  indexFace = LI2.begin()->p->getPrimitiveId();
1174  mat = _solver.getTabPolygon()[indexFace].material;
1175  }
1176 
1177  // Angle estimation
1178  OVector3D direction(incident._ptA, incident._ptB);
1179  direction.normalize();
1180 
1181  // This is kept commented for the time being, even though it's the best solution
1182  // double angle = ( direction * -1 ).angle( _solver.getTabPolygon()[indexFace].normal );
1183  // angle = ABS(M_PI/2. - angle);
1184  double angle = (direction * -1).angle(OVector3D(incident._ptB, segPente._ptA));
1185  // Compute reflexion spectrum
1186  spectre = mat->get_absorption(angle, length);
1187 
1188  return spectre;
1189 }
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
NxReal s
Definition: NxVec3.cpp:317
#define min(a, b)
std::deque< TYCheminDefaultSolver > TYTabCheminDefaultSolver
TYChemin collection.
std::deque< TYEtapeDefaultSolver > TYTabEtapeDefaultSolver
TYEtape collection.
@ TYREFLEXION
Definition: acoustic_path.h:25
@ TYRECEPTEUR
Definition: acoustic_path.h:29
@ 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
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
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:1141
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:1253
virtual OVector3D toVector3D() const
Build a OVector3D from a segment used for the direction of the sources.
Definition: 3d.h:1240
virtual int projection(const OPoint3D &pt, OPoint3D &ptProj, double seuilConfondus) const
Return the projection of a point.
Definition: 3d.cpp:1258
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:1255
OSpectreAbstract & sum(const OSpectreAbstract &spectre) const
Arithmetic sum of two spectrums in one-third Octave.
Definition: spectre.cpp:224
unsigned int getNbValues() const
Number of values in the spectrum.
Definition: spectre.cpp:187
OSpectreAbstract & invMult(const double &coefficient=1.0) const
Division of a double constant by this spectrum.
Definition: spectre.cpp:350
void setType(TYSpectreType type)
Set the spectrum type.
Definition: spectre.h:153
OSpectreAbstract & div(const OSpectreAbstract &spectre) const
Division of two spectrums.
Definition: spectre.cpp:278
OSpectreAbstract & racine() const
Compute the root square of this spectrum.
Definition: spectre.cpp:432
void setDefaultValue(const double &valeur=TY_SPECTRE_DEFAULT_VALUE)
Definition: spectre.cpp:202
OSpectreAbstract & mult(const OSpectreAbstract &spectre) const
Multiplication of two spectrums.
Definition: spectre.cpp:248
static OSpectre getLambda(const double &c)
Definition: spectre.cpp:1077
static OSpectre getEmptyLinSpectre(const double &valInit=1.0E-20)
Create a physical quantity spectrum.
Definition: spectre.cpp:1130
double * getTabValReel() override
Definition: spectre.h:357
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 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
OSpectre calculAttDiffraction(const OSegment3D &rayon, const OSegment3D &penteMoyenne, const bool &miroir, const double &re, const double &epaisseur, const bool &vertical, const bool &avantApres, bool &bDiffOk, bool conditionFav=false) const
Compute the attenuation from the diffraction on the screen.
OSpectreComplex 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.
void computeCheminSansEcran(const OSegment3D &rayon, const tympan::AcousticSource &source, TYTabCheminDefaultSolver &TabChemins, double distance, bool conditionFav=false) const
Compute the list of paths generated by reflection on the ground if there is no screen.
bool solve(TYTrajetDefaultSolver &trajet)
Compute the source contribution to the point.
virtual void compute(const std::deque< TYSIntersection > &tabIntersect, TYTrajetDefaultSolver &trajet, TabPoint3D &ptsTop, TabPoint3D &ptsLeft, TabPoint3D &ptsRight)
OSpectre limAttDiffraction(const OSpectre &sNC, const OSpectre &C) const
Limit the screen attenuation value with a frequency dependent criteria.
void computeCheminReflexion(const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &rayon, const tympan::AcousticSource &source, TYTabCheminDefaultSolver &TabChemins, double distance) const
Compute the list of path generated by reflection on the vertical walls.
TYSolverDefaultSolver & _solver
Reference to the solver.
bool addGroundSteps(const OPoint3D &ptDebut, const OPoint3D &ptFin, const OSegment3D &penteMoyenne, const tympan::AcousticSource &source, const bool &fromSource, const bool &toRecepteur, TYTabEtapeDefaultSolver &Etapes, double &longueur) const
Compute the different steps from a point to another via a reflection and a direct view.
void computeCheminAPlat(const OSegment3D &rayon, const tympan::AcousticSource &source, TYTabCheminDefaultSolver &TabChemins, double distance) const
Compute the list of paths for a perfectly flat and reflective ground.
OSpectre calculC(const double &epaisseur) const
Compute the spectrum of the C factor used in the diffraction calculation.
void computeWaveLength() override
Compute the wave length for the default solver.
TYAcousticModelDefaultSolver(TYSolverDefaultSolver &solver)
virtual bool computeCheminsAvecEcran(const OSegment3D &rayon, const tympan::AcousticSource &source, const TabPoint3D &pts, const bool vertical, TYTabCheminDefaultSolver &TabChemins, double distance, bool conditionFav=false) const
Compute the segment path from the list of the points of the TYTrajet journey. It takes in account the...
Acoustic model for the considered solver.
std::unique_ptr< AtmosphericConditions > _pSolverAtmos
void meanSlope(const OSegment3D &director, OSegment3D &slope) const
Create a segment corresponding to the projection of "director" segment on the ground.
OPlan buildMeanSlopePlan(const OSegment3D &penteMoyenne) const
Representation of one of the most optimal path between source and receptor: S—>R. The class TYChemin ...
void calcAttenuation(const TYTabEtapeDefaultSolver &tabEtapes, const AtmosphericConditions &atmos)
Compute the global attenuation on the path.
void setType(const TYTypeChemin &type)
Change the path type.
Definition: TYChemin.h:139
void setDistance(const double &distance)
Definition: TYChemin.h:130
void setLongueur(const double &longueur)
Definition: TYChemin.h:108
OSpectreComplex _Absorption
absorption Spectrum
OSpectre _Attenuation
attenuation Spectrum
OPoint3D _pt
The starting point of this step.
Definition: TYEtape.h:109
ACOUSTIC_EVENT_TYPES _type
Acoustic event type.
Definition: TYEtape.h:108
void setPoint(const OPoint3D &pt)
Definition: TYEtape.h:99
const Scene * getScene() const
Get the Scene.
Definition: TYSolver.h:71
const std::vector< TYStructSurfIntersect > & getTabPolygon() const
Get the array of polygons.
Definition: TYSolver.h:57
This class TYTrajet (journey) links a couple Source-Receptor and a collection of paths,...
OSpectre & getSpectre()
Get/Set the spectrum at the receptor point.
TYTabCheminDefaultSolver & getChemins()
Return the collection of paths of *this.
OSpectre getPInterference(const AtmosphericConditions &atmos)
Compute the quadratic pressure on the journey.
TYTabCheminDefaultSolver & getCheminsDirect()
Return an array of the direct paths.
OSpectre getPEnergetique(const AtmosphericConditions &atmos)
Compute the acoustic pressure (phase modulation) on the journey.
double getDistance()
Get/Set the distance between source and receptor.
Definition: TYTrajet.h:75
void getPtSetPtRfromOSeg3D(OSegment3D &seg) const
Definition: TYTrajet.h:115
tympan::AcousticSource & asrc
Business source.
Definition: TYTrajet.h:126
3D vector Vector defined with 3 float numbers
Definition: mathlib.h:114
Describes building material.
Definition: entities.hpp:64
Base class for material.
Definition: entities.hpp:37
virtual ComplexSpectrum get_absorption(double incidence_angle, double length)
Virtual method to return material absorption at reflection point.
Definition: entities.hpp:42
Describes an acoustic source.
Definition: entities.hpp:394
string volume_id
Volume id.
Definition: entities.hpp:404
SourceDirectivityInterface * directivity
Pointer to the source directivity.
Definition: entities.hpp:403
Spectrum spectrum
Associated spectrum.
Definition: entities.hpp:402
static LPSolverConfiguration get()
Get the configuration.
Definition: config.cpp:94
virtual Spectrum lwAdjustment(Vector direction, double distance)=0
< Pure virtual method to return directivity of the Source
#define M_PI
Pi.
Definition: color.cpp:25
This file provides class for solver configuration.
std::complex< double > TYComplex
Definition: macros.h:25
Math library.
float decimal
Definition: mathlib.h:45
vec3 OPoint3Dtovec3(const OPoint3D &_p)
Converts a OPoint3D to vec3.
Definition: mathlib.h:446
base_vec3< decimal > vec3
Definition: mathlib.h:387
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_ATT
Definition: spectre.h:28
@ SPECTRE_TYPE_ABSO
Definition: spectre.h:29
Data structure for intersections.
bool isInfra
Flag to define if is a infrastructure face.
bool bIntersect[2]
Flag to indicate the face cuts vertical plane ([0]) or horizontal plane ([1])
OSegment3D segInter[2]
tympan::AcousticMaterialBase * material
Pointer to a material.