Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYReflectionPathFinder.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) <2012-2024> <EDF-DTG> <FRANCE>
3  * This file is part of Code_TYMPAN (R).
4  * Code_TYMPAN (R) is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * Code_TYMPAN (R) is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  * See the GNU General Public License for more details.
12  * You should have received a copy of the GNU General Public License along
13  * with Code_TYMPAN (R). If not, see <https://www.gnu.org/licenses/>.
14  */
15 
16 #include "TYReflectionPathFinder.h"
18 
19 TYReflectionPathFinderART::TYReflectionPathFinderART(unsigned int nbRays, double rcptRadius)
20  : TYAbstractReflectionPathFinder(), _nbRays(nbRays), _rcptRadius(rcptRadius)
21 {
22  _extrusionLength = 10.; // hard-coded value, should not have any impact on results
23 
24  // AcousticRaytracer configuration
25  constexpr double maxDouble{std::numeric_limits<double>::max()};
26  _ARTSimulation.getConfiguration()->Accelerator = 2; // BVH data-structure
27  _ARTSimulation.getConfiguration()->MaxTreeDepth = 12; // BVH parameter
28  _ARTSimulation.getConfiguration()->MaxDiffraction = 0; // should disable diffractions
29  _ARTSimulation.getConfiguration()->MaxLength = maxDouble; // disable length selector
30  _ARTSimulation.getConfiguration()->UseSol = false; // disable reflections on ground triangles
31  _ARTSimulation.getConfiguration()->UsePostFilters = false; // disable non-default selectors
32  _ARTSimulation.getConfiguration()->KeepDebugRay = false; // do not store invalidated rays
33 }
34 
35 std::unique_ptr<TYAbstractReflectionPathFinder> TYReflectionPathFinderART::instanciate() const
36 {
37  return std::make_unique<TYReflectionPathFinderART>(this->_nbRays, this->_rcptRadius);
38 }
39 
40 bool TYReflectionPathFinderART::setup(size_t maxOrder, const std::deque<TYSIntersection>& tabIntersect,
41  const OPoint3D& source, const OPoint3D& receptor)
42 {
43  setupConfiguration(maxOrder);
44  if (!setupScene(tabIntersect, source, receptor))
45  {
46  return false;
47  }
49  setupSolver();
51  buildReflectionPaths(source, receptor);
52 
53  return true;
54 }
55 
57 {
58  return _paths.size() > 0;
59 }
60 
62 {
63  if (_paths.size() > 0)
64  {
65  TYReflectionPath res = _paths.back();
66  _paths.pop_back();
67  return res;
68  }
69  else
70  {
71  return TYReflectionPath();
72  }
73 }
74 
76 {
79 }
80 
81 bool TYReflectionPathFinderART::setupScene(const std::deque<TYSIntersection>& tabIntersect,
82  const OPoint3D& sourcePoint, const OPoint3D& receptorPoint)
83 {
84  _ELnormal = computeELPlaneNormal(sourcePoint, receptorPoint);
85 
86  // add faces
87  for (const TYSIntersection& inter : tabIntersect)
88  {
89  if (!processIntersectingSegment(inter))
90  {
91  return false;
92  }
93  }
94 
95  // create initial rays sampler
97 
98  // add source, using the sampler
99  Source source;
100  source.setPosition(OPoint3Dtovec3(sourcePoint));
101  source.setSampler(&sampler); // no transfer of ownership
102  // it may segfault further once sampler is popped from the stack
103  source.setInitialRayCount(_nbRays);
104  _ARTSimulation.addSource(source); // a copy of the sampler is in fact hidden here using
105  // `UniformCircularSampler(UniformCircularSampler*)`
106  // in practice it does not segfault (I assume that only the copy is
107  // used when setupScene is finished)
108 
109  // add receptor
110  Recepteur receptor;
111  receptor.setPosition(OPoint3Dtovec3(receptorPoint));
112  receptor.setRadius(_rcptRadius);
113  _ARTSimulation.addRecepteur(receptor);
114 
115  return true;
116 }
117 
119 {
120  const unsigned int acceleratorID{_ARTSimulation.getConfiguration()->Accelerator};
121 
122  // this instruction builds the accelerating data-structure of the scene
123  // the second argument sets the behavior when intersections between a ray and scene elements are found:
124  // here only the first intersection is considered
126 
127  // this instruction builds the accelerating data-structure of receptors
128  // the second argument sets the behavior when intersections between a ray and scene elements are found:
129  // here all intersections considered
131 }
132 
134 {
135  Scene& scene = *_ARTSimulation.getScene();
136  _pSolver = std::make_unique<BasicSolver>();
137  _ARTSimulation.setSolver(_pSolver.get()); // no transfer of ownership
138 
139  // this instruction builds selectors (only a CleanerSelector and a LengthSelector using default Simulation
140  // configuration)
141  _pSolver->postTreatmentScene(&scene, _ARTSimulation.getSources(), _ARTSimulation.getRecepteurs());
142 }
143 
145 {
147 }
148 
150 {
151  for (Ray* pRay : *_pSolver->getValidRays())
152  {
153  // ignore direct path
154  const bool isReflectionPath{pRay->getNbEvents() > 0};
155  if (!isReflectionPath)
156  {
157  continue;
158  }
159 
160  // build the path assuming it is valid (to minimize TYReflectionPath constructions)
161  _paths.emplace_back();
162  TYReflectionPath& path = _paths.back();
163  path.source = source;
164  path.receptor = receptor;
165  for (boost::shared_ptr<Event> pEvent : *pRay->getEvents())
166  {
167  // it is assumed that each event is a reflection
168  const OPoint3D reflectionPoint = vec3toOPoint3D(pEvent->getPosition());
169  path.reflectionPoints.push_back(reflectionPoint);
170  const TYSIntersection* pInterReflection = _shapeToTYSIntersection[pEvent->getShape()];
171  path.reflectingSegments.push_back(pInterReflection);
172  }
173 
174  // validate the path and remove it if not valid
175  const bool validPath = isPathValid(path);
176  if (validPath)
177  {
178  _foundSequences.insert(path.reflectingSegments);
179  }
180  else
181  {
182  _paths.pop_back();
183  }
184  }
185 
187 }
188 
190 {
191  if (inter.bIntersect[1])
192  {
193  if (inter.isInfra)
194  {
195  return processInfraIntersectingSegment(inter);
196  }
197  else
198  {
200  return true;
201  }
202  }
203  else
204  {
205  // do nothing with intersecting segment which do not intersect EL-place
206  return true;
207  }
208 }
209 
211 {
212  if (!inter.pFaceGeomData)
213  {
214  // should never happen
215  return false;
216  }
217 
218  const OVector3D& normal{inter.pFaceGeomData->n};
219  OPoint3D p1Top, p1Bottom, p2Top, p2Bottom;
220  buildQuadranglePointsFromInter(inter, p1Top, p1Bottom, p2Top, p2Bottom);
221  addOrientedQuadrangle(p1Top, p1Bottom, p2Top, p2Bottom, normal, inter);
222 
223  return true;
224 }
225 
227 {
228  const OSegment3D& segment{inter.segInter[1]};
229 
230  const OPoint3D p1{segment._ptA};
231  const OPoint3D p2{segment._ptB};
232 
233  // build a normal of the segment in EL-plane
234  // its orientation has no importance
235  const OVector3D tangent{p1, p2};
236  OVector3D normal{-tangent._y, tangent._x, 0.};
237  normal.normalize();
238 
239  OPoint3D p1Top, p1Bottom, p2Top, p2Bottom;
240  buildQuadranglePointsFromInter(inter, p1Top, p1Bottom, p2Top, p2Bottom);
241 
242  addOrientedQuadrangle(p1Top + normal * EPSILON_6, p1Bottom + normal * EPSILON_6,
243  p2Top + normal * EPSILON_6, p2Bottom + normal * EPSILON_6, normal, inter);
244  addOrientedQuadrangle(p1Top + normal * -EPSILON_6, p1Bottom + normal * -EPSILON_6,
245  p2Top + normal * -EPSILON_6, p2Bottom + normal * -EPSILON_6, normal * -1., inter);
246 
247  return true;
248 }
249 
251  OPoint3D& p1Bottom, OPoint3D& p2Top,
252  OPoint3D& p2Bottom) const
253 {
254  const OSegment3D& segment{inter.segInter[1]};
255  const OPoint3D& p1{segment._ptA};
256  const OPoint3D& p2{segment._ptB};
257  const OVector3D upExtrusion = _ELnormal * _extrusionLength;
258  const OVector3D downExtrusion = _ELnormal * -_extrusionLength;
259  p1Top = p1 + upExtrusion;
260  p1Bottom = p1 + downExtrusion;
261  p2Top = p2 + upExtrusion;
262  p2Bottom = p2 + downExtrusion;
263 }
264 
266  const OPoint3D& p2Top, const OPoint3D& p2Bottom,
267  const OVector3D vExt,
268  const TYSIntersection& sourceInter)
269 {
270  Shape* pT1 = addOrientedTriangle(p1Bottom, p2Top, p1Top, vExt);
271  Shape* pT2 = addOrientedTriangle(p1Bottom, p2Bottom, p2Top, vExt);
272  _shapeToTYSIntersection[pT1] = &sourceInter;
273  _shapeToTYSIntersection[pT2] = &sourceInter;
274 }
275 
277  const OPoint3D& p3, const OVector3D& vExt)
278 {
279  Scene& scene = *_ARTSimulation.getScene();
280  unsigned int i1, i2, i3;
281 
282  const OVector3D p1p2{p1, p2};
283  const OVector3D p1p3{p1, p3};
284  const OVector3D nCandidate = p1p2.cross(p1p3);
285 
286  if (nCandidate.scalar(vExt) > 0)
287  {
288  // v1 = p1, v2 = p2, v3 = p3
289  scene.addVertex(OPoint3Dtovec3(p1), i1);
290  scene.addVertex(OPoint3Dtovec3(p2), i2);
291  scene.addVertex(OPoint3Dtovec3(p3), i3);
292  }
293  else
294  {
295  // v1 = p1, v2 = p3, v3 = p2
296  scene.addVertex(OPoint3Dtovec3(p1), i1);
297  scene.addVertex(OPoint3Dtovec3(p3), i2);
298  scene.addVertex(OPoint3Dtovec3(p2), i3);
299  }
300 
301  return scene.addTriangle(i1, i2, i3, nullptr, false);
302 }
303 
305 {
306  const OVector3D e3{0., 0., 1.};
307  const OVector3D v{source, receptor};
308  const OVector3D u = v.cross(e3);
309  const OVector3D n = u.cross(v); // normal vector, so that (u, v, n) is a right-handed basis
310  const OVector3D nNormalized = n * (1. / n.norme());
311  return nNormalized;
312 }
313 
315 {
316  if (isPathAlreadyFound(path))
317  {
318  return false;
319  }
321  {
322  return false;
323  }
324  return true;
325 }
326 
328 {
329  return _foundSequences.count(path.reflectingSegments) > 0;
330 }
331 
333 {
334  const OPoint3D& lastReflection = path.reflectionPoints.back();
335  const OPoint3D& receptor = path.receptor;
336 
337  const double distLastReflectionReceptor = lastReflection.distFrom(receptor);
338 
339  const OVector3D rayDirection{lastReflection, receptor};
340  Ray ray{OPoint3Dtovec3(lastReflection), OPoint3Dtovec3(rayDirection)};
341  std::list<Intersection> intersections;
342  double distToClosestElement =
343  static_cast<double>(_ARTSimulation.getScene()->getAccelerator()->traverse(&ray, intersections));
344 
345  return distToClosestElement > 0. && distToClosestElement < distLastReflectionReceptor;
346 }
#define EPSILON_6
Definition: 3d.h:39
std::pair< unsigned int, unsigned int > segment
virtual decimal traverse(Ray *r, std::list< Intersection > &result) const
Run this accelerator.
Definition: Accelerator.h:68
unsigned int MaxTreeDepth
BvhAccelerator Accelerator option (Maximal tree depth)
bool KeepDebugRay
Flag to store rays into a debug_rays array after being invalidated.
unsigned int MaxReflexion
Maximal reflection events.
double MaxLength
LengthSelector Selector option (maximal length)
unsigned int MaxDiffraction
Maximal diffraction events.
unsigned int MaxProfondeur
Maximal number of events for ray validation in ANIME3D solver.
bool UsePostFilters
Flag to use some specifics Selector.
double _y
y coordinate of OCoord3D
Definition: 3d.h:283
The 3D point class.
Definition: 3d.h:487
double distFrom(const OPoint3D &pt) const
Computes the distance from this point to another.
Definition: 3d.cpp:371
Class to define a segment.
Definition: 3d.h:1141
The 3D vector class.
Definition: 3d.h:298
double norme() const
Computes the length of this vector.
Definition: 3d.cpp:215
double scalar(const OVector3D &vector) const
Performs the scalar product between this object and another vector.
Definition: 3d.cpp:210
OVector3D cross(const OVector3D &vector) const
Cross product.
Definition: 3d.cpp:196
: 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
Receptor inherits from a Sphere Shape.
Definition: Recepteur.h:28
This class mainly define a mesh (list of Shape) used by the Simulation object.
Definition: Scene.h:51
Shape * addTriangle(unsigned int i1, unsigned int i2, unsigned int i3, Material *m, const bool &isSol=false)
Add a triangle to the scene built with the vertices array.
Definition: Scene.cpp:118
bool addVertex(const vec3 &newVertex, unsigned int &index)
Add a vertex to the vertices array.
Definition: Scene.cpp:101
Accelerator * getAccelerator() const
Get the accelerator.
Definition: Scene.h:82
bool finish(int accelerator_id=1, leafTreatment::treatment _intersectionChoice=leafTreatment::FIRST)
Build the selected accelerator on the scene.
Definition: Scene.cpp:50
base class for shapes (Cylindre, Mesh, Sphere, Triangle,...)
Definition: Shape.h:57
void setSolver(Solver *_solver)
Tool function to set the acoustic solver for the simulation.
Definition: Simulation.h:93
AcousticRaytracerConfiguration * getConfiguration()
Get the configuration.
Definition: Simulation.h:197
void clean()
Clean the simulation: the scene, sources, and receptors and all the rays are deleted.
Definition: Simulation.cpp:17
void addRecepteur(Recepteur &r)
Tool function to add quickly a receptor for the simulation.
Definition: Simulation.h:159
void addSource(const Source &s)
Tool function to add a source to the simulation.
Definition: Simulation.h:138
Scene * getScene()
Get a pointer to the scene.
Definition: Simulation.h:73
std::vector< Recepteur > & getRecepteurs()
Return a vector of all receptors of the scene.
Definition: Simulation.h:175
std::vector< Source > & getSources()
Return the sources list of the scene.
Definition: Simulation.h:149
bool launchSimulation()
Program main loop. Extract all the rays from the sources then treat them. The loop finishes when the ...
Definition: Simulation.cpp:30
Scene * get_receptors_landscape()
Return the geometric distribution of receptors.
Definition: Simulation.h:83
Acoustic source class.
Definition: Source.h:33
void setSampler(Sampler *_sampler)
Set the Sampler for this Source.
Definition: Source.h:156
void setPosition(const vec3 _pos)
Set the position of the Source.
Definition: Source.h:110
void setInitialRayCount(int nb)
Set the initial rays counter.
Definition: Source.h:145
void setRadius(decimal _radius)
Set the radius of the sphere.
Definition: Sphere.h:70
void setPosition(const vec3 &_position)
Set the center of the sphere.
Definition: Sphere.h:81
Interface for multiple reflection paths computation algorithms.
std::unique_ptr< TYAbstractReflectionPathFinder > instanciate() const override
Instanciate a new TYReflectionPathFinderART. The configuration of the former path finder (number of r...
void computeRaytracing()
Perform raytracing simulation.
void setupConfiguration(size_t maxOrder)
Setup ART' Simulation configuration.
bool processIntersectingSegment(const TYSIntersection &inter)
Process an intersecting segment in EL-plane to add equivalent faces in the AcousticRaytracer' simulat...
std::unique_ptr< Solver > _pSolver
bool setup(size_t maxOrder, const std::deque< TYSIntersection > &tabIntersect, const OPoint3D &source, const OPoint3D &receptor) override
Set the scene to be treated by the path finder.
std::unordered_map< const Shape *, const TYSIntersection * > _shapeToTYSIntersection
Shape * addOrientedTriangle(const OPoint3D &p1, const OPoint3D &p2, const OPoint3D &p3, const OVector3D &vExt)
Add an oriented triangle to the AcousticRaytracer' simulation scene. The vertices (v1 = p1,...
void setupAcceleratingDataStructure()
Setup accelerating data-structure using ART' Simulation configuration.
bool remainingPaths() const override
Tell if some paths remain in the set of remaining paths.
bool setupScene(const std::deque< TYSIntersection > &tabIntersect, const OPoint3D &sourcePoint, const OPoint3D &receptorPoint)
Build an AcousticRaytracer scene containing one source, one receptor, and a collection of faces....
void buildQuadranglePointsFromInter(const TYSIntersection &inter, OPoint3D &p1Top, OPoint3D &p1Bottom, OPoint3D &p2Top, OPoint3D &p2Bottom) const
Compute points forming a quadrangle from an intersecting segment in EL-plane. Points are obtained by ...
std::deque< TYReflectionPath > _paths
bool isPathAlreadyFound(const TYReflectionPath &path) const
Check if a path has already been found.
bool processTopoIntersectingSegment(const TYSIntersection &inter)
Process a topography intersecting segment in EL-plane to add equivalent faces in the AcousticRaytrace...
void buildReflectionPaths(const OPoint3D &source, const OPoint3D &receptor)
Build reflection paths from valid rays found by the solver. For each sequence of reflecting barriers,...
TYReflectionPathFinderART()=default
TYReflectionPath popPath() override
Give the last computed reflection path, and remove it from the set of remaining paths.
OVector3D computeELPlaneNormal(const OPoint3D &source, const OPoint3D &receptor)
Compute a normal vector of the EL-plane Hypothesis: source and receptor are not aligned along a verti...
bool processInfraIntersectingSegment(const TYSIntersection &inter)
Process an infrastructure intersecting segment in EL-plane to add equivalent faces in the AcousticRay...
void setupSolver()
Setup ART' simulation solver.
std::set< std::vector< const TYSIntersection * > > _foundSequences
bool isPathValid(const TYReflectionPath &path)
Check if a path is valid. In plus of validation performed during raytracing, it has to be verified:
bool isLastSegmentIntersectingSceneElement(const TYReflectionPath &path)
Check if the last segment of a path intersects a scene element.
void addOrientedQuadrangle(const OPoint3D &p1Top, const OPoint3D &p1Bottom, const OPoint3D &p2Top, const OPoint3D &p2Bottom, const OVector3D vExt, const TYSIntersection &sourceInter)
Add an oriented quadrangle to the AcousticRaytracer' simulation scene. The quadrangle is oriented usi...
Sampler providing directions uniformly distributed on a circle. This circle is in the plane defined b...
vec3 OPoint3Dtovec3(const OPoint3D &_p)
Converts a OPoint3D to vec3.
Definition: mathlib.h:446
OPoint3D vec3toOPoint3D(const vec3 &_v)
Converts a vec3 to OPoint3D.
Definition: mathlib.h:437
vec3 OVector3Dtovec3(const OVector3D &_v)
Converts a OVector3D to vec3.
Definition: mathlib.h:464
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.
bool isInfra
Flag to define if is a infrastructure face.
bool bIntersect[2]
Flag to indicate the face cuts vertical plane ([0]) or horizontal plane ([1])
boost::shared_ptr< tympan::AcousticFaceGeomData > pFaceGeomData
OSegment3D segInter[2]