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