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