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
25 {
26 void deletePolylines(std::unique_ptr<std::vector<GeoLib::Polyline*>> polylines)
27 {
28  for (GeoLib::Polyline* line : *polylines)
29  {
30  delete line;
31  }
32 }
33 
34 void deleteSurfaces(std::unique_ptr<std::vector<GeoLib::Surface*>> surfaces)
35 {
36  for (GeoLib::Surface* surface : *surfaces)
37  {
38  delete surface;
39  }
40 }
41 void deleteGeometry(std::unique_ptr<std::vector<GeoLib::Point*>> points,
42  std::unique_ptr<std::vector<GeoLib::Polyline*>>
43  polylines,
44  std::unique_ptr<std::vector<GeoLib::Surface*>>
45  surfaces)
46 {
47  for (GeoLib::Point* point : *points)
48  {
49  delete point;
50  }
51  deletePolylines(std::move(polylines));
52  deleteSurfaces(std::move(surfaces));
53 }
54 } // namespace
55 
56 namespace GeoLib
57 {
58 namespace IO
59 {
61  : XMLQtInterface("OpenGeoSysGLI.xsd"), _geo_objs(geo_objs)
62 {
63 }
64 
65 int XmlGmlInterface::readFile(const QString& fileName)
66 {
67  if (XMLQtInterface::readFile(fileName) == 0)
68  {
69  return 0;
70  }
71 
72  QDomDocument doc("OGS-GLI-DOM");
73  doc.setContent(getContent());
74  QDomElement docElement = doc.documentElement(); // OpenGeoSysGLI
75  if (docElement.nodeName().compare("OpenGeoSysGLI"))
76  {
77  ERR("XmlGmlInterface::readFile() - Unexpected XML root.");
78  return 0;
79  }
80 
81  std::string gliName("[NN]");
82 
83  auto points = std::make_unique<std::vector<GeoLib::Point*>>();
84  auto polylines = std::make_unique<std::vector<GeoLib::Polyline*>>();
85  auto surfaces = std::make_unique<std::vector<GeoLib::Surface*>>();
86 
87  using MapNameId = std::map<std::string, std::size_t>;
88  auto pnt_names = std::make_unique<MapNameId>();
89  auto ply_names = std::make_unique<MapNameId>();
90  auto sfc_names = std::make_unique<MapNameId>();
91 
92  QDomNodeList geoTypes = docElement.childNodes();
93  for (int i = 0; i < geoTypes.count(); i++)
94  {
95  const QDomNode type_node(geoTypes.at(i));
96  const QString nodeName = type_node.nodeName();
97  if (nodeName.compare("name") == 0)
98  {
99  if (type_node.toElement().text().isEmpty())
100  {
101  ERR("XmlGmlInterface::readFile(): <name>-tag is empty.");
102  deleteGeometry(std::move(points), std::move(polylines),
103  std::move(surfaces));
104  return 0;
105  }
106 
107  gliName = type_node.toElement().text().toStdString();
108  }
109  else if (nodeName.compare("points") == 0)
110  {
111  readPoints(type_node, points.get(), pnt_names.get());
112 
113  // if names-map is empty, set it to nullptr because it is not needed
114  if (pnt_names->empty())
115  {
116  pnt_names.reset(nullptr);
117  }
118  _geo_objs.addPointVec(std::move(points), gliName,
119  std::move(pnt_names));
120  }
121  else if (nodeName.compare("polylines") == 0)
122  {
123  try
124  {
125  readPolylines(type_node, polylines.get(),
126  *_geo_objs.getPointVec(gliName),
127  _geo_objs.getPointVecObj(gliName)->getIDMap(),
128  ply_names.get());
129  }
130  catch (std::runtime_error const&)
131  {
132  // further reading is aborted and it is necessary to clean up
133  _geo_objs.removePointVec(gliName);
134  throw;
135  }
136  // if names-map is empty, set it to nullptr because it is not needed
137  if (ply_names->empty())
138  {
139  ply_names.reset(nullptr);
140  }
141  }
142  else if (nodeName.compare("surfaces") == 0)
143  {
144  try
145  {
146  readSurfaces(type_node, surfaces.get(),
147  *_geo_objs.getPointVec(gliName),
148  _geo_objs.getPointVecObj(gliName)->getIDMap(),
149  sfc_names.get());
150  }
151  catch (std::runtime_error const&)
152  {
153  // further reading is aborted and it is necessary to clean up
154  _geo_objs.removePointVec(gliName);
155  _geo_objs.removePolylineVec(gliName);
156  throw;
157  }
158 
159  // if names-map is empty, set it to nullptr because it is not needed
160  if (sfc_names->empty())
161  {
162  sfc_names.reset(nullptr);
163  }
164  }
165  }
166 
167  if (!polylines->empty())
168  {
169  _geo_objs.addPolylineVec(std::move(polylines), gliName,
170  std::move(ply_names));
171  }
172 
173  if (!surfaces->empty())
174  {
175  _geo_objs.addSurfaceVec(std::move(surfaces), gliName,
176  std::move(sfc_names));
177  }
178  return 1;
179 }
180 
181 void XmlGmlInterface::readPoints(const QDomNode& pointsRoot,
182  std::vector<GeoLib::Point*>* points,
183  std::map<std::string, std::size_t>* pnt_names)
184 {
185  char* pEnd;
186  QDomElement point = pointsRoot.firstChildElement();
187  while (!point.isNull())
188  {
189  _idx_map.insert(std::pair<std::size_t, std::size_t>(
190  strtol((point.attribute("id")).toStdString().c_str(), &pEnd, 10),
191  points->size()));
192  GeoLib::Point* p = new GeoLib::Point(point.attribute("x").toDouble(),
193  point.attribute("y").toDouble(),
194  point.attribute("z").toDouble(),
195  point.attribute("id").toInt());
196  if (point.hasAttribute("name"))
197  {
198  pnt_names->insert(std::pair<std::string, std::size_t>(
199  point.attribute("name").toStdString(), points->size()));
200  }
201 
202  points->push_back(p);
203  point = point.nextSiblingElement();
204  }
205 }
206 
208  const QDomNode& polylinesRoot,
209  std::vector<GeoLib::Polyline*>* polylines,
210  std::vector<GeoLib::Point*> const& points,
211  const std::vector<std::size_t>& pnt_id_map,
212  std::map<std::string, std::size_t>* ply_names)
213 {
214  QDomElement polyline = polylinesRoot.firstChildElement();
215  while (!polyline.isNull())
216  {
217  std::size_t const idx = polylines->size();
218  polylines->push_back(new GeoLib::Polyline(points));
219 
220  if (polyline.hasAttribute("name"))
221  {
222  std::string const ply_name(
223  polyline.attribute("name").toStdString());
224  std::map<std::string, std::size_t>::const_iterator it(
225  ply_names->find(ply_name));
226  if (it == ply_names->end())
227  {
228  ply_names->insert(
229  std::pair<std::string, std::size_t>(ply_name, idx));
230  }
231  else
232  {
233  WARN(
234  "Polyline '{:s}' exists already. Polyline {:d} will be "
235  "inserted without a name.",
236  ply_name, idx);
237  }
238  }
239 
240  QDomElement point = polyline.firstChildElement();
241  auto accessOrError = [this, &polyline](auto pt_idx)
242  {
243  auto search = _idx_map.find(pt_idx);
244  if (search == _idx_map.end())
245  {
246  std::string polyline_name;
247  if (polyline.hasAttribute("name"))
248  {
249  polyline_name = polyline.attribute("name").toStdString();
250  }
251  OGS_FATAL(
252  "Polyline `{:s}' contains the point id `{:d}' which is not "
253  "in the point list.",
254  polyline_name, pt_idx);
255  }
256  return search->second;
257  };
258 
259  while (!point.isNull())
260  {
261  (*polylines)[idx]->addPoint(
262  pnt_id_map[accessOrError(point.text().toInt())]);
263  point = point.nextSiblingElement();
264  }
265 
266  polyline = polyline.nextSiblingElement();
267  }
268 }
269 
271  const QDomNode& surfacesRoot,
272  std::vector<GeoLib::Surface*>* surfaces,
273  std::vector<GeoLib::Point*> const& points,
274  const std::vector<std::size_t>& pnt_id_map,
275  std::map<std::string, std::size_t>* sfc_names)
276 {
277  QDomElement surface = surfacesRoot.firstChildElement();
278  while (!surface.isNull())
279  {
280  surfaces->push_back(new GeoLib::Surface(points));
281 
282  if (surface.hasAttribute("name"))
283  {
284  sfc_names->insert(std::pair<std::string, std::size_t>(
285  surface.attribute("name").toStdString(), surfaces->size() - 1));
286  }
287 
288  auto accessOrError = [this, &surface](auto pt_idx)
289  {
290  auto search = _idx_map.find(pt_idx);
291  if (search == _idx_map.end())
292  {
293  std::string surface_name;
294  if (surface.hasAttribute("name"))
295  {
296  surface_name = surface.attribute("name").toStdString();
297  }
298  OGS_FATAL(
299  "Surface `{:s}' contains the point id `{:d}', which is not "
300  "in the point list.",
301  surface_name, pt_idx);
302  }
303  return search->second;
304  };
305 
306  QDomElement element = surface.firstChildElement();
307  while (!element.isNull())
308  {
309  std::size_t p1 =
310  pnt_id_map[accessOrError(element.attribute("p1").toInt())];
311  std::size_t p2 =
312  pnt_id_map[accessOrError(element.attribute("p2").toInt())];
313  std::size_t p3 =
314  pnt_id_map[accessOrError(element.attribute("p3").toInt())];
315  surfaces->back()->addTriangle(p1, p2, p3);
316  element = element.nextSiblingElement();
317  }
318 
319  surface = surface.nextSiblingElement();
320  }
321 }
323 {
324  if (export_name.empty())
325  {
326  ERR("XmlGmlInterface::write(): No geometry specified.");
327  return false;
328  }
329 
330  out << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"; // xml
331  // definition
332 
333  QDomDocument doc("OGS-GML-DOM");
334  QDomElement root = doc.createElement("OpenGeoSysGLI");
335  root.setAttribute("xmlns:ogs", "http://www.opengeosys.org");
336  root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
337 
338  doc.appendChild(root);
339 
340  QDomElement geoNameTag = doc.createElement("name");
341  root.appendChild(geoNameTag);
342  QDomText geoNameText =
343  doc.createTextNode(QString::fromStdString(export_name));
344  geoNameTag.appendChild(geoNameText);
345 
346  // POINTS
347  QDomElement pointsListTag = doc.createElement("points");
348  root.appendChild(pointsListTag);
349 
351  if (pnt_vec)
352  {
353  const std::vector<GeoLib::Point*>* points(pnt_vec->getVector());
354 
355  if (!points->empty())
356  {
357  auto const nPoints = points->size();
358  for (std::size_t i = 0; i < nPoints; i++)
359  {
360  QDomElement pointTag = doc.createElement("point");
361  pointTag.setAttribute("id", QString::number(i));
362  pointTag.setAttribute(
363  "x",
364  QString::number((*(*points)[i])[0], 'f',
365  std::numeric_limits<double>::digits10));
366  pointTag.setAttribute(
367  "y",
368  QString::number((*(*points)[i])[1], 'f',
369  std::numeric_limits<double>::digits10));
370  pointTag.setAttribute(
371  "z",
372  QString::number((*(*points)[i])[2], 'f',
373  std::numeric_limits<double>::digits10));
374 
375  std::string const& point_name(pnt_vec->getItemNameByID(i));
376  if (!point_name.empty())
377  {
378  pointTag.setAttribute("name",
379  QString::fromStdString(point_name));
380  }
381 
382  pointsListTag.appendChild(pointTag);
383  }
384  }
385  else
386  {
387  ERR("XmlGmlInterface::write(): Point vector is empty, abort "
388  "writing geometry.");
389  return false;
390  }
391  }
392  else
393  {
394  ERR("XmlGmlInterface::write(): No point vector found, abort writing "
395  "geometry.");
396  return false;
397  }
398 
399  // POLYLINES
400  const GeoLib::PolylineVec* ply_vec(
402  if (ply_vec)
403  {
404  const std::vector<GeoLib::Polyline*>* polylines(ply_vec->getVector());
405 
406  if (polylines)
407  {
408  if (!polylines->empty())
409  {
410  QDomElement plyListTag = doc.createElement("polylines");
411  root.appendChild(plyListTag);
412  auto const nPolylines = polylines->size();
413  for (std::size_t i = 0; i < nPolylines; i++)
414  {
415  QDomElement polylineTag = doc.createElement("polyline");
416  polylineTag.setAttribute("id", QString::number(i));
417 
418  std::string ply_name;
419  if (ply_vec->getNameOfElementByID(i, ply_name))
420  {
421  polylineTag.setAttribute(
422  "name", QString::fromStdString(ply_name));
423  }
424  else
425  {
426  ply_name = std::to_string(i);
427  polylineTag.setAttribute(
428  "name", QString::fromStdString(ply_name));
429  }
430 
431  plyListTag.appendChild(polylineTag);
432 
433  auto const nPoints = (*polylines)[i]->getNumberOfPoints();
434  for (std::size_t j = 0; j < nPoints; j++)
435  {
436  QDomElement plyPointTag = doc.createElement("pnt");
437  polylineTag.appendChild(plyPointTag);
438  QDomText plyPointText = doc.createTextNode(
439  QString::number(((*polylines)[i])->getPointID(j)));
440  plyPointTag.appendChild(plyPointText);
441  }
442  }
443  }
444  else
445  {
446  INFO(
447  "XmlGmlInterface::write(): Polyline vector is empty, no "
448  "polylines written to file.");
449  }
450  }
451  }
452  else
453  {
454  INFO(
455  "XmlGmlInterface::write(): Polyline vector is empty, no polylines "
456  "written to file.");
457  }
458 
459  // SURFACES
461  if (sfc_vec)
462  {
463  const std::vector<GeoLib::Surface*>* surfaces(sfc_vec->getVector());
464 
465  if (surfaces)
466  {
467  if (!surfaces->empty())
468  {
469  QDomElement sfcListTag = doc.createElement("surfaces");
470  root.appendChild(sfcListTag);
471  auto const nSurfaces = surfaces->size();
472  for (std::size_t i = 0; i < nSurfaces; i++)
473  {
474  QDomElement surfaceTag = doc.createElement("surface");
475  surfaceTag.setAttribute("id", QString::number(i));
476 
477  std::string sfc_name;
478  if (sfc_vec->getNameOfElementByID(i, sfc_name))
479  {
480  surfaceTag.setAttribute(
481  "name", QString::fromStdString(sfc_name));
482  }
483 
484  sfcListTag.appendChild(surfaceTag);
485 
486  // writing the elements compromising the surface
487  std::size_t nElements =
488  ((*surfaces)[i])->getNumberOfTriangles();
489  for (std::size_t j = 0; j < nElements; j++)
490  {
491  QDomElement elementTag = doc.createElement("element");
492  elementTag.setAttribute(
493  "p1", QString::number((*(*(*surfaces)[i])[j])[0]));
494  elementTag.setAttribute(
495  "p2", QString::number((*(*(*surfaces)[i])[j])[1]));
496  elementTag.setAttribute(
497  "p3", QString::number((*(*(*surfaces)[i])[j])[2]));
498  surfaceTag.appendChild(elementTag);
499  }
500  }
501  }
502  else
503  {
504  INFO(
505  "XmlGmlInterface::write(): Surface vector is empty, no "
506  "surfaces written to file.");
507  }
508  }
509  }
510  else
511  {
512  INFO(
513  "XmlGmlInterface::write(): Surface vector is empty, no surfaces "
514  "written to file.");
515  }
516 
517  std::string xml = doc.toString().toStdString();
518  out << xml;
519 
520  return true;
521 }
522 
523 } // namespace IO
524 } // 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 addSurfaceVec(std::unique_ptr< std::vector< Surface * >> sfc, const std::string &name, std::unique_ptr< std::map< std::string, std::size_t >> sfc_names=nullptr)
Definition: GEOObjects.cpp:261
const std::vector< Point * > * getPointVec(const std::string &name) const
Definition: GEOObjects.cpp:71
const PointVec * getPointVecObj(const std::string &name) const
Definition: GEOObjects.cpp:84
bool removePointVec(const std::string &name)
Definition: GEOObjects.cpp:97
void addPointVec(std::unique_ptr< std::vector< Point * >> points, std::string &name, std::unique_ptr< std::map< std::string, std::size_t >> pnt_id_name_map=nullptr, double eps=std::sqrt(std::numeric_limits< double >::epsilon()))
Definition: GEOObjects.cpp:51
SurfaceVec * getSurfaceVecObj(const std::string &name)
Returns the surface vector with the given name.
Definition: GEOObjects.h:205
const PolylineVec * getPolylineVecObj(const std::string &name) const
Definition: GEOObjects.cpp:227
void addPolylineVec(std::unique_ptr< std::vector< Polyline * >> lines, const std::string &name, std::unique_ptr< std::map< std::string, std::size_t >> ply_names=nullptr)
Definition: GEOObjects.cpp:150
bool removePolylineVec(const std::string &name)
Definition: GEOObjects.cpp:243
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 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.
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, std::map< std::string, std::size_t > *ply_names)
Reads GeoLib::Polyline-objects from an xml-file.
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, std::map< std::string, std::size_t > *sfc_names)
Reads GeoLib::Surface-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 deletin...
Definition: PointVec.h:39
const std::vector< std::size_t > & getIDMap() const
Definition: PointVec.h:97
std::string const & getItemNameByID(std::size_t id) const
Definition: PointVec.cpp:244
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition: Polyline.h:51
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:40
const std::vector< T * > * getVector() const
Definition: TemplateVec.h:112
bool getNameOfElementByID(std::size_t id, std::string &element_name) const
Definition: TemplateVec.h:153
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
void deleteGeometry(std::unique_ptr< std::vector< GeoLib::Point * >> points, std::unique_ptr< std::vector< GeoLib::Polyline * >> polylines, std::unique_ptr< std::vector< GeoLib::Surface * >> surfaces)
void deleteSurfaces(std::unique_ptr< std::vector< GeoLib::Surface * >> surfaces)
void deletePolylines(std::unique_ptr< std::vector< GeoLib::Polyline * >> polylines)