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