Code_TYMPAN  4.4.0
Industrial site acoustic simulation
TYIGNLevelCurvesParser.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 // TYIGNLevelCurvesParser.cpp
17 #include "TYIGNLevelCurvesParser.h"
18 #include "Tympan/core/logging.h"
19 
21  : QObject(parent), m_isXmlLoaded(false), m_hasRetrievedLevelCurves(false)
22 {
23 }
24 
26 {
28  m_isXmlLoaded = false;
29  m_xmlDocument.clear();
30  m_ct.clear();
31 }
32 
33 bool TYIGNLevelCurvesParser::loadXmlFile(const QString& filePath)
34 {
35  QFile file(filePath);
36  if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
37  {
38  qDebug() << "Failed to open XML file for reading:" << file.errorString();
39  return false;
40  }
41 
42  QDomDocument newDocument;
43  if (!newDocument.setContent(&file))
44  {
45  qDebug() << "Failed to set XML content from file";
46  file.close();
47  return false;
48  }
49 
50  file.close();
51 
52  // Copy the content of the newly loaded document to the member variable
53  m_xmlDocument = newDocument;
54  m_isXmlLoaded = true;
56  return true;
57 }
58 
59 void TYIGNLevelCurvesParser::parseXmlData(const OCoord3D& SIGCoords, const OBox& selectedZone,
60  double scaleFactor)
61 {
63  {
64  qDebug() << "Level curves have not been retrieved.";
65  return;
66  }
67 
68  if (!m_isXmlLoaded)
69  {
70  qDebug() << "XML document is not loaded.";
71  return;
72  }
73 
74  buildCTFromXMLFile(SIGCoords);
76  createLevelCurvesFromCT(SIGCoords, selectedZone, scaleFactor);
77 }
78 
80 {
81  bool ret = false;
82  if (text.isEmpty())
83  {
85  }
86  else
87  {
89  QDomDocument newDocument;
90  if (!newDocument.setContent(text))
91  {
92  qDebug() << "Failed to set XML content from text";
93  }
94  else
95  {
96  // Copy the content of the newly constructed document to the member variable
97  m_xmlDocument = newDocument;
98  m_isXmlLoaded = true;
99  ret = true;
100  }
101  }
102  return ret;
103 }
104 
106 {
107  QDomElement root = m_xmlDocument.documentElement();
108  QDomNodeList courbeList = root.elementsByTagName("ELEVATION.CONTOUR.LINE:courbe");
109 
110  OMessageManager::get()->debug(QString("Number of courbe elements found: %1").arg(courbeList.size()));
111 
112  for (int i = 0; i < courbeList.size(); ++i)
113  {
114  QDomElement courbe = courbeList.at(i).toElement();
115  buildPolylineFromCourbe(courbe, SIGCoords);
116  }
117 
118  return true;
119 }
120 
121 bool TYIGNLevelCurvesParser::buildPolylineFromCourbe(const QDomElement& courbe, const OCoord3D& SIGCoords)
122 {
123  QString id = courbe.attribute("gml:id");
124  OMessageManager::get()->debug(QString("Courbe ID: %1").arg(id));
125 
126  double altitude = courbe.firstChildElement("ELEVATION.CONTOUR.LINE:altitude").text().toDouble();
127  OMessageManager::get()->debug(QString("Altitude: %1").arg(altitude));
128 
129  AltimetryInfo altiInfo(id, altitude);
130 
131  QDomElement geom =
132  courbe.firstChildElement("ELEVATION.CONTOUR.LINE:geom").firstChildElement("gml:LineString");
133  QString srsName = geom.attribute("srsName");
134  OMessageManager::get()->debug(QString("SRS Name: %1").arg(srsName));
135 
136  QString posList = geom.firstChildElement("gml:posList").text();
137  QStringList points = posList.split(" ");
138  OMessageManager::get()->debug(QString("Number of points: %1").arg(points.size() / 2));
139 
140  Point currentPoint;
141  std::vector<Point> CGALpoints;
142  int currentIndex = 0;
143 
144  while (currentIndex < points.size())
145  {
146  currentPoint = getCGALPoint(points, currentIndex, SIGCoords, altitude);
147  CGALpoints.push_back(currentPoint);
148  currentIndex += 2;
149  }
150 
151  auto constraint_id = m_ct.insert_constraint(CGALpoints);
152 
153  // Associate AltimetryInfo with the constraint
154  // Wrap the Constraint_id
155  ConstraintIdWrapper wrapped_id(constraint_id);
156  m_constraintToAltimetryInfoMap[wrapped_id] = altiInfo;
157 
158  return true;
159 }
160 
162 {
163  size_t nb_removed_vertices = 0;
164  double dStopParam = 0.25;
165  nb_removed_vertices = PS::simplify(m_ct, Cost(), Stop(dStopParam));
166  return nb_removed_vertices;
167 }
168 
169 bool TYIGNLevelCurvesParser::createLevelCurvesFromCT(const OCoord3D& SIGCoords, const OBox& selectedZone,
170  double scaleFactor)
171 {
172  bool ret = true;
173  OBox selectedZoneTympanCoords{selectedZone};
174  selectedZoneTympanCoords.Translate(OVector3D() - OVector3D(SIGCoords));
175 
176  for (Constraint_iterator constraint_it = m_ct.constraints_begin();
177  constraint_it != m_ct.constraints_end(); ++constraint_it)
178  {
179  Constraint_id constraint_id = *constraint_it;
180  // Wrap the Constraint_id
181  ConstraintIdWrapper wrapped_id(constraint_id);
182 
183  auto it = getConstraintToAltimetryInfoMap().find(wrapped_id);
184  if (it == getConstraintToAltimetryInfoMap().end())
185  {
186  return false;
187  }
188 
189  const TYIGNLevelCurvesParser::AltimetryInfo& info = it->second;
190  QString id = info.id;
191  double altitude = info.altitude;
192 
193  TYPoint currentPoint;
194  auto vit = m_ct.points_in_constraint_begin(constraint_id);
195 
196  while (vit != m_ct.points_in_constraint_end(constraint_id))
197  {
198  // Search for first point of level curve inside selected zone
199  bool firstPointFound = false;
200  while (!firstPointFound && vit != m_ct.points_in_constraint_end(constraint_id))
201  {
202  currentPoint = TYPoint{vit->x(), vit->y(), altitude};
203  // getPoint(points, currentIndex, SIGCoords, altitude);
204  firstPointFound = selectedZoneTympanCoords.isInside2D(currentPoint);
205  vit++;
206  }
207  // If a first point is found
208  if (firstPointFound)
209  {
210  TYTabPoint listPoints;
211  // Add first point to level curve
212  TYPoint fistPointTympanCoords{currentPoint._x * scaleFactor, currentPoint._y * scaleFactor,
213  currentPoint._z};
214  listPoints.push_back(fistPointTympanCoords);
215  // Then add all following points inside zone to the level curve
216  bool isPointInsideZone = true;
217  while (isPointInsideZone && vit != m_ct.points_in_constraint_end(constraint_id))
218  {
219  currentPoint = TYPoint{vit->x(), vit->y(), altitude};
220  isPointInsideZone = selectedZoneTympanCoords.isInside2D(currentPoint);
221  if (isPointInsideZone)
222  {
223  TYPoint newPointTympanCoords{currentPoint._x * scaleFactor,
224  currentPoint._y * scaleFactor, currentPoint._z};
225  listPoints.push_back(newPointTympanCoords);
226  }
227  vit++;
228  }
229  // If there are at least two points then create the level curve
230  if (listPoints.size() >= 2)
231  {
232  LPTYCourbeNiveau crb = new TYCourbeNiveau();
233  crb->setName(id);
234  crb->setAltitude(altitude);
235  crb->setListPoints(listPoints);
236  // Emit signal with the created TYCourbeNiveau object
237  emit courbeNiveauCreated(crb);
238  }
239  }
240  }
241  }
242  return ret;
243 }
244 
246 {
247  TYPoint result;
248 
249  const double earthRadius = 6378137.0; // Earth radius in meters
250  const double originShift = 2.0 * M_PI * earthRadius / 2.0;
251 
252  result._x = longitude * originShift / 180.0;
253  result._y = log(tan((90.0 + latitude) * M_PI / 360.0)) / (M_PI / 180.0);
254  result._y = result._y * originShift / 180.0;
255 
256  return result;
257 }
258 
259 TYPoint TYIGNLevelCurvesParser::getPoint(const QStringList& points, int index, const OCoord3D& SIGCoords,
260  double altitude)
261 {
262  double latitude = points[index].toDouble();
263  double longitude = points[index + 1].toDouble(); // Longitude comes after latitude in the XML
264 
265  // Project each point to EPSG:3857
266  TYPoint projectedPoint = convertLatLonToWebMercator(latitude, longitude);
267  projectedPoint._x -= SIGCoords._x;
268  projectedPoint._y -= SIGCoords._y;
269  projectedPoint._z = altitude;
270 
271  return projectedPoint;
272 }
273 
274 Point TYIGNLevelCurvesParser::getCGALPoint(const QStringList& points, int index, const OCoord3D& SIGCoords,
275  double altitude)
276 {
277  TYPoint tyPoint = getPoint(points, index, SIGCoords, altitude);
278  Point ret{tyPoint._x, tyPoint._y};
279  return ret;
280 }
std::vector< TYPoint > TYTabPoint
Collection de TYPoint.
Definition: TYDefines.h:340
PS::Stop_below_count_ratio_threshold Stop
CT::Constraint_iterator Constraint_iterator
CT::Point Point
PS::Scaled_squared_distance_cost Cost
CT::Constraint_id Constraint_id
The box class.
Definition: 3d.h:1346
virtual void Translate(const OPoint3D &vectorTranslate)
Translate this box.
Definition: 3d.cpp:1688
The 3D coordinate class.
Definition: 3d.h:226
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
virtual void debug(const char *message,...)
Definition: logging.cpp:151
static OMessageManager * get()
Definition: logging.cpp:108
The 3D vector class.
Definition: 3d.h:298
void setListPoints(const TYTabPoint &pts)
void setAltitude(double alt)
void setName(QString name)
Definition: TYElement.h:669
std::unordered_map< ConstraintIdWrapper, AltimetryInfo > & getConstraintToAltimetryInfoMap()
Getter for the constraint to AltimetryInfo map.
TYIGNLevelCurvesParser(QObject *parent=nullptr)
std::unordered_map< ConstraintIdWrapper, AltimetryInfo > m_constraintToAltimetryInfoMap
void courbeNiveauCreated(LPTYCourbeNiveau courbeNiveau)
static Point getCGALPoint(const QStringList &points, int index, const OCoord3D &SIGCoords, double altitude)
bool createLevelCurvesFromCT(const OCoord3D &SIGCoords, const OBox &selectedZone, double scaleFactor)
Create level curves from CGAL constrained triangulation.
bool buildXmlDocument(const QString &text)
bool buildCTFromXMLFile(const OCoord3D &SIGCoords)
Build constrained triangulation from IGN XML file containing level curves.
bool buildPolylineFromCourbe(const QDomElement &courbe, const OCoord3D &SIGCoords)
static TYPoint getPoint(const QStringList &points, int index, const OCoord3D &SIGCoords, double altitude)
void parseXmlData(const OCoord3D &SIGCoords, const OBox &selectedZone, double scaleFactor)
bool loadXmlFile(const QString &filePath)
static TYPoint convertLatLonToWebMercator(double latitude, double longitude)
#define M_PI
Pi.
Definition: color.cpp:25