OGS
BoostXmlGmlInterface.cpp
Go to the documentation of this file.
1
16
17#include <boost/property_tree/xml_parser.hpp>
18
19#include "BaseLib/Algorithm.h"
21#include "BaseLib/Logging.h"
22#include "GeoLib/GEOObjects.h"
23#include "GeoLib/Point.h"
24#include "GeoLib/PointVec.h"
25#include "GeoLib/Polyline.h"
26#include "GeoLib/Surface.h"
27#include "GeoLib/Triangle.h"
28
29namespace GeoLib
30{
31namespace IO
32{
34 : _geo_objects(geo_objs)
35{
36}
37
38bool BoostXmlGmlInterface::readFile(const std::string& fname)
39{
41 auto doc = BaseLib::makeConfigTreeFromFile(fname, true, "OpenGeoSysGLI");
42
43 // ignore attributes related to XML schema
44 doc.ignoreConfigAttribute("xmlns:xsi");
45 doc.ignoreConfigAttribute("xsi:noNamespaceSchemaLocation");
46 doc.ignoreConfigAttribute("xmlns:ogs");
47
49 auto geo_name = doc.getConfigParameter<std::string>("name");
50 if (geo_name.empty())
51 {
52 OGS_FATAL("BoostXmlGmlInterface::readFile(): <name> tag is empty.");
53 }
54
56 for (auto st : doc.getConfigSubtreeList("points"))
57 {
58 std::vector<GeoLib::Point*> points;
60 readPoints(st, points, pnt_names);
61 _geo_objects.addPointVec(std::move(points), geo_name,
62 std::move(pnt_names));
63 }
64
65 std::vector<GeoLib::Polyline*> polylines;
68 for (auto st : doc.getConfigSubtreeList("polylines"))
69 {
71 polylines,
72 *_geo_objects.getPointVec(geo_name),
74 ply_names);
75 }
76
77 std::vector<GeoLib::Surface*> surfaces;
78 SurfaceVec::NameIdMap sfc_names;
79
81 for (auto st : doc.getConfigSubtreeList("surfaces"))
82 {
83 readSurfaces(st, surfaces, *_geo_objects.getPointVec(geo_name),
85 sfc_names);
86 }
87
88 if (!polylines.empty())
89 {
90 _geo_objects.addPolylineVec(std::move(polylines), geo_name,
91 std::move(ply_names));
92 }
93
94 if (!surfaces.empty())
95 {
96 _geo_objects.addSurfaceVec(std::move(surfaces), geo_name,
97 std::move(sfc_names));
98 }
99
100 return true;
101}
102
104 BaseLib::ConfigTree const& pointsRoot,
105 std::vector<GeoLib::Point*>& points,
106 std::map<std::string, std::size_t>& pnt_names)
107{
109 for (auto const pt : pointsRoot.getConfigParameterList("point"))
110 {
112 auto const p_id = pt.getConfigAttribute<std::size_t>("id");
114 auto const p_x = pt.getConfigAttribute<double>("x");
116 auto const p_y = pt.getConfigAttribute<double>("y");
118 auto const p_z = pt.getConfigAttribute<double>("z");
119
120 auto const p_size = points.size();
122 "The point id is not unique.");
123 points.push_back(new GeoLib::Point(p_x, p_y, p_z, p_id));
124
125 if (auto const p_name =
127 pt.getConfigAttributeOptional<std::string>("name"))
128 {
129 if (p_name->empty())
130 {
131 OGS_FATAL("Empty point name found in geometry file.");
132 }
133
135 pnt_names, *p_name, p_size, "The point name is not unique.");
136 }
137 }
138}
139
141 BaseLib::ConfigTree const& polylinesRoot,
142 std::vector<GeoLib::Polyline*>& polylines,
143 std::vector<GeoLib::Point*> const& points,
144 std::vector<std::size_t> const& pnt_id_map,
145 std::map<std::string, std::size_t>& ply_names)
146{
148 for (auto const pl : polylinesRoot.getConfigSubtreeList("polyline"))
149 {
151 auto const id = pl.getConfigAttribute<std::size_t>("id");
152 // The id is not used but must be present in the GML file.
153 // That's why pl.ignore...() cannot be used.
154 (void)id;
155
156 polylines.push_back(new GeoLib::Polyline(points));
157
158 if (auto const p_name =
160 pl.getConfigAttributeOptional<std::string>("name"))
161 {
162 if (p_name->empty())
163 {
164 OGS_FATAL("Empty polyline name found in geometry file.");
165 }
166
168 ply_names, *p_name, polylines.size() - 1,
169 "The polyline name is not unique.");
170
171 auto accessOrError = [this, &p_name](auto pt_idx)
172 {
173 auto search = _idx_map.find(pt_idx);
174 if (search == _idx_map.end())
175 {
176 OGS_FATAL(
177 "Polyline `{:s}' contains the point id `{:d}', but the "
178 "id is not in the point list.",
179 p_name->c_str(), pt_idx);
180 }
181 return search->second;
182 };
183
185 for (auto const pt : pl.getConfigParameterList<std::size_t>("pnt"))
186 {
187 polylines.back()->addPoint(pnt_id_map[accessOrError(pt)]);
188 }
189 }
190 else
191 {
192 // polyline has no name, ignore it.
193 pl.ignoreConfigParameterAll("pnt");
194 WARN(
195 "Polyline name is required! Polylines without a name are "
196 "ignored.");
197 }
198 }
199}
200
202 BaseLib::ConfigTree const& surfacesRoot,
203 std::vector<GeoLib::Surface*>& surfaces,
204 std::vector<GeoLib::Point*> const& points,
205 const std::vector<std::size_t>& pnt_id_map,
206 std::map<std::string, std::size_t>& sfc_names)
207{
209 for (auto const& sfc : surfacesRoot.getConfigSubtreeList("surface"))
210 {
212 auto const id = sfc.getConfigAttribute<std::size_t>("id");
213 // The id is not used but must be present in the GML file.
214 // That's why sfc.ignore...() cannot be used.
215 (void)id;
216 surfaces.push_back(new GeoLib::Surface(points));
217
218 if (auto const s_name =
220 sfc.getConfigAttributeOptional<std::string>("name"))
221 {
222 if (s_name->empty())
223 {
224 OGS_FATAL("Empty surface name found in geometry file.");
225 }
226
228 sfc_names, *s_name, surfaces.size() - 1,
229 "The surface name is not unique.");
230
232 for (auto const& element : sfc.getConfigParameterList("element"))
233 {
234 auto const p1_attr =
236 element.getConfigAttribute<std::size_t>("p1");
237 auto const p2_attr =
239 element.getConfigAttribute<std::size_t>("p2");
240 auto const p3_attr =
242 element.getConfigAttribute<std::size_t>("p3");
243
244 auto accessOrError = [this, &s_name](std::size_t pt_idx)
245 {
246 auto search = _idx_map.find(pt_idx);
247 if (search == _idx_map.end())
248 {
249 OGS_FATAL(
250 "The element list of the surface `{:s}' contains "
251 "the invalid point id `{:d}'.",
252 s_name->c_str(), pt_idx);
253 }
254 return search->second;
255 };
256
257 auto const p1 = pnt_id_map[accessOrError(p1_attr)];
258 auto const p2 = pnt_id_map[accessOrError(p2_attr)];
259 auto const p3 = pnt_id_map[accessOrError(p3_attr)];
260 surfaces.back()->addTriangle(p1, p2, p3);
261 }
262 }
263 else
264 {
265 // surface has no name, ignore it.
266 sfc.ignoreConfigParameterAll("element");
267 }
268 }
269}
270
272{
273 if (export_name.empty())
274 {
275 ERR("BoostXmlGmlInterface::write(): No geometry specified.");
276 return false;
277 }
278
279 GeoLib::PointVec const* const pnt_vec(
281 if (!pnt_vec)
282 {
283 ERR("BoostXmlGmlInterface::write(): No PointVec within the geometry "
284 "'{:s}'.",
286 return false;
287 }
288
289 auto const& pnts(pnt_vec->getVector());
290 if (pnts.empty())
291 {
292 ERR("BoostXmlGmlInterface::write(): No points within the geometry "
293 "'{:s}'.",
295 return false;
296 }
297
298 // create a property tree for writing it to file
299 boost::property_tree::ptree pt;
300
301 // put header in property tree
302 pt.put("<xmlattr>.xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
303 pt.put("<xmlattr>.xmlns:ogs", "https://www.opengeosys.org");
304 auto& geometry_set = pt.add("OpenGeoSysGLI", "");
305
306 geometry_set.add("name", export_name);
307 auto& pnts_tag = geometry_set.add("points", "");
308 for (std::size_t k(0); k < pnts.size(); k++)
309 {
310 auto& pnt_tag = pnts_tag.add("point", "");
311 pnt_tag.put("<xmlattr>.id", k);
312 pnt_tag.put("<xmlattr>.x", (*pnts[k])[0]);
313 pnt_tag.put("<xmlattr>.y", (*pnts[k])[1]);
314 pnt_tag.put("<xmlattr>.z", (*pnts[k])[2]);
315 std::string const& point_name(pnt_vec->getItemNameByID(k));
316 if (!point_name.empty())
317 {
318 pnt_tag.put("<xmlattr>.name", point_name);
319 }
320 }
321
322 addPolylinesToPropertyTree(geometry_set);
323 addSurfacesToPropertyTree(geometry_set);
324
325 boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
326 write_xml(out, pt, settings);
327 return true;
328}
329
331 boost::property_tree::ptree& geometry_set)
332{
333 GeoLib::SurfaceVec const* const sfc_vec(
335 if (!sfc_vec)
336 {
337 INFO(
338 "BoostXmlGmlInterface::addSurfacesToPropertyTree(): No surfaces "
339 "within the geometry '{:s}'.",
341 return;
342 }
343
344 auto const& surfaces(sfc_vec->getVector());
345 if (surfaces.empty())
346 {
347 INFO(
348 "BoostXmlGmlInterface::addSurfacesToPropertyTree(): No surfaces "
349 "within the geometry '{:s}'.",
351 return;
352 }
353
354 auto& surfaces_tag = geometry_set.add("surfaces", "");
355 for (std::size_t i = 0; i < surfaces.size(); ++i)
356 {
357 GeoLib::Surface const* const surface(surfaces[i]);
358 std::string sfc_name;
359 sfc_vec->getNameOfElement(surface, sfc_name);
360 auto& surface_tag = surfaces_tag.add("surface", "");
361 surface_tag.put("<xmlattr>.id", i);
362 if (!sfc_name.empty())
363 {
364 surface_tag.put("<xmlattr>.name", sfc_name);
365 }
366 for (std::size_t j = 0; j < surface->getNumberOfTriangles(); ++j)
367 {
368 auto& element_tag = surface_tag.add("element", "");
369 element_tag.put("<xmlattr>.p1", (*(*surface)[j])[0]);
370 element_tag.put("<xmlattr>.p2", (*(*surface)[j])[1]);
371 element_tag.put("<xmlattr>.p3", (*(*surface)[j])[2]);
372 }
373 }
374}
375
377 boost::property_tree::ptree& geometry_set)
378{
379 GeoLib::PolylineVec const* const vec(
381 if (!vec)
382 {
383 INFO(
384 "BoostXmlGmlInterface::addPolylinesToPropertyTree(): No polylines "
385 "within the geometry '{:s}'.",
387 return;
388 }
389
390 auto const& polylines(vec->getVector());
391 if (polylines.empty())
392 {
393 INFO(
394 "BoostXmlGmlInterface::addPolylinesToPropertyTree(): No polylines "
395 "within the geometry '{:s}'.",
397 return;
398 }
399
400 auto& polylines_tag = geometry_set.add("polylines", "");
401 for (std::size_t i = 0; i < polylines.size(); ++i)
402 {
403 GeoLib::Polyline const* const polyline(polylines[i]);
404 std::string ply_name;
405 vec->getNameOfElement(polyline, ply_name);
406 auto& polyline_tag = polylines_tag.add("polyline", "");
407 polyline_tag.put("<xmlattr>.id", i);
408 if (!ply_name.empty())
409 {
410 polyline_tag.put("<xmlattr>.name", ply_name);
411 }
412 for (std::size_t j = 0; j < polyline->getNumberOfPoints(); ++j)
413 {
414 polyline_tag.add("pnt", polyline->getPointID(j));
415 }
416 }
417}
418
419} // end namespace IO
420} // end namespace GeoLib
Definition of the BoostXmlGmlInterface class.
#define OGS_FATAL(...)
Definition Error.h:26
Definition of the GEOObjects class.
Definition of the Point class.
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 PointVec class.
Definition of the PolyLine class.
Range< SubtreeIterator > getConfigSubtreeList(std::string const &root) const
Range< ValueIterator< T > > getConfigParameterList(std::string const &param) const
std::ostringstream out
The stream to write to.
Definition Writer.h:47
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
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 write() override
Writes the object to the internal stream. This method must be implemented by a subclass....
void readPolylines(BaseLib::ConfigTree const &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 addPolylinesToPropertyTree(boost::property_tree::ptree &geometry_set)
void readPoints(BaseLib::ConfigTree const &pointsRoot, std::vector< GeoLib::Point * > &points, std::map< std::string, std::size_t > &pnt_names)
Reads GeoLib::Point-objects from an xml-file.
void readSurfaces(BaseLib::ConfigTree const &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.
bool readFile(const std::string &fname) override
Reads an xml-file containing OGS geometry.
void addSurfacesToPropertyTree(boost::property_tree::ptree &geometry_set)
std::map< std::size_t, std::size_t > _idx_map
BoostXmlGmlInterface(GeoLib::GEOObjects &geo_objs)
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
std::size_t getPointID(std::size_t const i) const
Definition Polyline.cpp:160
std::size_t getNumberOfPoints() const
Definition Polyline.cpp:109
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
Definition Surface.h:33
std::size_t getNumberOfTriangles() const
Definition Surface.cpp:82
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 getNameOfElement(const T *data, std::string &name) const
std::vector< T * > const & getVector() const
ConfigTree makeConfigTreeFromFile(const std::string &filepath, const bool be_ruthless, const std::string &toplevel_tag)
void insertIfKeyUniqueElseError(Map &map, Key const &key, Value &&value, std::string const &error_message)
Definition Algorithm.h:104