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 
68  double seuilConfondus)
69 {
70  const OPoint3D& A = segA._ptA;
71  const OPoint3D& B = segA._ptB;
72  const OPoint3D& C = segB._ptA;
73  const OPoint3D& D = segB._ptB;
74 
75  const double ux = B._x - A._x;
76  const double uy = B._y - A._y;
77  const double uz = B._z - A._z;
78 
79  const double vx = D._x - C._x;
80  const double vy = D._y - C._y;
81  const double vz = D._z - C._z;
82 
83  // Normal of the plane spanned by the 2 segment directions.
84  const double nx = uy * vz - uz * vy;
85  const double ny = uz * vx - ux * vz;
86  const double nz = ux * vy - uy * vx;
87 
88  const double anx = std::abs(nx);
89  const double any = std::abs(ny);
90  const double anz = std::abs(nz);
91 
92  // Degenerate or quasi-parallel case: keep legacy robust behavior.
93  if ((anx <= TYSEUILCONFONDUS) && (any <= TYSEUILCONFONDUS) && (anz <= TYSEUILCONFONDUS))
94  {
95  return segA.intersects(segB, pt, seuilConfondus) != INTERS_NULLE;
96  }
97 
98  // Project to the coordinate plane where the 2D determinant is the most stable.
99  double a1, a2, u1, u2, c1, c2, v1, v2;
100 
101  if ((anx >= any) && (anx >= anz))
102  {
103  // Drop X => work in YZ
104  a1 = A._y;
105  a2 = A._z;
106  u1 = uy;
107  u2 = uz;
108  c1 = C._y;
109  c2 = C._z;
110  v1 = vy;
111  v2 = vz;
112  }
113  else if ((any >= anx) && (any >= anz))
114  {
115  // Drop Y => work in XZ
116  a1 = A._x;
117  a2 = A._z;
118  u1 = ux;
119  u2 = uz;
120  c1 = C._x;
121  c2 = C._z;
122  v1 = vx;
123  v2 = vz;
124  }
125  else
126  {
127  // Drop Z => work in XY
128  a1 = A._x;
129  a2 = A._y;
130  u1 = ux;
131  u2 = uy;
132  c1 = C._x;
133  c2 = C._y;
134  v1 = vx;
135  v2 = vy;
136  }
137 
138  const double w1 = c1 - a1;
139  const double w2 = c2 - a2;
140 
141  const double det = u1 * v2 - u2 * v1;
142 
143  // Near-parallel in projected plane: keep legacy behavior.
144  if (std::abs(det) <= TYSEUILCONFONDUS)
145  {
146  return segA.intersects(segB, pt, seuilConfondus) != INTERS_NULLE;
147  }
148 
149  const double t = (w1 * v2 - w2 * v1) / det;
150  const double s = (w1 * u2 - w2 * u1) / det;
151 
152  const double lenU = std::sqrt(ux * ux + uy * uy + uz * uz);
153  const double lenV = std::sqrt(vx * vx + vy * vy + vz * vz);
154  const double paramTol = seuilConfondus / std::max(1.0, std::max(lenU, lenV));
155 
156  if ((t < -paramTol) || (t > 1.0 + paramTol) || (s < -paramTol) || (s > 1.0 + paramTol))
157  {
158  return false;
159  }
160 
161  pt._x = A._x + t * ux;
162  pt._y = A._y + t * uy;
163  pt._z = A._z + t * uz;
164 
165  return true;
166 }
167 } // namespace
168 
170  : TYAcousticModel9613Solver(solver), _pReflectionPathFinder(nullptr), _pReflectionPruningStrategy(nullptr)
171 {
172 }
173 
175 {
177 
179  // Select reflection path finder depending on solver configuration
180  // TODO : Externalize in computation parameters
181  const std::string solverConfigPath = "C:\\projects\\tympan_tools\\17534-3\\solver_conf.txt";
182  const std::string reflectionMethod =
183  readReflectionMethodFromConfig(solverConfigPath, "IMAGE_SOURCE_METHOD");
184  if (reflectionMethod.compare("RAY_TRACING") == 0)
185  {
186  const unsigned int nbRays = readRaytracingNbRaysFromConfig(
187  solverConfigPath, 200); // TODO : Externalize in computation parameters
188  const unsigned int accelerator = config->Accelerator;
189  const unsigned int maxTreeDepth = config->MaxTreeDepth;
190  float rayMaxLength = config->MaxLength;
191 
193  std::make_unique<TYReflectionPathFinderART>(nbRays, accelerator, maxTreeDepth, rayMaxLength);
194  }
195 
196  // Select pruning strategy depending on solver configuration
197  const bool enableVisibilityPruning = config->EnableVisibilityPruning;
198  if (enableVisibilityPruning)
199  {
200  _pReflectionPruningStrategy = std::make_unique<TYReflectionVisibilityPruningStrategy>();
201  }
202  else
203  {
204  _pReflectionPruningStrategy = std::make_unique<TYReflectionNoPruningStrategy>();
205  }
206 }
207 
209 {
210  // zmin = -2 * lambda / (C2 * C3)
211  OSpectreOctave zmin = _lambda * (-2.0);
212  zmin = zmin.div(C3 * C2);
213  return zmin;
214 }
215 
216 OSpectreOctave TYAcousticModel9613Solver2024::calculKmeteo(const bool vertical, const double d_SS,
217  const double d_SR, const double d, const double z,
218  const double e, const OSpectreOctave& z_min) const
219 {
220  // K_meteo = exp{-(1 / 2000) * sqrt(([max(d_SS, d_SR) + e] * min(d_SS, d_SR) * d) / [2 * (z - z_min)])}
221  // for vertical diffraction K_meteo = 1 for lateral diffraction
222  //
223  // This is not specified explicitly in the standard, but we also set:
224  // K_meteo = 1 when z < z_min
225  // which avoids a division by zero and has no effect on the computation of Dz
226 
227  OSpectreOctave K_meteo{1.0};
228 
229  if (!vertical)
230  {
231  return K_meteo;
232  }
233 
234  double* kMeteo = K_meteo.getTabValReel();
235  const double* zMin = z_min.getTabValReel();
236 
237  const double dMax = std::max(d_SS, d_SR);
238  const double dMin = std::min(d_SS, d_SR);
239  const double numerator = (dMax + e) * dMin * d;
240 
241  for (std::size_t i = 0; i < TY_SPECTRE_OCT_NB_ELMT; ++i)
242  {
243  if (z > zMin[i])
244  {
245  kMeteo[i] = std::exp(-(1.0 / 2000.0) * std::sqrt(numerator / (2.0 * (z - zMin[i]))));
246  }
247  }
248 
249  return K_meteo;
250 }
251 
253  const OSpectreOctave& C3, const OSpectreOctave& Kmeteo,
254  const OSpectreOctave& zmin) const
255 {
256  // Dz = 10 * log10[1 + (2 + (C2 / lambda) * C3 * z) * Kmeteo] dB for z > zmin
257  // Dz = 0 dB for z <= zmin
258 
259  OSpectreOctave Dz{0.0};
260 
261  double* dz = Dz.getTabValReel();
262  const double* lambda = _lambda.getTabValReel();
263  const double* c3 = C3.getTabValReel();
264  const double* kmeteo = Kmeteo.getTabValReel();
265  const double* zMin = zmin.getTabValReel();
266 
267  for (std::size_t i = 0; i < TY_SPECTRE_OCT_NB_ELMT; ++i)
268  {
269  if (z > zMin[i])
270  {
271  const double term = 2.0 + (C2 / lambda[i]) * c3[i] * z;
272  dz[i] = 10.0 * std::log10(1.0 + term * kmeteo[i]);
273  }
274  }
275 
276  return Dz;
277 }
278 
279 void TYAcousticModel9613Solver2024::computeCheminReflexion(const std::deque<TYSIntersection>& tabIntersect,
280  const OSegment3D& ray,
281  const tympan::AcousticSource& source,
282  TYTabChemin9613Solver& TabChemins,
283  double distance) const
284 {
285  // Multiple reflection order
287  const size_t multipleReflectionOrder = config->ReflectionOrder;
288 
289  if (multipleReflectionOrder == 0)
290  {
291  return;
292  }
293 
295  {
296  // use the TYAbstractReflectionPathFinder interface
297  std::unique_ptr<TYAbstractReflectionPathFinder> pReflectionPathFinderInstance =
298  _pReflectionPathFinder->instanciate();
299 
300  pReflectionPathFinderInstance->setup(multipleReflectionOrder, tabIntersect, ray._ptA, ray._ptB);
301 
302  while (pReflectionPathFinderInstance->remainingPaths())
303  {
304  TYReflectionPath reflectionPath = pReflectionPathFinderInstance->popPath();
305 
306  // imageSourcesList is introduced to use existing interface of buildReflectionPath
307  // only its length is used
308  std::deque<OPoint3D> imageSourcesList;
309  for (size_t i = 0; i < reflectionPath.reflectingSegments.size() + 1; i++)
310  {
311  imageSourcesList.emplace_back();
312  }
313 
314  // the path is assumed to be valid, thus it is directly built
315  buildReflectionPath(reflectionPath.reflectingSegments, imageSourcesList,
316  reflectionPath.reflectionPoints, ray, source, TabChemins, distance);
317  }
318  }
319  else
320  {
321  // historical code for image source method
322  // TODO: implement it as a TYReflectionPathFinder
323  computeCheminReflectionImageSourceMethod(multipleReflectionOrder, tabIntersect, ray, source,
324  TabChemins, distance);
325  }
326 }
327 
329  size_t multipleReflectionOrder, const std::deque<TYSIntersection>& tabIntersect, const OSegment3D& ray,
330  const tympan::AcousticSource& source, TYTabChemin9613Solver& TabChemins, double distance) const
331 {
332  std::vector<ReflectingSegmentCache> reflectingSegments;
333  reflectingSegments.reserve(tabIntersect.size());
334 
335  // Keep only barriers that are both infrastructure and intersecting the EL plane.
336  // Their support-line geometry is cached once here, then reused during the DFS.
337  for (const auto& inter : tabIntersect)
338  {
339  if (inter.isInfra && inter.bIntersect[1])
340  {
341  reflectingSegments.push_back(makeReflectingSegmentCache(inter));
342  }
343  }
344 
345  if (reflectingSegments.empty())
346  {
347  return;
348  }
349 
350  std::vector<const TYSIntersection*> currentCombination;
351  currentCombination.reserve(multipleReflectionOrder);
352 
353  std::deque<OPoint3D> currentImageSources;
354  currentImageSources.push_back(ray._ptA);
355 
356  // Streaming exploration of ordered reflection combinations.
357  // Each valid prefix is turned directly into an acoustic path, avoiding the
358  // construction of an intermediate global set of combinations/candidates.
359  buildReflectionPathsStreaming(multipleReflectionOrder, reflectingSegments, currentCombination,
360  currentImageSources, tabIntersect, ray, source, TabChemins, distance);
361 }
362 
364  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
365  const std::deque<OPoint3D>& pathPoints2D, double hs, double hr, double& Gs, double& Gm, double& Gr) const
366 {
367  Gs = 0.5;
368  Gm = 0.5;
369  Gr = 0.5;
370 
371  if (!computeGroundFactorSourceZone(tabIntersectSegments, pathPoints2D, hs, Gs))
372  {
373  return false;
374  }
375 
376  if (!computeGroundFactorMiddleZone(tabIntersectSegments, pathPoints2D, hs, hr, Gm))
377  {
378  return false;
379  }
380 
381  if (!computeGroundFactorReceiverZone(tabIntersectSegments, pathPoints2D, hr, Gr))
382  {
383  return false;
384  }
385 
386  return true;
387 }
388 
390  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
391  const std::deque<OPoint3D>& pathPoints2D, double hs, double& Gs) const
392 {
393  double heightRatio = 30.0;
394  Gs = 0.5;
395 
396  if (pathPoints2D.size() < 2)
397  {
398  return false;
399  }
400 
401  if (tabIntersectSegments.size() != pathPoints2D.size() - 1)
402  {
403  return false;
404  }
405 
406  const double srcZoneLength = heightRatio * hs;
407 
408  // Same fallback behavior as legacy code.
409  if (srcZoneLength <= TYSEUILCONFONDUS)
410  {
411  Gs = 0.5;
412  return true;
413  }
414 
415  double traversedLength = 0.0; // curvilinear length along the broken path
416  double coveredLength = 0.0; // sum of dp returned by computeGZone
417  double weightedGroundSum = 0.0;
418 
419  for (size_t i = 0; i + 1 < pathPoints2D.size(); ++i)
420  {
421  const OPoint3D& ptA = pathPoints2D[i];
422  const OPoint3D& ptB = pathPoints2D[i + 1];
423 
424  const OSegment3D currentSegment(ptA, ptB);
425  const double currentSegmentLength = currentSegment.longueur();
426 
427  if (currentSegmentLength <= TYSEUILCONFONDUS)
428  {
429  continue;
430  }
431 
432  const double remainingLength = srcZoneLength - traversedLength;
433 
434  if (remainingLength <= TYSEUILCONFONDUS)
435  {
436  break;
437  }
438 
439  OPoint3D ptEndZone = ptB;
440 
441  // The source-zone limit lies inside the current segment.
442  if (remainingLength < currentSegmentLength)
443  {
444  const double alpha = remainingLength / currentSegmentLength;
445 
446  ptEndZone._x = ptA._x + alpha * (ptB._x - ptA._x);
447  ptEndZone._y = ptA._y + alpha * (ptB._y - ptA._y);
448  ptEndZone._z = ptA._z + alpha * (ptB._z - ptA._z);
449 
450  double GCurSeg = 0.0;
451  double dpCurSeg = 0.0;
452  computeGZone(ptA, ptEndZone, GCurSeg, dpCurSeg, tabIntersectSegments[i]);
453 
454  weightedGroundSum += GCurSeg;
455  coveredLength += dpCurSeg;
456  traversedLength = srcZoneLength;
457 
458  break;
459  }
460 
461  // The whole current segment belongs to the source zone.
462  double GCurSeg = 0.0;
463  double dpCurSeg = 0.0;
464  computeGZone(ptA, ptB, GCurSeg, dpCurSeg, tabIntersectSegments[i]);
465 
466  weightedGroundSum += GCurSeg;
467  coveredLength += dpCurSeg;
468  traversedLength += currentSegmentLength;
469  }
470 
471  if (coveredLength > TYSEUILCONFONDUS)
472  {
473  Gs = weightedGroundSum / coveredLength;
474  }
475  else
476  {
477  Gs = 0.5;
478  }
479 
480  return true;
481 }
482 
484  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
485  const std::deque<OPoint3D>& pathPoints2D, double hr, double& Gr) const
486 {
487  double heightRatio = 30.0;
488  Gr = 0.5;
489 
490  if (pathPoints2D.size() < 2)
491  {
492  return false;
493  }
494 
495  if (tabIntersectSegments.size() != pathPoints2D.size() - 1)
496  {
497  return false;
498  }
499 
500  const double rcpZoneLength = heightRatio * hr;
501 
502  // Same fallback behavior as legacy code.
503  if (rcpZoneLength <= TYSEUILCONFONDUS)
504  {
505  Gr = 0.5;
506  return true;
507  }
508 
509  double traversedLength = 0.0; // curvilinear length traversed backward from receiver
510  double coveredLength = 0.0; // sum of dp returned by computeGZone
511  double weightedGroundSum = 0.0;
512 
513  for (size_t i = pathPoints2D.size() - 1; i > 0; --i)
514  {
515  const OPoint3D& ptA = pathPoints2D[i - 1];
516  const OPoint3D& ptB = pathPoints2D[i];
517 
518  const OSegment3D currentSegment(ptA, ptB);
519  const double currentSegmentLength = currentSegment.longueur();
520 
521  if (currentSegmentLength <= TYSEUILCONFONDUS)
522  {
523  continue;
524  }
525 
526  const double remainingLength = rcpZoneLength - traversedLength;
527 
528  if (remainingLength <= TYSEUILCONFONDUS)
529  {
530  break;
531  }
532 
533  // The receiver-zone limit lies inside the current segment.
534  if (remainingLength < currentSegmentLength)
535  {
536  const double alpha = remainingLength / currentSegmentLength;
537 
538  // Start point of the receiver zone on the current segment,
539  // located at distance "remainingLength" from ptB toward ptA.
540  OPoint3D ptStartZone;
541  ptStartZone._x = ptB._x + alpha * (ptA._x - ptB._x);
542  ptStartZone._y = ptB._y + alpha * (ptA._y - ptB._y);
543  ptStartZone._z = ptB._z + alpha * (ptA._z - ptB._z);
544 
545  double GCurSeg = 0.0;
546  double dpCurSeg = 0.0;
547  computeGZone(ptStartZone, ptB, GCurSeg, dpCurSeg, tabIntersectSegments[i - 1]);
548 
549  weightedGroundSum += GCurSeg;
550  coveredLength += dpCurSeg;
551  traversedLength = rcpZoneLength;
552 
553  break;
554  }
555 
556  // The whole current segment belongs to the receiver zone.
557  double GCurSeg = 0.0;
558  double dpCurSeg = 0.0;
559  computeGZone(ptA, ptB, GCurSeg, dpCurSeg, tabIntersectSegments[i - 1]);
560 
561  weightedGroundSum += GCurSeg;
562  coveredLength += dpCurSeg;
563  traversedLength += currentSegmentLength;
564  }
565 
566  if (coveredLength > TYSEUILCONFONDUS)
567  {
568  Gr = weightedGroundSum / coveredLength;
569  }
570  else
571  {
572  Gr = 0.5;
573  }
574 
575  return true;
576 }
577 
579  const std::deque<std::deque<TYSIntersection>>& tabIntersectSegments,
580  const std::deque<OPoint3D>& pathPoints2D, double hs, double hr, double& Gm) const
581 {
582  double heightRatio = 30.0;
583  Gm = 0.5;
584 
585  if (pathPoints2D.size() < 2)
586  {
587  return false;
588  }
589 
590  if (tabIntersectSegments.size() != pathPoints2D.size() - 1)
591  {
592  return false;
593  }
594 
595  const double srcZoneLength = heightRatio * hs;
596  const double rcpZoneLength = heightRatio * hr;
597 
598  // Compute total curvilinear length of the broken path.
599  double dp = 0.0;
600  for (size_t i = 0; i + 1 < pathPoints2D.size(); ++i)
601  {
602  dp += OSegment3D(pathPoints2D[i], pathPoints2D[i + 1]).longueur();
603  }
604 
605  // No middle zone when source and receiver zones touch or overlap.
606  if ((srcZoneLength + rcpZoneLength) >= (dp - TYSEUILCONFONDUS))
607  {
608  Gm = 0.5;
609  return true;
610  }
611 
612  const double middleZoneBegin = srcZoneLength;
613  const double middleZoneEnd = dp - rcpZoneLength;
614 
615  double traversedLength = 0.0; // curvilinear abscissa at segment start
616  double coveredLength = 0.0; // sum of dp returned by computeGZone
617  double weightedGroundSum = 0.0;
618 
619  for (size_t i = 0; i + 1 < pathPoints2D.size(); ++i)
620  {
621  const OPoint3D& ptA = pathPoints2D[i];
622  const OPoint3D& ptB = pathPoints2D[i + 1];
623 
624  const OSegment3D currentSegment(ptA, ptB);
625  const double currentSegmentLength = currentSegment.longueur();
626 
627  if (currentSegmentLength <= TYSEUILCONFONDUS)
628  {
629  continue;
630  }
631 
632  const double segmentBegin = traversedLength;
633  const double segmentEnd = traversedLength + currentSegmentLength;
634 
635  // Overlap between current segment and middle zone in curvilinear abscissa.
636  const double overlapBegin = std::max(segmentBegin, middleZoneBegin);
637  const double overlapEnd = std::min(segmentEnd, middleZoneEnd);
638 
639  if ((overlapEnd - overlapBegin) > TYSEUILCONFONDUS)
640  {
641  const double alphaBegin = (overlapBegin - segmentBegin) / currentSegmentLength;
642  const double alphaEnd = (overlapEnd - segmentBegin) / currentSegmentLength;
643 
644  OPoint3D ptZoneBegin;
645  ptZoneBegin._x = ptA._x + alphaBegin * (ptB._x - ptA._x);
646  ptZoneBegin._y = ptA._y + alphaBegin * (ptB._y - ptA._y);
647  ptZoneBegin._z = ptA._z + alphaBegin * (ptB._z - ptA._z);
648 
649  OPoint3D ptZoneEnd;
650  ptZoneEnd._x = ptA._x + alphaEnd * (ptB._x - ptA._x);
651  ptZoneEnd._y = ptA._y + alphaEnd * (ptB._y - ptA._y);
652  ptZoneEnd._z = ptA._z + alphaEnd * (ptB._z - ptA._z);
653 
654  double GCurSeg = 0.0;
655  double dpCurSeg = 0.0;
656  computeGZone(ptZoneBegin, ptZoneEnd, GCurSeg, dpCurSeg, tabIntersectSegments[i]);
657 
658  weightedGroundSum += GCurSeg;
659  coveredLength += dpCurSeg;
660  }
661 
662  traversedLength = segmentEnd;
663  }
664 
665  if (coveredLength > TYSEUILCONFONDUS)
666  {
667  Gm = weightedGroundSum / coveredLength;
668  }
669  else
670  {
671  Gm = 0.5;
672  }
673 
674  return true;
675 }
676 
678  const TYSIntersection& rhs) const
679 {
680  const OSegment3D& seg1 = lhs.segInter[1];
681  const OSegment3D& seg2 = rhs.segInter[1];
682 
683  const bool sameOrder = (seg1._ptA == seg2._ptA) && (seg1._ptB == seg2._ptB);
684 
685  const bool reverseOrder = (seg1._ptA == seg2._ptB) && (seg1._ptB == seg2._ptA);
686 
687  return sameOrder || reverseOrder;
688 }
689 
691  const std::vector<const TYSIntersection*>& currentCombination,
692  const std::deque<OPoint3D>& imageSourcesList, const OPoint3D& receptorPoint,
693  std::deque<OPoint3D>& reflectionPointsList) const
694 {
695  reflectionPointsList.clear();
696 
697  if (currentCombination.empty())
698  {
699  return true;
700  }
701 
702  // By convention:
703  // imageSourcesList[0] = S0 = source point
704  // imageSourcesList[i] = image source after i reflections
705  if (imageSourcesList.size() != currentCombination.size() + 1)
706  {
707  return false;
708  }
709 
710  OPoint3D nextPoint = receptorPoint; // P(n+1) = R
711 
712  // Reflection points are reconstructed backward:
713  // starting from the receptor, intersect the current image ray with the
714  // corresponding reflecting segment, then continue with the previous order.
715  for (int i = static_cast<int>(currentCombination.size()) - 1; i >= 0; --i)
716  {
717  const OPoint3D& currentImageSource = imageSourcesList[i + 1]; // Si
718  const OSegment3D& currentBarrier = currentCombination[i]->segInter[1]; // Bi
719 
720  OPoint3D currentReflectionPoint;
721 
722  // Intersection must be computed on segments, not on infinite lines.
723  if (!intersectSegmentsFastInTheirPlane(currentBarrier, OSegment3D(currentImageSource, nextPoint),
724  currentReflectionPoint, TYSEUILCONFONDUS))
725  {
726  reflectionPointsList.clear();
727  return false;
728  }
729 
730  reflectionPointsList.push_front(currentReflectionPoint);
731  nextPoint = currentReflectionPoint;
732  }
733 
734  return true;
735 }
736 
738  const std::vector<const TYSIntersection*>& barrierCombination,
739  const std::deque<OPoint3D>& reflectionPointsList, const std::deque<TYSIntersection>& tabIntersect,
740  const OPoint3D& sourcePoint, const OPoint3D& receptorPoint) const
741 {
742  const size_t reflectionOrder = barrierCombination.size();
743 
744  if (reflectionPointsList.size() != reflectionOrder)
745  {
746  return false;
747  }
748 
749  std::deque<OPoint3D> pathPoints;
750  pathPoints.push_back(sourcePoint);
751  for (const auto& point : reflectionPointsList)
752  {
753  pathPoints.push_back(point);
754  }
755  pathPoints.push_back(receptorPoint);
756 
757  // For each leg [Pi, P(i+1)], only the reflecting barriers on which belong Pi or P(i+1) are allowed to
758  // touch the path. Any other barrier intersection invalidates the candidate.
759  for (size_t i = 0; i <= reflectionOrder; ++i)
760  {
761  const OSegment3D pathSegment(pathPoints[i], pathPoints[i + 1]);
762 
763  for (const auto& sceneBarrier : tabIntersect)
764  {
765  if ((i >= 1) && sameReflectingSegment(sceneBarrier, *barrierCombination[i - 1]))
766  {
767  continue;
768  }
769 
770  if ((i < reflectionOrder) && sameReflectingSegment(sceneBarrier, *barrierCombination[i]))
771  {
772  continue;
773  }
774 
775  OPoint3D intersectionPoint;
776  if (sceneBarrier.segInter[1].intersects(pathSegment, intersectionPoint, TYSEUILCONFONDUS))
777  {
778  return false;
779  }
780  }
781  }
782 
783  return true;
784 }
785 
787  const std::vector<const TYSIntersection*>& barrierCombination,
788  const std::deque<OPoint3D>& imageSourcesList, const std::deque<OPoint3D>& reflectionPointsList,
789  const OSegment3D& directRay, const tympan::AcousticSource& source, TYTabChemin9613Solver& TabChemins,
790  double distance) const
791 {
792  const size_t reflectionOrder = barrierCombination.size();
793 
794  if (reflectionOrder == 0)
795  {
796  return false;
797  }
798 
799  if (imageSourcesList.size() != reflectionOrder + 1)
800  {
801  return false;
802  }
803 
804  if (reflectionPointsList.size() != reflectionOrder)
805  {
806  return false;
807  }
808 
809  // Build path points:
810  // P0 = S
811  // P1 ... Pn = reflection points
812  // P(n+1) = R
813  std::deque<OPoint3D> pathPoints;
814  std::deque<OPoint3D> pathPoints2D;
815  std::deque<double> sourceReflectionPointLengths;
816  std::deque<double> reflectionPointReceptorLengths;
817 
818  pathPoints.push_back(directRay._ptA);
819 
820  for (const auto& point : reflectionPointsList)
821  {
822  pathPoints.push_back(point);
823  }
824 
825  pathPoints.push_back(directRay._ptB);
826 
827  TYTabEtape9613Solver tabEtapes;
828  double pathLength = 0.0;
829  double dp = 0.0;
830 
831  OPoint3D A2D;
832  OPoint3D B2D;
833  double segLength = 0.0;
834 
835  for (size_t i = 0; i + 1 < pathPoints.size(); ++i)
836  {
837  OSegment3D segment(pathPoints[i], pathPoints[i + 1]);
838  segLength = segment.longueur();
839  pathLength += segLength;
840  if (i < pathPoints.size() - 2)
841  {
842  sourceReflectionPointLengths.push_back(pathLength);
843  reflectionPointReceptorLengths.push_back(-pathLength);
844  }
845  A2D = OPoint3D{segment._ptA._x, segment._ptA._y, 0.0};
846  B2D = OPoint3D{segment._ptB._x, segment._ptB._y, 0.0};
847 
848  // dp is the broken-path length projected in the horizontal plane.
849  dp += OSegment3D{A2D, B2D}.longueur();
850  pathPoints2D.push_back(A2D);
851  }
852  pathPoints2D.push_back(B2D);
853 
854  for (size_t i = 0; i < reflectionOrder; ++i)
855  {
856  reflectionPointReceptorLengths[i] += pathLength;
857  }
858 
859  {
860  TYEtape9613Solver etape;
861  etape._pt = pathPoints[0];
862  etape._type = TYSOURCE;
863 
864  const OSegment3D firstLeg(pathPoints[0], pathPoints[1]);
865  etape._Absorption =
866  source.directivity->lwAdjustment(OVector3D(firstLeg._ptA, firstLeg._ptB), firstLeg.longueur());
867 
868  tabEtapes.push_back(etape);
869  }
870 
871  for (size_t i = 0; i < reflectionOrder; ++i)
872  {
874  dynamic_cast<tympan::AcousticBuildingMaterial*>(barrierCombination[i]->material);
875 
876  if (material == nullptr)
877  {
878  return false;
879  }
880 
881  if (!barrierCombination[i]->pFaceGeomData)
882  {
883  // should never happen
884  return false;
885  }
886 
887  // keep only paths with reflections over infrastructure
888  if (dynamic_cast<tympan::AcousticFaceGeomDataInfra*>(barrierCombination[i]->pFaceGeomData.get()) ==
889  nullptr)
890  {
891  return false;
892  }
893 
894  TYEtape9613Solver etape;
895  etape._pt = reflectionPointsList[i];
896  etape._type = TYREFLEXION;
897  etape._Absorption = material->spectrum;
898 
899  tabEtapes.push_back(etape);
900  }
901 
902  OSegment3D segMeanSlope;
903  meanSlope(directRay, segMeanSlope);
904 
905  double hs{0.0}, hr{0.0};
906  computeSegmentEdgesHeights(hs, hr, segMeanSlope, directRay);
907 
908  double Gs{0.0}, Gm{0.0}, Gr{0.0};
909 
910  // Recompute the scene intersections for each broken-path leg [Pi, P(i+1)].
911  // Ground factors must be evaluated on the reflected path, not on the direct ray.
912  std::deque<std::deque<TYSIntersection>> tabIntersectSegments;
913  OSegment3D seg;
914  tabIntersectSegments.resize(reflectionOrder + 1);
915  for (size_t i = 0; i < reflectionOrder + 1; ++i)
916  {
917  seg = OSegment3D{pathPoints[i], pathPoints[i + 1]};
918  _solver.selectFaces(tabIntersectSegments[i], seg, source.volume_id);
919  }
920 
921  getGroundfactors(tabIntersectSegments, pathPoints2D, hs, hr, Gs, Gm, Gr);
922 
923  std::unique_ptr<TYChemin9613Solver> chemin = createChemin();
924  chemin->setType(TYTypeChemin::CHEMIN_REFLEX);
925  chemin->setLongueur(pathLength);
926  chemin->setDistance(distance);
927  chemin->calcAttenuation(tabEtapes, *_pSolverAtmos, dp, hs, hr, Gs, Gm, Gr);
928 
929  // The minimal extension condition is evaluated reflection by reflection on
930  // the broken reflected path.
931  OSpectreOctave filter{1.}, curFilter{0.};
932  for (size_t i = 0; i < reflectionOrder; ++i)
933  {
934  const OPoint3D& Oprev = pathPoints[i];
935  const OPoint3D& O = pathPoints[i + 1];
936 
937  boost::shared_ptr<tympan::AcousticFaceGeomDataInfra> pFaceGeomDataInfra =
938  boost::dynamic_pointer_cast<tympan::AcousticFaceGeomDataInfra, tympan::AcousticFaceGeomData>(
939  barrierCombination[i]->pFaceGeomData);
940  const double a = pFaceGeomDataInfra->a;
941  const double h = pFaceGeomDataInfra->h;
942  const OVector3D& normal = pFaceGeomDataInfra->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:415
string volume_id
Volume id.
Definition: entities.hpp:425
SourceDirectivityInterface * directivity
Pointer to the source directivity.
Definition: entities.hpp:424
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)
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:225
Data structure to store geometrical data of the surface from which comes a triangle issued from infra...
Definition: entities.hpp:215
Data structure to store geometrical data of the surface from which comes a triangle.
Definition: entities.hpp:204