OGS 6.2.1-97-g73d1aeda3
BoostXmlGmlInterface.cpp
Go to the documentation of this file.
1 
15 #include "BoostXmlGmlInterface.h"
16 
17 #include <boost/property_tree/xml_parser.hpp>
18 #include <logog/include/logog.hpp>
19 
20 #include "BaseLib/Algorithm.h"
21 #include "BaseLib/ConfigTreeUtil.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 {
33 
35  _geo_objects(geo_objs)
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 points = std::make_unique<std::vector<GeoLib::Point*>>();
49  auto polylines = std::make_unique<std::vector<GeoLib::Polyline*>>();
50  auto surfaces = std::make_unique<std::vector<GeoLib::Surface*>>();
51 
52  using MapNameId = std::map<std::string, std::size_t>;
53  auto pnt_names = std::make_unique<MapNameId>();
54  auto ply_names = std::make_unique<MapNameId>();
55  auto sfc_names = std::make_unique<MapNameId>();
56 
58  auto geo_name = doc->getConfigParameter<std::string>("name");
59  if (geo_name.empty())
60  {
61  OGS_FATAL("BoostXmlGmlInterface::readFile(): <name> tag is empty.");
62  }
63 
65  for (auto st : doc->getConfigSubtreeList("points"))
66  {
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  _geo_objects.addPolylineVec(std::move(polylines), geo_name,
94  std::move(ply_names));
95  }
96 
97  if (!surfaces->empty()) {
98  _geo_objects.addSurfaceVec(std::move(surfaces), geo_name,
99  std::move(sfc_names));
100  }
101 
102  return true;
103 }
104 
106  std::vector<GeoLib::Point*>& points,
107  std::map<std::string, std::size_t>& pnt_names )
108 {
110  for (auto const pt : pointsRoot.getConfigParameterList("point"))
111  {
113  auto const p_id = pt.getConfigAttribute<std::size_t>("id");
115  auto const p_x = pt.getConfigAttribute<double>("x");
117  auto const p_y = pt.getConfigAttribute<double>("y");
119  auto const p_z = pt.getConfigAttribute<double>("z");
120 
121  auto const p_size = points.size();
123  "The point id is not unique.");
124  points.push_back(new GeoLib::Point(p_x, p_y, p_z, p_id));
125 
127  if (auto const p_name = pt.getConfigAttributeOptional<std::string>("name"))
128  {
129  if (p_name->empty()) {
130  OGS_FATAL("Empty point name found in geometry file.");
131  }
132 
133  BaseLib::insertIfKeyUniqueElseError(pnt_names, *p_name, p_size,
134  "The point name is not unique.");
135  }
136  }
137 }
138 
140  BaseLib::ConfigTree const& polylinesRoot,
141  std::vector<GeoLib::Polyline*>& polylines,
142  std::vector<GeoLib::Point*> const& points,
143  std::vector<std::size_t> const& pnt_id_map,
144  std::map<std::string, std::size_t>& ply_names)
145 {
147  for (auto const pl : polylinesRoot.getConfigSubtreeList("polyline"))
148  {
150  auto const id = pl.getConfigAttribute<std::size_t>("id");
151  // The id is not used but must be present in the GML file.
152  // That's why pl.ignore...() cannot be used.
153  (void) id;
154 
155  polylines.push_back(new GeoLib::Polyline(points));
156 
158  if (auto const p_name = pl.getConfigAttributeOptional<std::string>("name"))
159  {
160  if (p_name->empty()) {
161  OGS_FATAL("Empty polyline name found in geometry file.");
162  }
163 
164  BaseLib::insertIfKeyUniqueElseError(ply_names, *p_name, polylines.size()-1,
165  "The polyline name is not unique.");
166 
167  auto accessOrError = [this, &p_name](auto pt_idx) {
168  auto search = _idx_map.find(pt_idx);
169  if (search == _idx_map.end())
170  {
171  OGS_FATAL(
172  "Polyline `%s' contains the point id `%d', but the "
173  "id is not in the point list.",
174  p_name->c_str(), pt_idx);
175  }
176  return search->second;
177  };
178 
180  for (auto const pt : pl.getConfigParameterList<std::size_t>("pnt"))
181  {
182  polylines.back()->addPoint(pnt_id_map[accessOrError(pt)]);
183  }
184  }
185  else
186  {
187  // polyline has no name, ignore it.
188  pl.ignoreConfigParameterAll("pnt");
189  }
190  }
191 }
192 
194  BaseLib::ConfigTree const& surfacesRoot,
195  std::vector<GeoLib::Surface*>& surfaces,
196  std::vector<GeoLib::Point*> const& points,
197  const std::vector<std::size_t>& pnt_id_map,
198  std::map<std::string, std::size_t>& sfc_names)
199 {
201  for (auto const& sfc : surfacesRoot.getConfigSubtreeList("surface"))
202  {
204  auto const id = sfc.getConfigAttribute<std::size_t>("id");
205  // The id is not used but must be present in the GML file.
206  // That's why sfc.ignore...() cannot be used.
207  (void) id;
208  surfaces.push_back(new GeoLib::Surface(points));
209 
211  if (auto const s_name = sfc.getConfigAttributeOptional<std::string>("name"))
212  {
213  if (s_name->empty()) {
214  OGS_FATAL("Empty surface name found in geometry file.");
215  }
216 
217  BaseLib::insertIfKeyUniqueElseError(sfc_names, *s_name, surfaces.size()-1,
218  "The surface name is not unique.");
219 
221  for (auto const& element : sfc.getConfigParameterList("element")) {
223  auto const p1_attr = element.getConfigAttribute<std::size_t>("p1");
225  auto const p2_attr = element.getConfigAttribute<std::size_t>("p2");
227  auto const p3_attr = element.getConfigAttribute<std::size_t>("p3");
228 
229  auto accessOrError = [this, &s_name](std::size_t pt_idx) {
230  auto search = _idx_map.find(pt_idx);
231  if (search == _idx_map.end())
232  {
233  OGS_FATAL(
234  "The element list of the surface `%s' contains the "
235  "invalid point id `%d'.",
236  s_name->c_str(), pt_idx);
237  }
238  return search->second;
239  };
240 
241  auto const p1 = pnt_id_map[accessOrError(p1_attr)];
242  auto const p2 = pnt_id_map[accessOrError(p2_attr)];
243  auto const p3 = pnt_id_map[accessOrError(p3_attr)];
244  surfaces.back()->addTriangle(p1,p2,p3);
245  }
246  }
247  else
248  {
249  // surface has no name, ignore it.
250  sfc.ignoreConfigParameterAll("element");
251  }
252  }
253 }
254 
256 {
257  if (this->_exportName.empty()) {
258  ERR("BoostXmlGmlInterface::write(): No geometry specified.");
259  return false;
260  }
261 
263  if (! pnt_vec) {
264  ERR("BoostXmlGmlInterface::write(): No PointVec within the geometry "
265  "'%s'.",
266  _exportName.c_str());
267  return false;
268  }
269 
270  std::vector<GeoLib::Point*> const*const pnts(pnt_vec->getVector());
271  if (! pnts) {
272  ERR("BoostXmlGmlInterface::write(): No vector of points within the "
273  "geometry '%s'.",
274  _exportName.c_str());
275  return false;
276  }
277  if (pnts->empty()) {
278  ERR("BoostXmlGmlInterface::write(): No points within the geometry "
279  "'%s'.",
280  _exportName.c_str());
281  return false;
282  }
283 
284  // create a property tree for writing it to file
285  boost::property_tree::ptree pt;
286 
287  // put header in property tree
288  pt.put("<xmlattr>.xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
289  pt.put("<xmlattr>.xmlns:ogs", "http://www.opengeosys.net");
290  auto& geometry_set = pt.add("OpenGeoSysGLI", "");
291 
292  geometry_set.add("name", _exportName);
293  auto& pnts_tag = geometry_set.add("points", "");
294  for (std::size_t k(0); k<pnts->size(); k++) {
295  auto& pnt_tag = pnts_tag.add("point", "");
296  pnt_tag.put("<xmlattr>.id", k);
297  pnt_tag.put("<xmlattr>.x", (*((*pnts)[k]))[0]);
298  pnt_tag.put("<xmlattr>.y", (*((*pnts)[k]))[1]);
299  pnt_tag.put("<xmlattr>.z", (*((*pnts)[k]))[2]);
300  std::string const& point_name(pnt_vec->getItemNameByID(k));
301  if (!point_name.empty())
302  {
303  pnt_tag.put("<xmlattr>.name", point_name);
304  }
305  }
306 
307  addPolylinesToPropertyTree(geometry_set);
308  addSurfacesToPropertyTree(geometry_set);
309 
310  boost::property_tree::xml_writer_settings<std::string> settings('\t', 1);
311  setPrecision(std::numeric_limits<double>::digits10);
312  write_xml(_out, pt, settings);
313  return true;
314 }
315 
317  boost::property_tree::ptree & geometry_set)
318 {
320  if (!sfc_vec) {
321  INFO(
322  "BoostXmlGmlInterface::addSurfacesToPropertyTree(): "
323  "No surfaces within the geometry '%s'.",
324  _exportName.c_str());
325  return;
326  }
327 
328  std::vector<GeoLib::Surface*> const*const surfaces(sfc_vec->getVector());
329  if (!surfaces || surfaces->empty())
330  {
331  INFO(
332  "BoostXmlGmlInterface::addSurfacesToPropertyTree(): "
333  "No surfaces within the geometry '%s'.",
334  _exportName.c_str());
335  return;
336  }
337 
338  auto& surfaces_tag = geometry_set.add("surfaces", "");
339  for (std::size_t i=0; i<surfaces->size(); ++i) {
340  GeoLib::Surface const*const surface((*surfaces)[i]);
341  std::string sfc_name;
342  sfc_vec->getNameOfElement(surface, sfc_name);
343  auto& surface_tag = surfaces_tag.add("surface", "");
344  surface_tag.put("<xmlattr>.id", i);
345  if (!sfc_name.empty())
346  {
347  surface_tag.put("<xmlattr>.name", sfc_name);
348  }
349  for (std::size_t j=0; j<surface->getNumberOfTriangles(); ++j) {
350  auto& element_tag = surface_tag.add("element", "");
351  element_tag.put("<xmlattr>.p1", (*(*surface)[j])[0]);
352  element_tag.put("<xmlattr>.p2", (*(*surface)[j])[1]);
353  element_tag.put("<xmlattr>.p3", (*(*surface)[j])[2]);
354  }
355  }
356 }
357 
359  boost::property_tree::ptree & geometry_set)
360 {
362  if (!vec) {
363  INFO(
364  "BoostXmlGmlInterface::addPolylinesToPropertyTree(): "
365  "No polylines within the geometry '%s'.",
366  _exportName.c_str());
367  return;
368  }
369 
370  std::vector<GeoLib::Polyline*> const*const polylines(vec->getVector());
371  if (!polylines || polylines->empty())
372  {
373  INFO(
374  "BoostXmlGmlInterface::addPolylinesToPropertyTree(): "
375  "No polylines within the geometry '%s'.",
376  _exportName.c_str());
377  return;
378  }
379 
380  auto& polylines_tag = geometry_set.add("polylines", "");
381  for (std::size_t i=0; i<polylines->size(); ++i) {
382  GeoLib::Polyline const*const polyline((*polylines)[i]);
383  std::string ply_name;
384  vec->getNameOfElement(polyline, ply_name);
385  auto& polyline_tag = polylines_tag.add("polyline", "");
386  polyline_tag.put("<xmlattr>.id", i);
387  if (!ply_name.empty())
388  {
389  polyline_tag.put("<xmlattr>.name", ply_name);
390  }
391  for (std::size_t j=0; j<polyline->getNumberOfPoints(); ++j) {
392  polyline_tag.add("pnt", polyline->getPointID(j));
393  }
394  }
395 }
396 
397 } // end namespace IO
398 } // end namespace GeoLib
BoostXmlGmlInterface(GeoLib::GEOObjects &geo_objs)
Definition of the PolyLine class.
Definition of the Point class.
Container class for geometric objects.
Definition: GEOObjects.h:62
bool write() override
Required method for writing geometry. This is not implemented here, use the Qt class for writing...
Definition of the BoostXmlGmlInterface class.
std::stringstream _out
The stream to write to.
Definition: Writer.h:56
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.
SurfaceVec * getSurfaceVecObj(const std::string &name)
Returns the surface vector with the given name.
Definition: GEOObjects.h:206
std::size_t getNumberOfTriangles() const
Definition: Surface.cpp:86
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=sqrt(std::numeric_limits< double >::epsilon()))
Definition: GEOObjects.cpp:45
ConfigTreeTopLevel makeConfigTree(const std::string &filepath, const bool be_ruthless, const std::string &toplevel_tag)
std::map< std::size_t, std::size_t > _idx_map
std::size_t getNumberOfPoints() const
Definition: Polyline.cpp:198
Definition of the GEOObjects class.
Definition: BaseItem.h:20
void addSurfacesToPropertyTree(BaseLib::ConfigTree::PTree &geometry_set)
std::size_t getPointID(std::size_t i) const
Definition: Polyline.cpp:245
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 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:137
bool readFile(const std::string &fname) override
Reads an xml-file containing OGS geometry.
void addPolylinesToPropertyTree(BaseLib::ConfigTree::PTree &geometry_set)
const PointVec * getPointVecObj(const std::string &name) const
Definition: GEOObjects.cpp:76
void setPrecision(unsigned int precision)
Sets the decimal precision.
Definition: Writer.cpp:69
const std::vector< Point * > * getPointVec(const std::string &name) const
Definition: GEOObjects.cpp:63
const std::vector< std::size_t > & getIDMap() const
Definition: PointVec.h:99
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition: Polyline.h:50
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:247
void insertIfKeyUniqueElseError(Map &map, Key const &key, Value &&value, std::string const &error_message)
Definition: Algorithm.h:104
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
Definition: Surface.h:34
const PolylineVec * getPolylineVecObj(const std::string &name) const
Definition: GEOObjects.cpp:213
Range< SubtreeIterator > getConfigSubtreeList(std::string const &root) const
Definition: ConfigTree.cpp:174
This class manages pointers to Points in a std::vector along with a name. It also handles the deletin...
Definition: PointVec.h:39
The class TemplateVec takes a unique name and manages a std::vector of pointers to data elements of t...
Definition: TemplateVec.h:40
#define OGS_FATAL(fmt,...)
Definition: Error.h:63
Range< ValueIterator< T > > getConfigParameterList(std::string const &param) const
Definition of the PointVec class.
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.