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