Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYAcousticModel9613Solver2024.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 
17 #include <fstream>
18 #include <string>
19 
21 
22 namespace
23 {
24 std::string readValueFromConfig(const std::string& filePath, const std::string& key,
25  const std::string& defaultValue)
26 {
27  std::ifstream file(filePath);
28  if (!file.is_open())
29  {
30  return defaultValue;
31  }
32 
33  const std::string keyExtended = key + "=";
34  std::string line;
35 
36  while (std::getline(file, line))
37  {
38  if (line.compare(0, keyExtended.size(), keyExtended) == 0)
39  {
40  std::string value{line.substr(keyExtended.size())};
41  return value;
42  }
43  }
44 
45  return defaultValue;
46 }
47 
48 std::string readReflectionMethodFromConfig(const std::string& filePath, std::string defaultValue)
49 {
50  return readValueFromConfig(filePath, "REFLECTION_METHOD", defaultValue);
51 }
52 
53 unsigned int readRaytracingNbRaysFromConfig(const std::string& filePath, unsigned int defaultValue)
54 {
55  const std::string value =
56  readValueFromConfig(filePath, "RAYTRACING_NB_RAYS", std::to_string(defaultValue));
57  try
58  {
59  return static_cast<unsigned int>(std::stoul(value));
60  }
61  catch (...)
62  {
63  return defaultValue;
64  }
65 }
66 
67 double readRaytracingRcptRadiusFromConfig(const std::string& filePath, double defaultValue)
68 {
69  const std::string value =
70  readValueFromConfig(filePath, "RAYTRACING_RCPT_RADIUS", std::to_string(defaultValue));
71  try
72  {
73  return static_cast<double>(std::stod(value));
74  }
75  catch (...)
76  {
77  return defaultValue;
78  }
79 }
80 
82  double seuilConfondus)
83 {
84  const OPoint3D& A = segA._ptA;
85  const OPoint3D& B = segA._ptB;
86  const OPoint3D& C = segB._ptA;
87  const OPoint3D& D = segB._ptB;
88 
89  const double ux = B._x - A._x;
90  const double uy = B._y - A._y;
91  const double uz = B._z - A._z;
92 
93  const double vx = D._x - C._x;
94  const double vy = D._y - C._y;
95  const double vz = D._z - C._z;
96 
97  // Normal of the plane spanned by the 2 segment directions.
98  const double nx = uy * vz - uz * vy;
99  const double ny = uz * vx - ux * vz;
100  const double nz = ux * vy - uy * vx;
101 
102  const double anx = std::abs(nx);
103  const double any = std::abs(ny);
104  const double anz = std::abs(nz);
105 
106  // Degenerate or quasi-parallel case: keep legacy robust behavior.
107  if ((anx <= TYSEUILCONFONDUS) && (any <= TYSEUILCONFONDUS) && (anz <= TYSEUILCONFONDUS))
108  {
109  return segA.intersects(segB, pt, seuilConfondus) != INTERS_NULLE;
110  }
111 
112  // Project to the coordinate plane where the 2D determinant is the most stable.
113  double a1, a2, u1, u2, c1, c2, v1, v2;
114 
115  if ((anx >= any) && (anx >= anz))
116  {
117  // Drop X => work in YZ
118  a1 = A._y;
119  a2 = A._z;
120  u1 = uy;
121  u2 = uz;
122  c1 = C._y;
123  c2 = C._z;
124  v1 = vy;
125  v2 = vz;
126  }
127  else if ((any >= anx) && (any >= anz))
128  {
129  // Drop Y => work in XZ
130  a1 = A._x;
131  a2 = A._z;
132  u1 = ux;
133  u2 = uz;
134  c1 = C._x;
135  c2 = C._z;
136  v1 = vx;
137  v2 = vz;
138  }
139  else
140  {
141  // Drop Z => work in XY
142  a1 = A._x;
143  a2 = A._y;
144  u1 = ux;
145  u2 = uy;
146  c1 = C._x;
147  c2 = C._y;
148  v1 = vx;
149  v2 = vy;
150  }
151 
152  const double w1 = c1 - a1;
153  const double w2 = c2 - a2;
154 
155  const double det = u1 * v2 - u2 * v1;
156 
157  // Near-parallel in projected plane: keep legacy behavior.
158  if (std::abs(det) <= TYSEUILCONFONDUS)
159  {
160  return segA.intersects(segB, pt, seuilConfondus) != INTERS_NULLE;
161  }
162 
163  const double t = (w1 * v2 - w2 * v1) / det;
164  const double s = (w1 * u2 - w2 * u1) / det;
165 
166  const double lenU = std::sqrt(ux * ux + uy * uy + uz * uz);
167  const double lenV = std::sqrt(vx * vx + vy * vy + vz * vz);
168  const double paramTol = seuilConfondus / std::max(1.0, std::max(lenU, lenV));
169 
170  if ((t < -paramTol) || (t > 1.0 + paramTol) || (s < -paramTol) || (s > 1.0 + paramTol))
171  {
172  return false;
173  }
174 
175  pt._x = A._x + t * ux;
176  pt._y = A._y + t * uy;
177  pt._z = A._z + t * uz;
178 
179  return true;
180 }
181 } // namespace
182 
184  : TYAcousticModel9613Solver(solver), _pReflectionPathFinder(nullptr), _pReflectionPruningStrategy(nullptr)
185 {
186 }
187 
189 {
191 
192  // Select reflection path finder depending on solver configuration
193  // TODO : Externalize in computation parameters
194  const std::string solverConfigPath = "C:\\projects\\tympan_tools\\17534-3\\solver_conf.txt";
195  const std::string reflectionMethod =
196  readReflectionMethodFromConfig(solverConfigPath, "IMAGE_SOURCE_METHOD");
197  if (reflectionMethod.compare("RAY_TRACING") == 0)
198  {
199  const unsigned int nbRays = readRaytracingNbRaysFromConfig(
200  solverConfigPath, 200); // TODO : Externalize in computation parameters
201  const double rcptRadius = readRaytracingRcptRadiusFromConfig(
202  solverConfigPath, 2.); // TODO : Externalize in computation parameters
203  _pReflectionPathFinder = std::make_unique<TYReflectionPathFinderART>(nbRays, rcptRadius);
204  }
205 
206  // Select pruning strategy depending on solver configuration
208  const bool enableVisibilityPruning = config->EnableVisibilityPruning;
209  if (enableVisibilityPruning)
210  {
211  _pReflectionPruningStrategy = std::make_unique<TYReflectionVisibilityPruningStrategy>();
212  }
213  else
214  {
215  _pReflectionPruningStrategy = std::make_unique<TYReflectionNoPruningStrategy>();
216  }
217 }
218 
220 {
221  // zmin = -2 * lambda / (C2 * C3)
222  OSpectreOctave zmin = _lambda * (-2.0);
223  zmin = zmin.div(C3 * C2);
224  return zmin;
225 }
226 
227 OSpectreOctave TYAcousticModel9613Solver2024::calculKmeteo(const bool vertical, const double d_SS,
228  const double d_SR, const double d, const double z,
229  const double e, const OSpectreOctave& z_min) const
230 {
231  // K_meteo = exp{-(1 / 2000) * sqrt(([max(d_SS, d_SR) + e] * min(d_SS, d_SR) * d) / [2 * (z - z_min)])}
232  // for vertical diffraction K_meteo = 1 for lateral diffraction
233  //
234  // This is not specified explicitly in the standard, but we also set:
235  // K_meteo = 1 when z < z_min
236  // which avoids a division by zero and has no effect on the computation of Dz
237 
238  OSpectreOctave K_meteo{1.0};
239 
240  if (!vertical)
241  {
242  return K_meteo;
243  }
244 
245  double* kMeteo = K_meteo.getTabValReel();
246  const double* zMin = z_min.getTabValReel();
247 
248  const double dMax = std::max(d_SS, d_SR);
249  const double dMin = std::min(d_SS, d_SR);
250  const double numerator = (dMax + e) * dMin * d;
251 
252  for (std::size_t i = 0; i < TY_SPECTRE_OCT_NB_ELMT; ++i)
253  {
254  if (z > zMin[i])
255  {
256  kMeteo[i] = std::exp(-(1.0 / 2000.0) * std::sqrt(numerator / (2.0 * (z - zMin[i]))));
257  }
258  }
259 
260  return K_meteo;
261 }
262 
264  const OSpectreOctave& C3, const OSpectreOctave& Kmeteo,
265  const OSpectreOctave& zmin) const
266 {
267  // Dz = 10 * log10[1 + (2 + (C2 / lambda) * C3 * z) * Kmeteo] dB for z > zmin
268  // Dz = 0 dB for z <= zmin
269 
270  OSpectreOctave Dz{0.0};
271 
272  double* dz = Dz.getTabValReel();
273  const double* lambda = _lambda.getTabValReel();
274  const double* c3 = C3.getTabValReel();
275  const double* kmeteo = Kmeteo.getTabValReel();
276  const double* zMin = zmin.getTabValReel();
277 
278  for (std::size_t i = 0; i < TY_SPECTRE_OCT_NB_ELMT; ++i)
279  {
280  if (z > zMin[i])
281  {
282  const double term = 2.0 + (C2 / lambda[i]) * c3[i] * z;
283  dz[i] = 10.0 * std::log10(1.0 + term * kmeteo[i]);
284  }
285  }
286 
287  return Dz;
288 }
289 
290 void TYAcousticModel9613Solver2024::computeCheminReflexion(const std::deque<TYSIntersection>& tabIntersect,
291  const OSegment3D& ray,
292  const tympan::AcousticSource& source,
293  TYTabChemin9613Solver& TabChemins,
294  double distance) const
295 {
296  // Multiple reflection order
298  const size_t multipleReflectionOrder = config->ReflectionOrder;
299 
300  if (multipleReflectionOrder == 0)
301  {
302  return;
303  }
304 
306  {
307  // use the TYAbstractReflectionPathFinder interface
308  std::unique_ptr<TYAbstractReflectionPathFinder> pReflectionPathFinderInstance =
309  _pReflectionPathFinder->instanciate();
310 
311  pReflectionPathFinderInstance->setup(multipleReflectionOrder, tabIntersect, ray._ptA, ray._ptB);
312 
313  while (pReflectionPathFinderInstance->remainingPaths())
314  {
315  TYReflectionPath reflectionPath = pReflectionPathFinderInstance->popPath();
316 
317  // imageSourcesList is introduced to use existing interface of buildReflectionPath
318  // only its length is used
319  std::deque<OPoint3D> imageSourcesList;
320  for (size_t i = 0; i < reflectionPath.reflectingSegments.size() + 1; i++)
321  {
322  imageSourcesList.emplace_back();
323  }
324 
325  // the path is assumed to be valid, thus it is directly built
326  buildReflectionPath(reflectionPath.reflectingSegments, imageSourcesList,
327  reflectionPath.reflectionPoints, ray, source, TabChemins, distance);
328  }
329  }
330  else
331  {
332  // historical code for image source method
333  // TODO: implement it as a TYReflectionPathFinder
334  computeCheminReflectionImageSourceMethod(multipleReflectionOrder, tabIntersect, ray, source,
335  TabChemins, distance);
336  }
337 }
338 
340  size_t multipleReflectionOrder, const std::deque<TYSIntersection>& tabIntersect, const OSegment3D& ray,
341  const tympan::AcousticSource& source, TYTabChemin9613Solver& TabChemins, double distance) const
342 {
343  std::vector<ReflectingSegmentCache> reflectingSegments;
344  reflectingSegments.reserve(tabIntersect.size());
345 
346  // Keep only barriers that are both infrastructure and intersecting the EL plane.
347  // Their support-line geometry is cached once here, then reused during the DFS.
348  for (const auto& inter : tabIntersect)
349  {
350  if (inter.isInfra && inter.bIntersect[1])
351  {
352  reflectingSegments.push_back(makeReflectingSegmentCache(inter));
353  }
354  }
355 
356  if (reflectingSegments.empty())
357  {
358  return;
359  }
360 
361  std::vector<const TYSIntersection*> currentCombination;
362  currentCombination.reserve(multipleReflectionOrder);
363 
364  std::deque<OPoint3D> currentImageSources;
365  currentImageSources.push_back(ray._ptA);
366 
367  // Streaming exploration of ordered reflection combinations.
368  // Each valid prefix is turned directly into an acoustic path, avoiding the
369  // construction of an intermediate global set of combinations/candidates.
370  buildReflectionPathsStreaming(multipleReflectionOrder, reflectingSegments, currentCombination,
371  currentImageSources, tabIntersect, ray, source, TabChemins, distance);
372 }
373 
375  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
376  const std::deque<OPoint3D>& pathPoints2D, double hs, double hr, double& Gs, double& Gm, double& Gr) const
377 {
378  Gs = 0.5;
379  Gm = 0.5;
380  Gr = 0.5;
381 
382  if (!computeGroundFactorSourceZone(tabIntersectSegments, pathPoints2D, hs, Gs))
383  {
384  return false;
385  }
386 
387  if (!computeGroundFactorMiddleZone(tabIntersectSegments, pathPoints2D, hs, hr, Gm))
388  {
389  return false;
390  }
391 
392  if (!computeGroundFactorReceiverZone(tabIntersectSegments, pathPoints2D, hr, Gr))
393  {
394  return false;
395  }
396 
397  return true;
398 }
399 
401  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
402  const std::deque<OPoint3D>& pathPoints2D, double hs, double& Gs) const
403 {
404  double heightRatio = 30.0;
405  Gs = 0.5;
406 
407  if (pathPoints2D.size() < 2)
408  {
409  return false;
410  }
411 
412  if (tabIntersectSegments.size() != pathPoints2D.size() - 1)
413  {
414  return false;
415  }
416 
417  const double srcZoneLength = heightRatio * hs;
418 
419  // Same fallback behavior as legacy code.
420  if (srcZoneLength <= TYSEUILCONFONDUS)
421  {
422  Gs = 0.5;
423  return true;
424  }
425 
426  double traversedLength = 0.0; // curvilinear length along the broken path
427  double coveredLength = 0.0; // sum of dp returned by computeGZone
428  double weightedGroundSum = 0.0;
429 
430  for (size_t i = 0; i + 1 < pathPoints2D.size(); ++i)
431  {
432  const OPoint3D& ptA = pathPoints2D[i];
433  const OPoint3D& ptB = pathPoints2D[i + 1];
434 
435  const OSegment3D currentSegment(ptA, ptB);
436  const double currentSegmentLength = currentSegment.longueur();
437 
438  if (currentSegmentLength <= TYSEUILCONFONDUS)
439  {
440  continue;
441  }
442 
443  const double remainingLength = srcZoneLength - traversedLength;
444 
445  if (remainingLength <= TYSEUILCONFONDUS)
446  {
447  break;
448  }
449 
450  OPoint3D ptEndZone = ptB;
451 
452  // The source-zone limit lies inside the current segment.
453  if (remainingLength < currentSegmentLength)
454  {
455  const double alpha = remainingLength / currentSegmentLength;
456 
457  ptEndZone._x = ptA._x + alpha * (ptB._x - ptA._x);
458  ptEndZone._y = ptA._y + alpha * (ptB._y - ptA._y);
459  ptEndZone._z = ptA._z + alpha * (ptB._z - ptA._z);
460 
461  double GCurSeg = 0.0;
462  double dpCurSeg = 0.0;
463  computeGZone(ptA, ptEndZone, GCurSeg, dpCurSeg, tabIntersectSegments[i]);
464 
465  weightedGroundSum += GCurSeg;
466  coveredLength += dpCurSeg;
467  traversedLength = srcZoneLength;
468 
469  break;
470  }
471 
472  // The whole current segment belongs to the source zone.
473  double GCurSeg = 0.0;
474  double dpCurSeg = 0.0;
475  computeGZone(ptA, ptB, GCurSeg, dpCurSeg, tabIntersectSegments[i]);
476 
477  weightedGroundSum += GCurSeg;
478  coveredLength += dpCurSeg;
479  traversedLength += currentSegmentLength;
480  }
481 
482  if (coveredLength > TYSEUILCONFONDUS)
483  {
484  Gs = weightedGroundSum / coveredLength;
485  }
486  else
487  {
488  Gs = 0.5;
489  }
490 
491  return true;
492 }
493 
495  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
496  const std::deque<OPoint3D>& pathPoints2D, double hr, double& Gr) const
497 {
498  double heightRatio = 30.0;
499  Gr = 0.5;
500 
501  if (pathPoints2D.size() < 2)
502  {
503  return false;
504  }
505 
506  if (tabIntersectSegments.size() != pathPoints2D.size() - 1)
507  {
508  return false;
509  }
510 
511  const double rcpZoneLength = heightRatio * hr;
512 
513  // Same fallback behavior as legacy code.
514  if (rcpZoneLength <= TYSEUILCONFONDUS)
515  {
516  Gr = 0.5;
517  return true;
518  }
519 
520  double traversedLength = 0.0; // curvilinear length traversed backward from receiver
521  double coveredLength = 0.0; // sum of dp returned by computeGZone
522  double weightedGroundSum = 0.0;
523 
524  for (size_t i = pathPoints2D.size() - 1; i > 0; --i)
525  {
526  const OPoint3D& ptA = pathPoints2D[i - 1];
527  const OPoint3D& ptB = pathPoints2D[i];
528 
529  const OSegment3D currentSegment(ptA, ptB);
530  const double currentSegmentLength = currentSegment.longueur();
531 
532  if (currentSegmentLength <= TYSEUILCONFONDUS)
533  {
534  continue;
535  }
536 
537  const double remainingLength = rcpZoneLength - traversedLength;
538 
539  if (remainingLength <= TYSEUILCONFONDUS)
540  {
541  break;
542  }
543 
544  // The receiver-zone limit lies inside the current segment.
545  if (remainingLength < currentSegmentLength)
546  {
547  const double alpha = remainingLength / currentSegmentLength;
548 
549  // Start point of the receiver zone on the current segment,
550  // located at distance "remainingLength" from ptB toward ptA.
551  OPoint3D ptStartZone;
552  ptStartZone._x = ptB._x + alpha * (ptA._x - ptB._x);
553  ptStartZone._y = ptB._y + alpha * (ptA._y - ptB._y);
554  ptStartZone._z = ptB._z + alpha * (ptA._z - ptB._z);
555 
556  double GCurSeg = 0.0;
557  double dpCurSeg = 0.0;
558  computeGZone(ptStartZone, ptB, GCurSeg, dpCurSeg, tabIntersectSegments[i - 1]);
559 
560  weightedGroundSum += GCurSeg;
561  coveredLength += dpCurSeg;
562  traversedLength = rcpZoneLength;
563 
564  break;
565  }
566 
567  // The whole current segment belongs to the receiver zone.
568  double GCurSeg = 0.0;
569  double dpCurSeg = 0.0;
570  computeGZone(ptA, ptB, GCurSeg, dpCurSeg, tabIntersectSegments[i - 1]);
571 
572  weightedGroundSum += GCurSeg;
573  coveredLength += dpCurSeg;
574  traversedLength += currentSegmentLength;
575  }
576 
577  if (coveredLength > TYSEUILCONFONDUS)
578  {
579  Gr = weightedGroundSum / coveredLength;
580  }
581  else
582  {
583  Gr = 0.5;
584  }
585 
586  return true;
587 }
588 
590  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
591  const std::deque<OPoint3D>& pathPoints2D, double hs, double hr, double& Gm) const
592 {
593  double heightRatio = 30.0;
594  Gm = 0.5;
595 
596  if (pathPoints2D.size() < 2)
597  {
598  return false;
599  }
600 
601  if (tabIntersectSegments.size() != pathPoints2D.size() - 1)
602  {
603  return false;
604  }
605 
606  const double srcZoneLength = heightRatio * hs;
607  const double rcpZoneLength = heightRatio * hr;
608 
609  // Compute total curvilinear length of the broken path.
610  double dp = 0.0;
611  for (size_t i = 0; i + 1 < pathPoints2D.size(); ++i)
612  {
613  dp += OSegment3D(pathPoints2D[i], pathPoints2D[i + 1]).longueur();
614  }
615 
616  // No middle zone when source and receiver zones touch or overlap.
617  if ((srcZoneLength + rcpZoneLength) >= (dp - TYSEUILCONFONDUS))
618  {
619  Gm = 0.5;
620  return true;
621  }
622 
623  const double middleZoneBegin = srcZoneLength;
624  const double middleZoneEnd = dp - rcpZoneLength;
625 
626  double traversedLength = 0.0; // curvilinear abscissa at segment start
627  double coveredLength = 0.0; // sum of dp returned by computeGZone
628  double weightedGroundSum = 0.0;
629 
630  for (size_t i = 0; i + 1 < pathPoints2D.size(); ++i)
631  {
632  const OPoint3D& ptA = pathPoints2D[i];
633  const OPoint3D& ptB = pathPoints2D[i + 1];
634 
635  const OSegment3D currentSegment(ptA, ptB);
636  const double currentSegmentLength = currentSegment.longueur();
637 
638  if (currentSegmentLength <= TYSEUILCONFONDUS)
639  {
640  continue;
641  }
642 
643  const double segmentBegin = traversedLength;
644  const double segmentEnd = traversedLength + currentSegmentLength;
645 
646  // Overlap between current segment and middle zone in curvilinear abscissa.
647  const double overlapBegin = std::max(segmentBegin, middleZoneBegin);
648  const double overlapEnd = std::min(segmentEnd, middleZoneEnd);
649 
650  if ((overlapEnd - overlapBegin) > TYSEUILCONFONDUS)
651  {
652  const double alphaBegin = (overlapBegin - segmentBegin) / currentSegmentLength;
653  const double alphaEnd = (overlapEnd - segmentBegin) / currentSegmentLength;
654 
655  OPoint3D ptZoneBegin;
656  ptZoneBegin._x = ptA._x + alphaBegin * (ptB._x - ptA._x);
657  ptZoneBegin._y = ptA._y + alphaBegin * (ptB._y - ptA._y);
658  ptZoneBegin._z = ptA._z + alphaBegin * (ptB._z - ptA._z);
659 
660  OPoint3D ptZoneEnd;
661  ptZoneEnd._x = ptA._x + alphaEnd * (ptB._x - ptA._x);
662  ptZoneEnd._y = ptA._y + alphaEnd * (ptB._y - ptA._y);
663  ptZoneEnd._z = ptA._z + alphaEnd * (ptB._z - ptA._z);
664 
665  double GCurSeg = 0.0;
666  double dpCurSeg = 0.0;
667  computeGZone(ptZoneBegin, ptZoneEnd, GCurSeg, dpCurSeg, tabIntersectSegments[i]);
668 
669  weightedGroundSum += GCurSeg;
670  coveredLength += dpCurSeg;
671  }
672 
673  traversedLength = segmentEnd;
674  }
675 
676  if (coveredLength > TYSEUILCONFONDUS)
677  {
678  Gm = weightedGroundSum / coveredLength;
679  }
680  else
681  {
682  Gm = 0.5;
683  }
684 
685  return true;
686 }
687 
689  const TYSIntersection& rhs) const
690 {
691  const OSegment3D& seg1 = lhs.segInter[1];
692  const OSegment3D& seg2 = rhs.segInter[1];
693 
694  const bool sameOrder = (seg1._ptA == seg2._ptA) && (seg1._ptB == seg2._ptB);
695 
696  const bool reverseOrder = (seg1._ptA == seg2._ptB) && (seg1._ptB == seg2._ptA);
697 
698  return sameOrder || reverseOrder;
699 }
700 
702  const std::vector<const TYSIntersection*>& currentCombination,
703  const std::deque<OPoint3D>& imageSourcesList, const OPoint3D& receptorPoint,
704  std::deque<OPoint3D>& reflectionPointsList) const
705 {
706  reflectionPointsList.clear();
707 
708  if (currentCombination.empty())
709  {
710  return true;
711  }
712 
713  // By convention:
714  // imageSourcesList[0] = S0 = source point
715  // imageSourcesList[i] = image source after i reflections
716  if (imageSourcesList.size() != currentCombination.size() + 1)
717  {
718  return false;
719  }
720 
721  OPoint3D nextPoint = receptorPoint; // P(n+1) = R
722 
723  // Reflection points are reconstructed backward:
724  // starting from the receptor, intersect the current image ray with the
725  // corresponding reflecting segment, then continue with the previous order.
726  for (int i = static_cast<int>(currentCombination.size()) - 1; i >= 0; --i)
727  {
728  const OPoint3D& currentImageSource = imageSourcesList[i + 1]; // Si
729  const OSegment3D& currentBarrier = currentCombination[i]->segInter[1]; // Bi
730 
731  OPoint3D currentReflectionPoint;
732 
733  // Intersection must be computed on segments, not on infinite lines.
734  if (!intersectSegmentsFastInTheirPlane(currentBarrier, OSegment3D(currentImageSource, nextPoint),
735  currentReflectionPoint, TYSEUILCONFONDUS))
736  {
737  reflectionPointsList.clear();
738  return false;
739  }
740 
741  reflectionPointsList.push_front(currentReflectionPoint);
742  nextPoint = currentReflectionPoint;
743  }
744 
745  return true;
746 }
747 
749  const std::vector<const TYSIntersection*>& barrierCombination,
750  const std::deque<OPoint3D>& reflectionPointsList, const std::deque<TYSIntersection>& tabIntersect,
751  const OPoint3D& sourcePoint, const OPoint3D& receptorPoint) const
752 {
753  const size_t reflectionOrder = barrierCombination.size();
754 
755  if (reflectionPointsList.size() != reflectionOrder)
756  {
757  return false;
758  }
759 
760  std::deque<OPoint3D> pathPoints;
761  pathPoints.push_back(sourcePoint);
762  for (const auto& point : reflectionPointsList)
763  {
764  pathPoints.push_back(point);
765  }
766  pathPoints.push_back(receptorPoint);
767 
768  // For each leg [Pi, P(i+1)], only the reflecting barriers on which belong Pi or P(i+1) are allowed to
769  // touch the path. Any other barrier intersection invalidates the candidate.
770  for (size_t i = 0; i <= reflectionOrder; ++i)
771  {
772  const OSegment3D pathSegment(pathPoints[i], pathPoints[i + 1]);
773 
774  for (const auto& sceneBarrier : tabIntersect)
775  {
776  if ((i >= 1) && sameReflectingSegment(sceneBarrier, *barrierCombination[i - 1]))
777  {
778  continue;
779  }
780 
781  if ((i < reflectionOrder) && sameReflectingSegment(sceneBarrier, *barrierCombination[i]))
782  {
783  continue;
784  }
785 
786  OPoint3D intersectionPoint;
787  if (sceneBarrier.segInter[1].intersects(pathSegment, intersectionPoint, TYSEUILCONFONDUS))
788  {
789  return false;
790  }
791  }
792  }
793 
794  return true;
795 }
796 
798  const std::vector<const TYSIntersection*>& barrierCombination,
799  const std::deque<OPoint3D>& imageSourcesList, const std::deque<OPoint3D>& reflectionPointsList,
800  const OSegment3D& directRay, const tympan::AcousticSource& source, TYTabChemin9613Solver& TabChemins,
801  double distance) const
802 {
803  const size_t reflectionOrder = barrierCombination.size();
804 
805  if (reflectionOrder == 0)
806  {
807  return false;
808  }
809 
810  if (imageSourcesList.size() != reflectionOrder + 1)
811  {
812  return false;
813  }
814 
815  if (reflectionPointsList.size() != reflectionOrder)
816  {
817  return false;
818  }
819 
820  // Build path points:
821  // P0 = S
822  // P1 ... Pn = reflection points
823  // P(n+1) = R
824  std::deque<OPoint3D> pathPoints;
825  std::deque<OPoint3D> pathPoints2D;
826  std::deque<double> sourceReflectionPointLengths;
827  std::deque<double> reflectionPointReceptorLengths;
828 
829  pathPoints.push_back(directRay._ptA);
830 
831  for (const auto& point : reflectionPointsList)
832  {
833  pathPoints.push_back(point);
834  }
835 
836  pathPoints.push_back(directRay._ptB);
837 
838  TYTabEtape9613Solver tabEtapes;
839  double pathLength = 0.0;
840  double dp = 0.0;
841 
842  OPoint3D A2D;
843  OPoint3D B2D;
844  double segLength = 0.0;
845 
846  for (size_t i = 0; i + 1 < pathPoints.size(); ++i)
847  {
848  OSegment3D segment(pathPoints[i], pathPoints[i + 1]);
849  segLength = segment.longueur();
850  pathLength += segLength;
851  if (i < pathPoints.size() - 2)
852  {
853  sourceReflectionPointLengths.push_back(pathLength);
854  reflectionPointReceptorLengths.push_back(-pathLength);
855  }
856  A2D = OPoint3D{segment._ptA._x, segment._ptA._y, 0.0};
857  B2D = OPoint3D{segment._ptB._x, segment._ptB._y, 0.0};
858 
859  // dp is the broken-path length projected in the horizontal plane.
860  dp += OSegment3D{A2D, B2D}.longueur();
861  pathPoints2D.push_back(A2D);
862  }
863  pathPoints2D.push_back(B2D);
864 
865  for (size_t i = 0; i < reflectionOrder; ++i)
866  {
867  reflectionPointReceptorLengths[i] += pathLength;
868  }
869 
870  {
871  TYEtape9613Solver etape;
872  etape._pt = pathPoints[0];
873  etape._type = TYSOURCE;
874 
875  const OSegment3D firstLeg(pathPoints[0], pathPoints[1]);
876  etape._Absorption =
877  source.directivity->lwAdjustment(OVector3D(firstLeg._ptA, firstLeg._ptB), firstLeg.longueur());
878 
879  tabEtapes.push_back(etape);
880  }
881 
882  for (size_t i = 0; i < reflectionOrder; ++i)
883  {
885  dynamic_cast<tympan::AcousticBuildingMaterial*>(barrierCombination[i]->material);
886 
887  if (material == nullptr)
888  {
889  return false;
890  }
891 
892  if (!barrierCombination[i]->pFaceGeomData)
893  {
894  return false;
895  }
896 
897  TYEtape9613Solver etape;
898  etape._pt = reflectionPointsList[i];
899  etape._type = TYREFLEXION;
900  etape._Absorption = material->spectrum;
901 
902  tabEtapes.push_back(etape);
903  }
904 
905  OSegment3D segMeanSlope;
906  meanSlope(directRay, segMeanSlope);
907 
908  double hs{0.0}, hr{0.0};
909  computeSegmentEdgesHeights(hs, hr, segMeanSlope, directRay);
910 
911  double Gs{0.0}, Gm{0.0}, Gr{0.0};
912 
913  // Recompute the scene intersections for each broken-path leg [Pi, P(i+1)].
914  // Ground factors must be evaluated on the reflected path, not on the direct ray.
915  std::deque<std::deque<TYSIntersection>> tabIntersectSegments;
916  OSegment3D seg;
917  tabIntersectSegments.resize(reflectionOrder + 1);
918  for (size_t i = 0; i < reflectionOrder + 1; ++i)
919  {
920  seg = OSegment3D{pathPoints[i], pathPoints[i + 1]};
921  _solver.selectFaces(tabIntersectSegments[i], seg, source.volume_id);
922  }
923 
924  getGroundfactors(tabIntersectSegments, pathPoints2D, hs, hr, Gs, Gm, Gr);
925 
926  std::unique_ptr<TYChemin9613Solver> chemin = createChemin();
927  chemin->setType(TYTypeChemin::CHEMIN_REFLEX);
928  chemin->setLongueur(pathLength);
929  chemin->setDistance(distance);
930  chemin->calcAttenuation(tabEtapes, *_pSolverAtmos, dp, hs, hr, Gs, Gm, Gr);
931 
932  // The minimal extension condition is evaluated reflection by reflection on
933  // the broken reflected path.
934  OSpectreOctave filter{1.}, curFilter{0.};
935  for (size_t i = 0; i < reflectionOrder; ++i)
936  {
937  const OPoint3D& Oprev = pathPoints[i];
938  const OPoint3D& O = pathPoints[i + 1];
939 
940  const double a = barrierCombination[i]->pFaceGeomData->a;
941  const double h = barrierCombination[i]->pFaceGeomData->h;
942  const OVector3D& normal = barrierCombination[i]->pFaceGeomData->n;
943  double d_SO = sourceReflectionPointLengths[i];
944  double d_OR = reflectionPointReceptorLengths[i];
945  curFilter = chemin->calcMinimalExtensionConditionOneReflection(Oprev, O, d_SO, d_OR, a, h, normal);
946  filter = filter * curFilter;
947  chemin->setMinimalExtensionConditionReflection(filter);
948  }
949 
950  // Evaluate the attenuation due to a reflection on a cylinder if needed.
951  // 9613-2:2024 states "Reflections of order > 1 are not considered with curved surfaces.", so tracks
952  // verifying this criterion are filtered
953  bool reflectionOnCylinder = false;
954  for (const TYSIntersection* pBarrier : barrierCombination)
955  {
956  if (dynamic_cast<tympan::AcousticFaceGeomDataCylinder*>(pBarrier->pFaceGeomData.get()) != nullptr)
957  {
958  reflectionOnCylinder = true;
959  }
960  }
961  if (reflectionOnCylinder)
962  {
963  if (reflectionOrder == 1)
964  {
965  boost::shared_ptr<tympan::AcousticFaceGeomDataCylinder> pFaceGeomDataCylinder =
966  boost::dynamic_pointer_cast<tympan::AcousticFaceGeomDataCylinder,
968  barrierCombination[0]->pFaceGeomData);
969  const OPoint3D& S{pathPoints[0]};
970  const OPoint3D& P{pathPoints[1]};
971  const OPoint3D& R{pathPoints[2]};
972  const OPoint3D& M{pFaceGeomDataCylinder->M};
973  const double r{pFaceGeomDataCylinder->r};
974  const OVector3D& axis{pFaceGeomDataCylinder->axis};
975  chemin->calcCylinderReflectionAttenuation(S, R, P, M, r, axis);
976  }
977  else
978  {
979  return false;
980  }
981  }
982 
983  TabChemins.push_back(*chemin);
984  return true;
985 }
986 
989 {
991  cache.barrier = &inter;
992 
993  const OSegment3D& seg = inter.segInter[1];
994 
995  cache.ax = seg._ptA._x;
996  cache.ay = seg._ptA._y;
997  cache.az = seg._ptA._z;
998 
999  cache.ux = seg._ptB._x - seg._ptA._x;
1000  cache.uy = seg._ptB._y - seg._ptA._y;
1001  cache.uz = seg._ptB._z - seg._ptA._z;
1002 
1003  // The cache stores the support line of the reflecting segment.
1004  // invNorm2 is used to project points on this line without recomputing the
1005  // segment norm at each recursive step.
1006  const double norm2 = cache.ux * cache.ux + cache.uy * cache.uy + cache.uz * cache.uz;
1007  if (norm2 > TYSEUILCONFONDUS * TYSEUILCONFONDUS)
1008  {
1009  cache.invNorm2 = 1.0 / norm2;
1010  }
1011  else
1012  {
1013  cache.invNorm2 = 0.0;
1014  }
1015 
1016  return cache;
1017 }
1018 
1020  const OPoint3D& inputPoint,
1021  OPoint3D& reflectedPoint) const
1022 {
1023  // Keep legacy behavior for degenerate cases.
1024  if ((cache.barrier == nullptr) || (cache.invNorm2 <= 0.0))
1025  {
1026  if (cache.barrier != nullptr)
1027  {
1028  cache.barrier->segInter[1].symetrieOf(inputPoint, reflectedPoint);
1029  }
1030  return;
1031  }
1032 
1033  const double apx = inputPoint._x - cache.ax;
1034  const double apy = inputPoint._y - cache.ay;
1035  const double apz = inputPoint._z - cache.az;
1036 
1037  const double t = (apx * cache.ux + apy * cache.uy + apz * cache.uz) * cache.invNorm2;
1038 
1039  const double hx = cache.ax + t * cache.ux;
1040  const double hy = cache.ay + t * cache.uy;
1041  const double hz = cache.az + t * cache.uz;
1042 
1043  // Reflection is performed about the support line of the segment in plane EL.
1044  reflectedPoint._x = 2.0 * hx - inputPoint._x;
1045  reflectedPoint._y = 2.0 * hy - inputPoint._y;
1046  reflectedPoint._z = 2.0 * hz - inputPoint._z;
1047 }
1048 
1050  size_t reflectionOrder, const std::vector<ReflectingSegmentCache>& reflectingSegments,
1051  std::vector<const TYSIntersection*>& currentCombination, std::deque<OPoint3D>& currentImageSources,
1052  const std::deque<TYSIntersection>& tabIntersect, const OSegment3D& ray,
1053  const tympan::AcousticSource& source, TYTabChemin9613Solver& TabChemins, double distance) const
1054 {
1055  if (currentCombination.size() == reflectionOrder)
1056  {
1057  return;
1058  }
1059 
1060  const OPoint3D& previousImageSource = currentImageSources.back();
1061 
1062  // Instantiate a new copy of the pruning strategy and provide it the current tree state
1063  std::unique_ptr<TYAbstractReflectionPruningStrategy> pPruningStrategyInstance =
1064  _pReflectionPruningStrategy->instanciate();
1065  pPruningStrategyInstance->initialize(currentCombination, currentImageSources);
1066 
1067  for (const auto& segment : reflectingSegments)
1068  {
1069  // Only consecutive reuse of the same reflecting segment is forbidden.
1070  if (!currentCombination.empty() && currentCombination.back() == segment.barrier)
1071  {
1072  continue;
1073  }
1074 
1075  // Check if it is possible to prune the tree
1076  if (pPruningStrategyInstance->pruningCriterionMet(*segment.barrier))
1077  {
1078  continue;
1079  }
1080 
1081  OPoint3D nextImageSource;
1082  reflectPointAboutCachedLine(segment, previousImageSource, nextImageSource);
1083 
1084  currentCombination.push_back(segment.barrier);
1085  currentImageSources.push_back(nextImageSource);
1086 
1087  // currentImageSources always stores:
1088  // S0 = source point, then one image source per current reflection.
1089  buildReflectionPathForCombination(currentCombination, currentImageSources, tabIntersect, ray, source,
1090  TabChemins, distance);
1091 
1092  buildReflectionPathsStreaming(reflectionOrder, reflectingSegments, currentCombination,
1093  currentImageSources, tabIntersect, ray, source, TabChemins, distance);
1094 
1095  currentImageSources.pop_back();
1096  currentCombination.pop_back();
1097  }
1098 }
1099 
1101  const std::vector<const TYSIntersection*>& currentCombination,
1102  const std::deque<OPoint3D>& imageSourcesList, const std::deque<TYSIntersection>& tabIntersect,
1103  const OSegment3D& ray, const tympan::AcousticSource& source, TYTabChemin9613Solver& TabChemins,
1104  double distance) const
1105 {
1106  std::deque<OPoint3D> reflectionPointsList;
1107 
1108  // Geometry is built in 3 stages:
1109  // 1. reconstruct reflection points from current image sources,
1110  // 2. validate the broken path against the scene,
1111  // 3. build the acoustic path only for valid combinations.
1112  if (!buildReflectionPoints(currentCombination, imageSourcesList, ray._ptB, reflectionPointsList))
1113  {
1114  return false;
1115  }
1116 
1117  if (!validateReflectionCandidate(currentCombination, reflectionPointsList, tabIntersect, ray._ptA,
1118  ray._ptB))
1119  {
1120  return false;
1121  }
1122 
1123  return buildReflectionPath(currentCombination, imageSourcesList, reflectionPointsList, ray, source,
1124  TabChemins, distance);
1125 }
#define TYSEUILCONFONDUS
Definition: 3d.h:47
#define INTERS_NULLE
No intersection.
Definition: 3d.h:35
NxReal s
Definition: NxVec3.cpp:317
std::pair< unsigned int, unsigned int > segment
#define min(a, b)
std::deque< TYChemin9613Solver > TYTabChemin9613Solver
TYChemin collection.
std::deque< TYEtape9613Solver > TYTabEtape9613Solver
TYEtape collection.
@ TYREFLEXION
Definition: acoustic_path.h:25
@ TYSOURCE
Definition: acoustic_path.h:28
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
The 3D point class.
Definition: 3d.h:487
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 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 & div(const OSpectreAbstract &spectre) const
Division of two spectrums.
Definition: spectre.cpp:278
double * getTabValReel() override
Get an array of the real values of the spectrum.
Definition: spectre.h:614
The 3D vector class.
Definition: 3d.h:298
TYAcousticModel9613Solver2024(TYSolver9613Solver2024 &solver)
bool validateReflectionCandidate(const std::vector< const TYSIntersection * > &barrierCombination, const std::deque< OPoint3D > &reflectionPointsList, const std::deque< TYSIntersection > &tabIntersect, const OPoint3D &sourcePoint, const OPoint3D &receptorPoint) const
Validate a reflection candidate against the reflecting segments of the scene. A reflection candidate ...
bool computeGroundFactorMiddleZone(const std::deque< std::deque< TYSIntersection >> &tabIntersectSegments, const std::deque< OPoint3D > &pathPoints2D, double hs, double hr, double &Gm) const
Compute the ground factor of the middle zone for a reflected path.
std::unique_ptr< TYChemin9613Solver > createChemin() const override
bool sameReflectingSegment(const TYSIntersection &lhs, const TYSIntersection &rhs) const
Check whether two reflecting segments are identical in plane EL.
ReflectingSegmentCache makeReflectingSegmentCache(const TYSIntersection &inter) const
Build the geometric cache associated with one reflecting segment.
void buildReflectionPathsStreaming(size_t reflectionOrder, const std::vector< ReflectingSegmentCache > &reflectingSegments, std::vector< const TYSIntersection * > &currentCombination, std::deque< OPoint3D > &currentImageSources, const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &ray, const tympan::AcousticSource &source, TYTabChemin9613Solver &TabChemins, double distance) const
Recursively build and validate reflection paths in streaming mode.
OSpectreOctave calculZMin(const double C2, const OSpectreOctave &C3) const override
Compute zmin, the min value of z for which the barrier attenuation Dz is null. This minimum distance ...
void computeCheminReflexion(const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &ray, const tympan::AcousticSource &source, TYTabChemin9613Solver &TabChemins, double distance) const override
Compute the list of path generated by reflection on the vertical walls.
void reflectPointAboutCachedLine(const ReflectingSegmentCache &cache, const OPoint3D &inputPoint, OPoint3D &reflectedPoint) const
Reflect a point about the support line stored in a reflecting segment cache.
bool getGroundfactors(const std::deque< std::deque< TYSIntersection >> &tabIntersectSegments, const std::deque< OPoint3D > &pathPoints2D, double hs, double hr, double &Gs, double &Gm, double &Gr) const
Get ground factors for source, middle and receptor zones for a reflected path.
bool computeGroundFactorReceiverZone(const std::deque< std::deque< TYSIntersection >> &tabIntersectSegments, const std::deque< OPoint3D > &pathPoints2D, double hr, double &Gr) const
Compute the ground factor of the receptor zone for a reflected path.
bool computeGroundFactorSourceZone(const std::deque< std::deque< TYSIntersection >> &tabIntersectSegments, const std::deque< OPoint3D > &pathPoints2D, double hs, double &Gs) const
Compute the ground factor of the source zone for a reflected path.
bool buildReflectionPathForCombination(const std::vector< const TYSIntersection * > &currentCombination, const std::deque< OPoint3D > &imageSourcesList, const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &ray, const tympan::AcousticSource &source, TYTabChemin9613Solver &TabChemins, double distance) const
Build a reflection path from the current reflecting segment combination.
void init() override
Initialize the acoustic model.
OSpectreOctave calculDz(const double z, const double C2, const OSpectreOctave &C3, const OSpectreOctave &Kmeteo, const OSpectreOctave &zmin) const override
Compute Dz, the barrier attenuation for each octave band in dB.
bool buildReflectionPath(const std::vector< const TYSIntersection * > &barrierCombination, const std::deque< OPoint3D > &imageSourcesList, const std::deque< OPoint3D > &reflectionPointsList, const OSegment3D &directRay, const tympan::AcousticSource &source, TYTabChemin9613Solver &TabChemins, double distance) const
Build a reflection path from a valid reflecting segment combination.
bool buildReflectionPoints(const std::vector< const TYSIntersection * > &currentCombination, const std::deque< OPoint3D > &imageSourcesList, const OPoint3D &receptorPoint, std::deque< OPoint3D > &reflectionPointsList) const
Build the list of reflection points associated with a reflecting segment combination.
std::unique_ptr< TYAbstractReflectionPruningStrategy > _pReflectionPruningStrategy
OSpectreOctave calculKmeteo(const bool vertical, const double d_SS, const double d_SR, const double d, const double z, const double e, const OSpectreOctave &z_min) const override
Compute Kmeteo, the correction factor for meteorological effects.
std::unique_ptr< TYAbstractReflectionPathFinder > _pReflectionPathFinder
void computeCheminReflectionImageSourceMethod(size_t multipleReflectionOrder, const std::deque< TYSIntersection > &tabIntersect, const OSegment3D &ray, const tympan::AcousticSource &source, TYTabChemin9613Solver &TabChemins, double distance) const
Compute the list of paths generated by multiple reflections in EL-plane using the Image Source Method...
Acoustic model for the 9613Solver.
virtual void init() override
Initialize the acoustic model.
TYSolver9613Solver & _solver
Reference to the solver.
bool computeGZone(const OPoint3D &ptDebut, const OPoint3D &ptFin, double &GZone, double &dpZone, const std::deque< TYSIntersection > &tabIntersect) const
Compute GZone and dpZone for the segment between ptDebut and ptFin.
bool computeSegmentEdgesHeights(double &hauteurA, double &hauteurB, const OSegment3D &meanSlope, const OSegment3D &ray) const
Compute heights relative to real ground, of the edges of a segment.
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.
OSpectreOctave _Absorption
absorption Spectrum
OPoint3D _pt
The starting point of this step.
Definition: TYEtape.h:109
ACOUSTIC_EVENT_TYPES _type
Acoustic event type.
Definition: TYEtape.h:108
9613 Solver version 2024
void selectFaces(std::deque< TYSIntersection > &tabIntersect, const OSegment3D &rayon, const string &sourceVolumeId)
Delegate to _faceSelector the build of the array of intersections.
Definition: TYSolver.cpp:148
Describes building material.
Definition: entities.hpp:64
ComplexSpectrum spectrum
Spectrum to store acoustic values at different frequencies.
Definition: entities.hpp:82
Describes an acoustic source.
Definition: entities.hpp:407
string volume_id
Volume id.
Definition: entities.hpp:417
SourceDirectivityInterface * directivity
Pointer to the source directivity.
Definition: entities.hpp:416
static LPSolverConfiguration get()
Get the configuration.
Definition: config.cpp:96
virtual Spectrum lwAdjustment(Vector direction, double distance)=0
< Pure virtual method to return directivity of the Source
std::string readValueFromConfig(const std::string &filePath, const std::string &key, const std::string &defaultValue)
unsigned int readRaytracingNbRaysFromConfig(const std::string &filePath, unsigned int defaultValue)
bool intersectSegmentsFastInTheirPlane(const OSegment3D &segA, const OSegment3D &segB, OPoint3D &pt, double seuilConfondus)
double readRaytracingRcptRadiusFromConfig(const std::string &filePath, double defaultValue)
std::string readReflectionMethodFromConfig(const std::string &filePath, std::string defaultValue)
boost::shared_ptr< SolverConfiguration > LPSolverConfiguration
Definition: interfaces.h:25
Cache geometry associated with one reflecting segment.
Data-structure representing a reflection path It stores all needed data to build a TYChemin.
std::deque< OPoint3D > reflectionPoints
std::vector< const TYSIntersection * > reflectingSegments
Data structure for intersections.
OSegment3D segInter[2]
Data structure to store geometrical data of the surface from which comes a triangle issued from a cyl...
Definition: entities.hpp:217
Data structure to store geometrical data of the surface from which comes a triangle.
Definition: entities.hpp:204