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