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 
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  {
70  readPolylines(st,
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}'.",
285  export_name);
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}'.",
294  export_name);
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}'.",
340  export_name);
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}'.",
350  export_name);
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}'.",
386  export_name);
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}'.",
396  export_name);
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(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 addPolylineVec(std::vector< Polyline * > &&lines, std::string const &name, PolylineVec::NameIdMap &&ply_names)
Definition: GEOObjects.cpp:152
const std::vector< Point * > * getPointVec(const std::string &name) const
Definition: GEOObjects.cpp:72
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()))
Definition: GEOObjects.cpp:47
const PointVec * getPointVecObj(const std::string &name) const
Definition: GEOObjects.cpp:85
SurfaceVec * getSurfaceVecObj(const std::string &name)
Returns the surface vector with the given name.
Definition: GEOObjects.h:211
void addSurfaceVec(std::vector< Surface * > &&sfc, const std::string &name, SurfaceVec::NameIdMap &&sfc_names)
Definition: GEOObjects.cpp:240
const PolylineVec * getPolylineVecObj(const std::string &name) const
Definition: GEOObjects.cpp:206
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(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 deletio...
Definition: PointVec.h:38
const std::vector< std::size_t > & getIDMap() const
Definition: PointVec.h:96
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:53
std::size_t getPointID(std::size_t 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: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:41
std::map< std::string, std::size_t > NameIdMap
Definition: TemplateVec.h:44
std::vector< T * > const & getVector() const
Definition: TemplateVec.h:109
bool getNameOfElement(const T *data, std::string &name) const
Definition: TemplateVec.h:177
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)