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