OGS
SHPInterface.cpp
Go to the documentation of this file.
1
14#include "SHPInterface.h"
15
17#include "BaseLib/Logging.h"
19#include "GeoLib/GEOObjects.h"
20#include "GeoLib/Point.h"
21#include "GeoLib/Polyline.h"
22#include "GeoLib/Station.h"
26#include "MeshLib/Mesh.h"
27#include "MeshLib/Node.h"
28
29namespace FileIO
30{
31bool SHPInterface::readSHPInfo(const std::string& filename, int& shapeType,
32 int& numberOfEntities)
33{
34 SHPHandle hSHP = SHPOpen(filename.c_str(), "rb");
35 if (!hSHP)
36 {
37 return false;
38 }
39
40 double padfMinBound[4];
41 double padfMaxBound[4];
42
43 // The SHPGetInfo() function retrieves various information about shapefile
44 // as a whole. The bounds are read from the file header, and may be
45 // inaccurate if the file was improperly generated.
46 SHPGetInfo(hSHP, &numberOfEntities, &shapeType, padfMinBound, padfMaxBound);
47
48 SHPClose(hSHP);
49 return true;
50}
51
52void SHPInterface::readSHPFile(const std::string& filename, OGSType choice,
53 const std::string& listName,
54 std::string const& gmsh_path)
55{
56 int shapeType;
57 int numberOfElements;
58 double padfMinBound[4];
59 double padfMaxBound[4];
60
61 SHPHandle hSHP = SHPOpen(filename.c_str(), "rb");
62 SHPGetInfo(hSHP, &numberOfElements, &shapeType, padfMinBound, padfMaxBound);
63
64 if (((shapeType - 1) % 10 == 0) && (choice == SHPInterface::OGSType::POINT))
65 {
66 readPoints(hSHP, numberOfElements, listName);
67 }
68 if (((shapeType - 1) % 10 == 0) &&
70 {
71 readStations(hSHP, numberOfElements, listName);
72 }
73 if (((shapeType - 3) % 10 == 0 || (shapeType - 5) % 10 == 0) &&
75 {
76 readPolylines(hSHP, numberOfElements, listName);
77 }
78 if (((shapeType - 3) % 10 == 0 || (shapeType - 5) % 10 == 0) &&
80 {
81 readPolygons(hSHP, numberOfElements, listName, gmsh_path);
82 }
83}
84
85void SHPInterface::readPoints(const SHPHandle& hSHP, int numberOfElements,
86 std::string listName)
87{
88 if (numberOfElements > 0)
89 {
90 std::vector<GeoLib::Point*> points;
91 SHPObject* hSHPObject;
92
93 for (int i = 0; i < numberOfElements; i++)
94 {
95 hSHPObject = SHPReadObject(hSHP, i);
96
97 auto* pnt =
98 new GeoLib::Point(*(hSHPObject->padfX), *(hSHPObject->padfY),
99 *(hSHPObject->padfZ));
100 points.push_back(pnt);
101 }
102
103 _geoObjects.addPointVec(std::move(points), listName,
105 SHPDestroyObject(hSHPObject); // de-allocate SHPObject
106 }
107}
108
109void SHPInterface::readStations(const SHPHandle& hSHP, int numberOfElements,
110 std::string listName)
111{
112 if (numberOfElements > 0)
113 {
114 std::vector<GeoLib::Point*> stations;
115 stations.reserve(numberOfElements);
116 SHPObject* hSHPObject;
117
118 for (int i = 0; i < numberOfElements; i++)
119 {
120 hSHPObject = SHPReadObject(hSHP, i);
121 GeoLib::Station* stn =
122 GeoLib::Station::createStation(std::to_string(i),
123 *(hSHPObject->padfX),
124 *(hSHPObject->padfY),
125 *(hSHPObject->padfZ));
126 stations.push_back(stn);
127 }
128
129 _geoObjects.addStationVec(std::move(stations), listName);
130 SHPDestroyObject(hSHPObject); // de-allocate SHPObject
131 }
132}
133
134void SHPInterface::readPolylines(const SHPHandle& hSHP, int numberOfElements,
135 std::string listName)
136{
137 if (numberOfElements <= 0)
138 {
139 return;
140 }
141 std::vector<GeoLib::Point*> pnts;
142 std::vector<GeoLib::Polyline*> lines;
143
144 std::size_t pnt_id(0);
145 // for each polyline
146 for (int i = 0; i < numberOfElements; ++i)
147 {
148 SHPObject* hSHPObject = SHPReadObject(hSHP, i);
149 int const noOfPoints = hSHPObject->nVertices;
150 int const noOfParts = hSHPObject->nParts;
151
152 for (int p = 0; p < noOfParts; ++p)
153 {
154 int const firstPnt = *(hSHPObject->panPartStart + p);
155 int const lastPnt = (p < (noOfParts - 1))
156 ? *(hSHPObject->panPartStart + p + 1)
157 : noOfPoints;
158
159 // for each point in that polyline
160 for (int j = firstPnt; j < lastPnt; ++j)
161 {
162 pnts.push_back(new GeoLib::Point(
163 *(hSHPObject->padfX + j), *(hSHPObject->padfY + j),
164 *(hSHPObject->padfZ + j), pnt_id));
165 pnt_id++;
166 }
167 }
168 SHPDestroyObject(hSHPObject); // de-allocate SHPObject
169 }
170
171 _geoObjects.addPointVec(std::move(pnts), listName,
173 GeoLib::PointVec const& points(*(_geoObjects.getPointVecObj(listName)));
174 std::vector<std::size_t> const& pnt_id_map(points.getIDMap());
175
176 pnt_id = 0;
177 for (int i = 0; i < numberOfElements; ++i)
178 {
179 SHPObject* hSHPObject = SHPReadObject(hSHP, i);
180 int const noOfPoints = hSHPObject->nVertices;
181 int const noOfParts = hSHPObject->nParts;
182
183 for (int p = 0; p < noOfParts; ++p)
184 {
185 // output for the first part of multipart polyline
186 if (noOfParts > 1 && p == 0)
187 {
188 INFO(
189 "Polygon {:d} consists of {:d} parts (PolylineIDs "
190 "{:d}-{:d}).",
191 i, noOfParts, lines.size(), lines.size() + noOfParts - 1);
192 }
193
194 int const firstPnt = *(hSHPObject->panPartStart + p);
195 int const lastPnt = (p < (noOfParts - 1))
196 ? *(hSHPObject->panPartStart + p + 1)
197 : noOfPoints;
198
199 auto* line = new GeoLib::Polyline(points.getVector());
200
201 // create polyline
202 for (int j = firstPnt; j < lastPnt; ++j)
203 {
204 line->addPoint(pnt_id_map[pnt_id]);
205 pnt_id++;
206 }
207 // add polyline to polyline vector
208 lines.push_back(line);
209 }
210 SHPDestroyObject(hSHPObject); // de-allocate SHPObject
211 }
212 _geoObjects.addPolylineVec(std::move(lines), listName,
214}
215
216void SHPInterface::readPolygons(const SHPHandle& hSHP, int numberOfElements,
217 const std::string& listName,
218 std::string const& gmsh_path)
219{
220 readPolylines(hSHP, numberOfElements, listName);
221
222 auto const polylines = _geoObjects.getPolylineVec(listName);
223
224 for (auto const* polyline : *polylines)
225 {
226 INFO("Creating a surface by triangulation of the polyline ...");
227 if (FileIO::createSurface(*polyline, _geoObjects, listName, gmsh_path))
228 {
229 INFO("\t done");
230 }
231 else
232 {
233 WARN(
234 "\t Creating a surface by triangulation of the polyline "
235 "failed.");
236 }
237 }
238}
239
240bool SHPInterface::write2dMeshToSHP(const std::string& file_name,
241 const MeshLib::Mesh& mesh)
242{
243 if (mesh.getDimension() != 2)
244 {
245 ERR("SHPInterface::write2dMeshToSHP(): Mesh to Shape conversion is "
246 "only working for 2D Meshes.");
247 return false;
248 }
249
250 std::size_t const n_elements = mesh.getNumberOfElements();
251 if (n_elements < 1)
252 {
253 ERR("SHPInterface::write2dMeshToSHP(): Mesh contains no elements.");
254 return false;
255 }
256
257 // DBF-export requires a limit of records because of the limits to the
258 // integer values. The exponent controls maximum number of elements and
259 // the maximum number of digits written in the DBF file.
260 std::size_t const max_exp = 8;
261 if (n_elements >= std::pow(10, max_exp))
262 {
263 ERR("SHPInterface::write2dMeshToSHP(): Mesh contains too many elements "
264 "for currently implemented DBF-boundaries.");
265 return false;
266 }
267
268 SHPHandle hSHP = SHPCreate(file_name.c_str(), SHPT_POLYGON);
269 DBFHandle hDBF = DBFCreate(file_name.c_str());
270 int const elem_id_field =
271 DBFAddField(hDBF, "Elem_ID", FTInteger, max_exp, 0);
272
273 // Writing mesh elements to shape file
274 std::size_t shp_record(0);
275 std::vector<MeshLib::Element*> const& elems = mesh.getElements();
276 for (MeshLib::Element const* const e : elems)
277 {
278 // ignore all elements except triangles and quads
279 if ((e->getGeomType() == MeshLib::MeshElemType::TRIANGLE) ||
280 (e->getGeomType() == MeshLib::MeshElemType::QUAD))
281 {
282 SHPObject* object = createShapeObject(*e, shp_record);
283 SHPWriteObject(hSHP, -1, object);
284 SHPDestroyObject(object);
285
286 // write element ID to DBF-file
287 DBFWriteIntegerAttribute(hDBF, shp_record, elem_id_field,
288 e->getID());
289 shp_record++;
290 }
291 }
292 SHPClose(hSHP);
293
294 // Write scalar arrays to database file
295 int const n_recs = DBFGetRecordCount(hDBF);
296 for (auto [name, property] : mesh.getProperties())
297 {
298 if (auto p = dynamic_cast<MeshLib::PropertyVector<int>*>(property))
299 {
300 int const field =
301 DBFAddField(hDBF, std::string(name).c_str(), FTInteger, 16, 0);
302 for (int i = 0; i < n_recs; ++i)
303 {
304 std::size_t const elem_idx =
305 DBFReadIntegerAttribute(hDBF, i, elem_id_field);
306 DBFWriteIntegerAttribute(hDBF, i, field, (*p)[elem_idx]);
307 }
308 }
309 else if (auto p =
310 dynamic_cast<MeshLib::PropertyVector<double>*>(property))
311 {
312 int const field =
313 DBFAddField(hDBF, std::string(name).c_str(), FTDouble, 33, 16);
314 for (int i = 0; i < n_recs; ++i)
315 {
316 std::size_t const elem_idx =
317 DBFReadIntegerAttribute(hDBF, i, elem_id_field);
318 DBFWriteDoubleAttribute(hDBF, i, field, (*p)[elem_idx]);
319 }
320 }
321 }
322 DBFClose(hDBF);
323 INFO("Shape export of 2D mesh '{:s}' finished.", mesh.getName());
324 return true;
325}
326
328 std::size_t const shp_record)
329{
330 unsigned const nNodes(e.getNumberOfBaseNodes());
331 double* padfX = new double[nNodes + 1];
332 double* padfY = new double[nNodes + 1];
333 double* padfZ = new double[nNodes + 1];
334 for (unsigned j = 0; j < nNodes; ++j)
335 {
336 padfX[j] = (*e.getNode(j))[0];
337 padfY[j] = (*e.getNode(j))[1];
338 padfZ[j] = (*e.getNode(j))[2];
339 }
340 // Last node == first node to close the polygon
341 padfX[nNodes] = (*e.getNode(0))[0];
342 padfY[nNodes] = (*e.getNode(0))[1];
343 padfZ[nNodes] = (*e.getNode(0))[2];
344
345 // the generated shape object now handles the memory for padfX/Y/Z
346 return SHPCreateObject(SHPT_POLYGON, shp_record, 0, nullptr, nullptr,
347 nNodes + 1, padfX, padfY, padfZ, nullptr);
348}
349
350} // namespace FileIO
Definition of analytical geometry functions.
Definition of the Element class.
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 Mesh class.
Definition of the Node class.
Definition of the PolyLine class.
Definition of the Quad class.
Implementation of the SHPInterface class.
Definition of the Station class.
Definition of the Tri class.
void readPolylines(const SHPHandle &hSHP, int numberOfElements, std::string listName)
Reads lines into a vector of Polyline objects.
static bool readSHPInfo(const std::string &filename, int &shapeType, int &numberOfEntities)
Reads the header of the shape file.
void readPoints(const SHPHandle &hSHP, int numberOfElements, std::string listName)
Reads points into a vector of Point objects.
OGSType
Connection between ESRI type system for shape files and OGS GeoLib.
void readStations(const SHPHandle &hSHP, int numberOfElements, std::string listName)
Reads points into a vector of Point objects and marks them as Station.
void readSHPFile(const std::string &filename, OGSType choice, const std::string &listName, std::string const &gmsh_path)
Reads data from the shape file.
GeoLib::GEOObjects & _geoObjects
static bool write2dMeshToSHP(const std::string &file_name, const MeshLib::Mesh &mesh)
static SHPObject * createShapeObject(MeshLib::Element const &e, std::size_t const shp_record)
Creates a shape object polygon out of a 2D mesh element.
void readPolygons(const SHPHandle &hSHP, int numberOfElements, const std::string &listName, std::string const &gmsh_path)
Reads lines into a vector of Polyline and Surface objects.
void addPolylineVec(std::vector< Polyline * > &&lines, std::string const &name, PolylineVec::NameIdMap &&ply_names)
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
void addStationVec(std::vector< Point * > &&stations, std::string &name)
Adds a vector of stations with the given name and colour to GEOObjects.
const std::vector< Polyline * > * getPolylineVec(const std::string &name) const
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
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition Polyline.h:40
A Station (observation site) is basically a Point with some additional information.
Definition Station.h:37
static Station * createStation(const std::string &line)
Definition Station.cpp:46
std::map< std::string, std::size_t > NameIdMap
Definition TemplateVec.h:41
std::vector< T * > const & getVector() const
virtual unsigned getNumberOfBaseNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:109
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:88
Properties & getProperties()
Definition Mesh.h:134
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:103
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
bool createSurface(GeoLib::Polyline const &ply, GeoLib::GEOObjects &geometries, std::string const &geometry_name, std::string const &gmsh_binary)