OGS
XmlGmlInterface.cpp
Go to the documentation of this file.
1 
15 #include "XmlGmlInterface.h"
16 
17 #include <QFile>
18 #include <QTextCodec>
19 #include <QtXml/QDomDocument>
20 
21 #include "BaseLib/Logging.h"
22 #include "GeoLib/Triangle.h"
23 
24 namespace GeoLib
25 {
26 namespace IO
27 {
29  : XMLQtInterface("OpenGeoSysGLI.xsd"), _geo_objs(geo_objs)
30 {
31 }
32 
33 int XmlGmlInterface::readFile(const QString& fileName)
34 {
35  if (XMLQtInterface::readFile(fileName) == 0)
36  {
37  return 0;
38  }
39 
40  QDomDocument doc("OGS-GLI-DOM");
41  doc.setContent(getContent());
42  QDomElement docElement = doc.documentElement(); // OpenGeoSysGLI
43  if (docElement.nodeName().compare("OpenGeoSysGLI"))
44  {
45  ERR("XmlGmlInterface::readFile() - Unexpected XML root.");
46  return 0;
47  }
48 
49  std::string gliName("[NN]");
50 
51  std::vector<GeoLib::Point*> points;
52  std::vector<GeoLib::Polyline*> polylines;
53  std::vector<GeoLib::Surface*> surfaces;
54 
58 
59  QDomNodeList geoTypes = docElement.childNodes();
60  for (int i = 0; i < geoTypes.count(); i++)
61  {
62  const QDomNode type_node(geoTypes.at(i));
63  const QString nodeName = type_node.nodeName();
64  if (nodeName.compare("name") == 0)
65  {
66  if (type_node.toElement().text().isEmpty())
67  {
68  ERR("XmlGmlInterface::readFile(): <name>-tag is empty.");
69  BaseLib::cleanupVectorElements(surfaces, polylines, points);
70  return 0;
71  }
72 
73  gliName = type_node.toElement().text().toStdString();
74  }
75  else if (nodeName.compare("points") == 0)
76  {
77  readPoints(type_node, points, &pnt_names);
78  _geo_objs.addPointVec(std::move(points), gliName,
79  std::move(pnt_names));
80  }
81  else if (nodeName.compare("polylines") == 0)
82  {
83  try
84  {
86  type_node, polylines, *_geo_objs.getPointVec(gliName),
87  _geo_objs.getPointVecObj(gliName)->getIDMap(), ply_names);
88  }
89  catch (std::runtime_error const&)
90  {
91  // further reading is aborted and it is necessary to clean up
92  _geo_objs.removePointVec(gliName);
93  throw;
94  }
95  }
96  else if (nodeName.compare("surfaces") == 0)
97  {
98  try
99  {
100  readSurfaces(
101  type_node, surfaces, *_geo_objs.getPointVec(gliName),
102  _geo_objs.getPointVecObj(gliName)->getIDMap(), sfc_names);
103  }
104  catch (std::runtime_error const&)
105  {
106  // further reading is aborted and it is necessary to clean up
107  _geo_objs.removePointVec(gliName);
108  _geo_objs.removePolylineVec(gliName);
109  throw;
110  }
111  }
112  }
113 
114  if (!polylines.empty())
115  {
116  _geo_objs.addPolylineVec(std::move(polylines), gliName,
117  std::move(ply_names));
118  }
119 
120  if (!surfaces.empty())
121  {
122  _geo_objs.addSurfaceVec(std::move(surfaces), gliName,
123  std::move(sfc_names));
124  }
125  return 1;
126 }
127 
128 void XmlGmlInterface::readPoints(const QDomNode& pointsRoot,
129  std::vector<GeoLib::Point*>& points,
130  std::map<std::string, std::size_t>* pnt_names)
131 {
132  char* pEnd;
133  QDomElement point = pointsRoot.firstChildElement();
134  while (!point.isNull())
135  {
136  _idx_map.insert(std::pair<std::size_t, std::size_t>(
137  strtol((point.attribute("id")).toStdString().c_str(), &pEnd, 10),
138  points.size()));
139  GeoLib::Point* p = new GeoLib::Point(point.attribute("x").toDouble(),
140  point.attribute("y").toDouble(),
141  point.attribute("z").toDouble(),
142  point.attribute("id").toInt());
143  if (point.hasAttribute("name"))
144  {
145  pnt_names->insert(std::pair<std::string, std::size_t>(
146  point.attribute("name").toStdString(), points.size()));
147  }
148 
149  points.push_back(p);
150  point = point.nextSiblingElement();
151  }
152 }
153 
154 void XmlGmlInterface::readPolylines(const QDomNode& polylinesRoot,
155  std::vector<GeoLib::Polyline*>& polylines,
156  std::vector<GeoLib::Point*> const& points,
157  const std::vector<std::size_t>& pnt_id_map,
159 {
160  QDomElement polyline = polylinesRoot.firstChildElement();
161  while (!polyline.isNull())
162  {
163  std::size_t const idx = polylines.size();
164  polylines.push_back(new GeoLib::Polyline(points));
165 
166  if (polyline.hasAttribute("name"))
167  {
168  std::string const ply_name(
169  polyline.attribute("name").toStdString());
170  std::map<std::string, std::size_t>::const_iterator it(
171  ply_names.find(ply_name));
172  if (it == ply_names.end())
173  {
174  ply_names.insert(
175  std::pair<std::string, std::size_t>(ply_name, idx));
176  }
177  else
178  {
179  WARN(
180  "Polyline '{:s}' exists already. Polyline {:d} will be "
181  "inserted without a name.",
182  ply_name, idx);
183  }
184  }
185 
186  QDomElement point = polyline.firstChildElement();
187  auto accessOrError = [this, &polyline](auto pt_idx)
188  {
189  auto search = _idx_map.find(pt_idx);
190  if (search == _idx_map.end())
191  {
192  std::string polyline_name;
193  if (polyline.hasAttribute("name"))
194  {
195  polyline_name = polyline.attribute("name").toStdString();
196  }
197  OGS_FATAL(
198  "Polyline `{:s}' contains the point id `{:d}' which is not "
199  "in the point list.",
200  polyline_name, pt_idx);
201  }
202  return search->second;
203  };
204 
205  while (!point.isNull())
206  {
207  polylines[idx]->addPoint(
208  pnt_id_map[accessOrError(point.text().toInt())]);
209  point = point.nextSiblingElement();
210  }
211 
212  polyline = polyline.nextSiblingElement();
213  }
214 }
215 
216 void XmlGmlInterface::readSurfaces(const QDomNode& surfacesRoot,
217  std::vector<GeoLib::Surface*>& surfaces,
218  std::vector<GeoLib::Point*> const& points,
219  const std::vector<std::size_t>& pnt_id_map,
221 {
222  QDomElement surface = surfacesRoot.firstChildElement();
223  while (!surface.isNull())
224  {
225  surfaces.push_back(new GeoLib::Surface(points));
226 
227  if (surface.hasAttribute("name"))
228  {
229  sfc_names.insert(std::pair<std::string, std::size_t>(
230  surface.attribute("name").toStdString(), surfaces.size() - 1));
231  }
232 
233  auto accessOrError = [this, &surface](auto pt_idx)
234  {
235  auto search = _idx_map.find(pt_idx);
236  if (search == _idx_map.end())
237  {
238  std::string surface_name;
239  if (surface.hasAttribute("name"))
240  {
241  surface_name = surface.attribute("name").toStdString();
242  }
243  OGS_FATAL(
244  "Surface `{:s}' contains the point id `{:d}', which is not "
245  "in the point list.",
246  surface_name, pt_idx);
247  }
248  return search->second;
249  };
250 
251  QDomElement element = surface.firstChildElement();
252  while (!element.isNull())
253  {
254  std::size_t p1 =
255  pnt_id_map[accessOrError(element.attribute("p1").toInt())];
256  std::size_t p2 =
257  pnt_id_map[accessOrError(element.attribute("p2").toInt())];
258  std::size_t p3 =
259  pnt_id_map[accessOrError(element.attribute("p3").toInt())];
260  surfaces.back()->addTriangle(p1, p2, p3);
261  element = element.nextSiblingElement();
262  }
263 
264  surface = surface.nextSiblingElement();
265  }
266 }
268 {
269  if (export_name.empty())
270  {
271  ERR("XmlGmlInterface::write(): No geometry specified.");
272  return false;
273  }
274 
275  out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml
276  // definition
277 
278  QDomDocument doc("OGS-GML-DOM");
279  QDomElement root = doc.createElement("OpenGeoSysGLI");
280  root.setAttribute("xmlns:ogs", "http://www.opengeosys.org");
281  root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
282 
283  doc.appendChild(root);
284 
285  QDomElement geoNameTag = doc.createElement("name");
286  root.appendChild(geoNameTag);
287  QDomText geoNameText =
288  doc.createTextNode(QString::fromStdString(export_name));
289  geoNameTag.appendChild(geoNameText);
290 
291  // POINTS
292  QDomElement pointsListTag = doc.createElement("points");
293  root.appendChild(pointsListTag);
294 
296  if (pnt_vec)
297  {
298  auto const& points(pnt_vec->getVector());
299 
300  if (!points.empty())
301  {
302  auto const nPoints = points.size();
303  for (std::size_t i = 0; i < nPoints; i++)
304  {
305  QDomElement pointTag = doc.createElement("point");
306  pointTag.setAttribute("id", QString::number(i));
307  pointTag.setAttribute(
308  "x",
309  QString::number((*points[i])[0], 'f',
310  std::numeric_limits<double>::digits10));
311  pointTag.setAttribute(
312  "y",
313  QString::number((*points[i])[1], 'f',
314  std::numeric_limits<double>::digits10));
315  pointTag.setAttribute(
316  "z",
317  QString::number((*points[i])[2], 'f',
318  std::numeric_limits<double>::digits10));
319 
320  std::string const& point_name(pnt_vec->getItemNameByID(i));
321  if (!point_name.empty())
322  {
323  pointTag.setAttribute("name",
324  QString::fromStdString(point_name));
325  }
326 
327  pointsListTag.appendChild(pointTag);
328  }
329  }
330  else
331  {
332  ERR("XmlGmlInterface::write(): Point vector is empty, abort "
333  "writing geometry.");
334  return false;
335  }
336  }
337  else
338  {
339  ERR("XmlGmlInterface::write(): No point vector found, abort writing "
340  "geometry.");
341  return false;
342  }
343 
344  // POLYLINES
345  const GeoLib::PolylineVec* ply_vec(
347  if (ply_vec)
348  {
349  auto const& polylines(ply_vec->getVector());
350 
351  if (!polylines.empty())
352  {
353  QDomElement plyListTag = doc.createElement("polylines");
354  root.appendChild(plyListTag);
355  auto const nPolylines = polylines.size();
356  for (std::size_t i = 0; i < nPolylines; i++)
357  {
358  QDomElement polylineTag = doc.createElement("polyline");
359  polylineTag.setAttribute("id", QString::number(i));
360 
361  std::string ply_name;
362  if (ply_vec->getNameOfElementByID(i, ply_name))
363  {
364  polylineTag.setAttribute("name",
365  QString::fromStdString(ply_name));
366  }
367  else
368  {
369  ply_name = std::to_string(i);
370  polylineTag.setAttribute("name",
371  QString::fromStdString(ply_name));
372  }
373 
374  plyListTag.appendChild(polylineTag);
375 
376  auto const nPoints = polylines[i]->getNumberOfPoints();
377  for (std::size_t j = 0; j < nPoints; j++)
378  {
379  QDomElement plyPointTag = doc.createElement("pnt");
380  polylineTag.appendChild(plyPointTag);
381  QDomText plyPointText = doc.createTextNode(
382  QString::number((polylines[i])->getPointID(j)));
383  plyPointTag.appendChild(plyPointText);
384  }
385  }
386  }
387  }
388  else
389  {
390  INFO(
391  "XmlGmlInterface::write(): Polyline vector is empty, no polylines "
392  "written to file.");
393  }
394 
395  // SURFACES
397  if (sfc_vec)
398  {
399  auto const& surfaces(sfc_vec->getVector());
400 
401  if (!surfaces.empty())
402  {
403  QDomElement sfcListTag = doc.createElement("surfaces");
404  root.appendChild(sfcListTag);
405  auto const nSurfaces = surfaces.size();
406  for (std::size_t i = 0; i < nSurfaces; i++)
407  {
408  QDomElement surfaceTag = doc.createElement("surface");
409  surfaceTag.setAttribute("id", QString::number(i));
410 
411  std::string sfc_name;
412  if (sfc_vec->getNameOfElementByID(i, sfc_name))
413  {
414  surfaceTag.setAttribute("name",
415  QString::fromStdString(sfc_name));
416  }
417 
418  sfcListTag.appendChild(surfaceTag);
419 
420  // writing the elements compromising the surface
421  std::size_t nElements = (surfaces[i])->getNumberOfTriangles();
422  for (std::size_t j = 0; j < nElements; j++)
423  {
424  QDomElement elementTag = doc.createElement("element");
425  elementTag.setAttribute(
426  "p1", QString::number((*(*surfaces[i])[j])[0]));
427  elementTag.setAttribute(
428  "p2", QString::number((*(*surfaces[i])[j])[1]));
429  elementTag.setAttribute(
430  "p3", QString::number((*(*surfaces[i])[j])[2]));
431  surfaceTag.appendChild(elementTag);
432  }
433  }
434  }
435  else
436  {
437  INFO(
438  "XmlGmlInterface::write(): Surface vector is empty, no "
439  "surfaces written to file.");
440  }
441  }
442  else
443  {
444  INFO(
445  "XmlGmlInterface::write(): Surface vector is empty, no surfaces "
446  "written to file.");
447  }
448 
449  std::string xml = doc.toString().toStdString();
450  out << xml;
451 
452  return true;
453 }
454 
455 } // namespace IO
456 } // namespace GeoLib
#define OGS_FATAL(...)
Definition: Error.h:26
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:32
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:42
void WARN(char const *fmt, Args const &... args)
Definition: Logging.h:37
Definition of the XmlGmlInterface class.
std::ostringstream out
The stream to write to.
Definition: Writer.h:46
QByteArray const & getContent() const
Container class for geometric objects.
Definition: GEOObjects.h:61
void addPolylineVec(std::vector< Polyline * > &&lines, std::string const &name, PolylineVec::NameIdMap &&ply_names)
Definition: GEOObjects.cpp:152
const std::vector< Point * > * getPointVec(const std::string &name) const
Definition: GEOObjects.cpp:72
void addPointVec(std::vector< Point * > &&points, std::string &name, PointVec::NameIdMap &&pnt_id_name_map, double const eps=std::sqrt(std::numeric_limits< double >::epsilon()))
Definition: GEOObjects.cpp:47
const PointVec * getPointVecObj(const std::string &name) const
Definition: GEOObjects.cpp:85
bool removePointVec(const std::string &name)
Definition: GEOObjects.cpp:98
SurfaceVec * getSurfaceVecObj(const std::string &name)
Returns the surface vector with the given name.
Definition: GEOObjects.h:211
void addSurfaceVec(std::vector< Surface * > &&sfc, const std::string &name, SurfaceVec::NameIdMap &&sfc_names)
Definition: GEOObjects.cpp:240
const PolylineVec * getPolylineVecObj(const std::string &name) const
Definition: GEOObjects.cpp:206
bool removePolylineVec(const std::string &name)
Definition: GEOObjects.cpp:222
void readPoints(const QDomNode &pointsRoot, std::vector< GeoLib::Point * > &points, std::map< std::string, std::size_t > *pnt_names)
Reads GeoLib::Point-objects from an xml-file.
std::map< std::size_t, std::size_t > _idx_map
bool write() override
Writes the object to the internal stream. This method must be implemented by a subclass....
GeoLib::GEOObjects & _geo_objs
void readSurfaces(const QDomNode &surfacesRoot, std::vector< GeoLib::Surface * > &surfaces, std::vector< GeoLib::Point * > const &points, const std::vector< std::size_t > &pnt_id_map, GeoLib::SurfaceVec::NameIdMap &sfc_names)
Reads GeoLib::Surface-objects from an xml-file.
void readPolylines(const QDomNode &polylinesRoot, std::vector< GeoLib::Polyline * > &polylines, std::vector< GeoLib::Point * > const &points, const std::vector< std::size_t > &pnt_id_map, GeoLib::PolylineVec::NameIdMap &ply_names)
Reads GeoLib::Polyline-objects from an xml-file.
XmlGmlInterface(GeoLib::GEOObjects &geo_objs)
int readFile(const QString &fileName) override
Reads an xml-file containing geometric object definitions into the GEOObjects used in the constructor...
This class manages pointers to Points in a std::vector along with a name. It also handles the deletio...
Definition: PointVec.h:38
const std::vector< std::size_t > & getIDMap() const
Definition: PointVec.h:96
std::string const & getItemNameByID(std::size_t id) const
Definition: PointVec.cpp:248
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition: Polyline.h:53
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
Definition: Surface.h:34
The class TemplateVec takes a unique name and manages a std::vector of pointers to data elements of t...
Definition: TemplateVec.h:41
std::map< std::string, std::size_t > NameIdMap
Definition: TemplateVec.h:44
bool getNameOfElementByID(std::size_t id, std::string &element_name) const
Definition: TemplateVec.h:151
std::vector< T * > const & getVector() const
Definition: TemplateVec.h:109
void cleanupVectorElements(std::vector< T * > &items)
Definition: Algorithm.h:300
bool readFile(std::string const &file_name, std::vector< std::unique_ptr< MeshLib::Mesh >> &meshes, DataType const export_type)
Reads the specified file and writes data into internal mesh vector.
TemplateElement< PointRule1 > Point
Definition: Point.h:20