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, unsigned int accelerator /* = 1 */,
20  unsigned int maxTreeDepth /* = 12 */,
21  float rayMaxLength /* = 5000.0f */)
22  : TYAbstractReflectionPathFinder(), _nbRays(nbRays), _accelerator(accelerator),
23  _maxTreeDepth(maxTreeDepth), _rayMaxLength(rayMaxLength)
24 {
25  _rcptRadius = 0.0;
26  _extrusionLength = 10.; // hard-coded value, should not have any impact on results
27 
28  // AcousticRaytracer configuration
29  _ARTSimulation.getConfiguration()->Accelerator = accelerator; // BVH data-structure
30  _ARTSimulation.getConfiguration()->MaxTreeDepth = maxTreeDepth; // BVH parameter
31  _ARTSimulation.getConfiguration()->MaxDiffraction = 0; // should disable diffractions
32  _ARTSimulation.getConfiguration()->MaxLength = rayMaxLength;
33  _ARTSimulation.getConfiguration()->UseSol = false; // disable reflections on ground triangles
34  _ARTSimulation.getConfiguration()->UsePostFilters = false; // disable non-default selectors
35  _ARTSimulation.getConfiguration()->KeepDebugRay = false; // do not store invalidated rays
36 }
37 
38 std::unique_ptr<TYAbstractReflectionPathFinder> TYReflectionPathFinderART::instanciate() const
39 {
40  return std::make_unique<TYReflectionPathFinderART>(this->_nbRays, this->_accelerator, this->_maxTreeDepth,
41  this->_rayMaxLength);
42 }
43 
44 bool TYReflectionPathFinderART::setup(size_t maxOrder, const std::deque<TYSIntersection>& tabIntersect,
45  const OPoint3D& source, const OPoint3D& receptor)
46 {
47  setupConfiguration(maxOrder);
48  if (!setupScene(tabIntersect, source, receptor))
49  {
50  return false;
51  }
53  setupSolver();
55  buildReflectionPaths(source, receptor);
56 
57  return true;
58 }
59 
61 {
62  return _paths.size() > 0;
63 }
64 
66  const OPoint3D& rcptPoint)
67 {
68  _rcptRadius = 3. * M_PI * sourcePoint.distFrom(rcptPoint) / _nbRays;
69 }
70 
72 {
73  if (_paths.size() > 0)
74  {
75  TYReflectionPath res = _paths.back();
76  _paths.pop_back();
77  return res;
78  }
79  else
80  {
81  return TYReflectionPath();
82  }
83 }
84 
86 {
89 }
90 
91 bool TYReflectionPathFinderART::setupScene(const std::deque<TYSIntersection>& tabIntersect,
92  const OPoint3D& sourcePoint, const OPoint3D& receptorPoint)
93 {
94  _ELnormal = computeELPlaneNormal(sourcePoint, receptorPoint);
95 
96  // add faces
97  for (const TYSIntersection& inter : tabIntersect)
98  {
99  if (!processIntersectingSegment(inter))
100  {
101  return false;
102  }
103  }
104 
105  // create initial rays sampler
107 
108  // add source, using the sampler
109  Source source;
110  source.setPosition(OPoint3Dtovec3(sourcePoint));
111  source.setSampler(&sampler); // no transfer of ownership
112  // it may segfault further once sampler is popped from the stack
113  source.setInitialRayCount(_nbRays);
114  _ARTSimulation.addSource(source); // a copy of the sampler is in fact hidden here using
115  // `UniformCircularSampler(UniformCircularSampler*)`
116  // in practice it does not segfault (I assume that only the copy is
117  // used when setupScene is finished)
118  // Compute receptor radius
119  computeRadiusFromDistanceSR(sourcePoint, receptorPoint);
120 
121  // add receptor
122  Recepteur receptor;
123  receptor.setPosition(OPoint3Dtovec3(receptorPoint));
124  receptor.setRadius(_rcptRadius);
125  _ARTSimulation.addRecepteur(receptor);
126 
127  return true;
128 }
129 
131 {
132  const unsigned int acceleratorID{_ARTSimulation.getConfiguration()->Accelerator};
133 
134  // this instruction builds the accelerating data-structure of the scene
135  // the second argument sets the behavior when intersections between a ray and scene elements are found:
136  // here only the first intersection is considered
138 
139  // this instruction builds the accelerating data-structure of receptors
140  // the second argument sets the behavior when intersections between a ray and scene elements are found:
141  // here only the first intersection is considered (there is only one receptor, and GridAccelerator finds
142  // multiple times the receptor with leafTreatment::ALL)
144 }
145 
147 {
148  Scene& scene = *_ARTSimulation.getScene();
149  _pSolver = std::make_unique<BasicSolver>();
150  _ARTSimulation.setSolver(_pSolver.get()); // no transfer of ownership
151 
152  // this instruction builds selectors (only a CleanerSelector and a LengthSelector using default Simulation
153  // configuration)
154  _pSolver->postTreatmentScene(&scene, _ARTSimulation.getSources(), _ARTSimulation.getRecepteurs());
155 }
156 
158 {
160 }
161 
163 {
164  for (Ray* pRay : *_pSolver->getValidRays())
165  {
166  // ignore direct path
167  const bool isReflectionPath{pRay->getNbEvents() > 0};
168  if (!isReflectionPath)
169  {
170  continue;
171  }
172 
173  // build the path assuming it is valid (to minimize TYReflectionPath constructions)
174  _paths.emplace_back();
175  TYReflectionPath& path = _paths.back();
176  path.source = source;
177  path.receptor = receptor;
178  for (boost::shared_ptr<Event> pEvent : *pRay->getEvents())
179  {
180  // it is assumed that each event is a reflection
181  const OPoint3D reflectionPoint = vec3toOPoint3D(pEvent->getPosition());
182  path.reflectionPoints.push_back(reflectionPoint);
183  const TYSIntersection* pInterReflection = _shapeToTYSIntersection[pEvent->getShape()];
184  path.reflectingSegments.push_back(pInterReflection);
185  }
186 
187  // validate the path and remove it if not valid
188  const bool validPath = isPathValid(path);
189  if (validPath)
190  {
191  _foundSequences.insert(path.reflectingSegments);
192  }
193  else
194  {
195  _paths.pop_back();
196  }
197  }
198 
200 }
201 
203 {
204  if (inter.bIntersect[1])
205  {
206  if (!inter.pFaceGeomData)
207  {
208  // should never happen
209  return false;
210  }
211 
212  const OVector3D& normal{inter.pFaceGeomData->n};
213  OPoint3D p1Top, p1Bottom, p2Top, p2Bottom;
214  buildQuadranglePointsFromInter(inter, p1Top, p1Bottom, p2Top, p2Bottom);
215  addOrientedQuadrangle(p1Top, p1Bottom, p2Top, p2Bottom, normal, inter);
216 
217  return true;
218  }
219  else
220  {
221  // do nothing with intersecting segment which do not intersect EL-place
222  return true;
223  }
224 }
225 
227  OPoint3D& p1Bottom, OPoint3D& p2Top,
228  OPoint3D& p2Bottom) const
229 {
230  const OSegment3D& segment{inter.segInter[1]};
231  const OPoint3D& p1{segment._ptA};
232  const OPoint3D& p2{segment._ptB};
233  const OVector3D upExtrusion = _ELnormal * _extrusionLength;
234  const OVector3D downExtrusion = _ELnormal * -_extrusionLength;
235  p1Top = p1 + upExtrusion;
236  p1Bottom = p1 + downExtrusion;
237  p2Top = p2 + upExtrusion;
238  p2Bottom = p2 + downExtrusion;
239 }
240 
242  const OPoint3D& p2Top, const OPoint3D& p2Bottom,
243  const OVector3D vExt,
244  const TYSIntersection& sourceInter)
245 {
246  Shape* pT1 = addOrientedTriangle(p1Bottom, p2Top, p1Top, vExt, !sourceInter.isInfra);
247  Shape* pT2 = addOrientedTriangle(p1Bottom, p2Bottom, p2Top, vExt, !sourceInter.isInfra);
248  _shapeToTYSIntersection[pT1] = &sourceInter;
249  _shapeToTYSIntersection[pT2] = &sourceInter;
250 }
251 
253  const OPoint3D& p3, const OVector3D& vExt,
254  const bool isSol)
255 {
256  Scene& scene = *_ARTSimulation.getScene();
257  unsigned int i1, i2, i3;
258 
259  const OVector3D p1p2{p1, p2};
260  const OVector3D p1p3{p1, p3};
261  const OVector3D nCandidate = p1p2.cross(p1p3);
262 
263  if (nCandidate.scalar(vExt) > 0)
264  {
265  // v1 = p1, v2 = p2, v3 = p3
266  scene.addVertex(OPoint3Dtovec3(p1), i1);
267  scene.addVertex(OPoint3Dtovec3(p2), i2);
268  scene.addVertex(OPoint3Dtovec3(p3), i3);
269  }
270  else
271  {
272  // v1 = p1, v2 = p3, v3 = p2
273  scene.addVertex(OPoint3Dtovec3(p1), i1);
274  scene.addVertex(OPoint3Dtovec3(p3), i2);
275  scene.addVertex(OPoint3Dtovec3(p2), i3);
276  }
277 
278  return scene.addTriangle(i1, i2, i3, nullptr, isSol);
279 }
280 
282 {
283  const OVector3D e3{0., 0., 1.};
284  const OVector3D v{source, receptor};
285  const OVector3D u = v.cross(e3);
286  const OVector3D n = u.cross(v); // normal vector, so that (u, v, n) is a right-handed basis
287  const OVector3D nNormalized = n * (1. / n.norme());
288  return nNormalized;
289 }
290 
292 {
293  if (isPathAlreadyFound(path))
294  {
295  return false;
296  }
298  {
299  return false;
300  }
301  return true;
302 }
303 
305 {
306  return _foundSequences.count(path.reflectingSegments) > 0;
307 }
308 
310 {
311  const OPoint3D& lastReflection = path.reflectionPoints.back();
312  const OPoint3D& receptor = path.receptor;
313 
314  const double distLastReflectionReceptor = lastReflection.distFrom(receptor);
315 
316  const OVector3D rayDirection{lastReflection, receptor};
317  Ray ray{OPoint3Dtovec3(lastReflection), OPoint3Dtovec3(rayDirection)};
318  std::list<Intersection> intersections;
319  double distToClosestElement =
320  static_cast<double>(_ARTSimulation.getScene()->getAccelerator()->traverse(&ray, intersections));
321 
322  return distToClosestElement > 0. && distToClosestElement < distLastReflectionReceptor;
323 }
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.
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...
Shape * addOrientedTriangle(const OPoint3D &p1, const OPoint3D &p2, const OPoint3D &p3, const OVector3D &vExt, const bool isSol)
Add an oriented triangle to the AcousticRaytracer' simulation scene. The vertices (v1 = p1,...
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
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.
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...
void computeRadiusFromDistanceSR(const OPoint3D &sourcePoint, const OPoint3D &rcptPoint)
Compute receiver radius from source and receiver points.
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...
#define M_PI
Pi.
Definition: color.cpp:25
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]