OGS
GMSHPolygonTree.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "GMSHPolygonTree.h"
5
6#include <sstream>
7
8#include "BaseLib/Algorithm.h"
12#include "GeoLib/GEOObjects.h"
13#include "GeoLib/Point.h"
14#include "GeoLib/Polygon.h"
17#include "GeoLib/Station.h"
18
19namespace FileIO
20{
21namespace GMSH
22{
25 GeoLib::GEOObjects& geo_objs,
26 std::string const& geo_name,
27 GMSHMeshDensityStrategy& mesh_density_strategy)
29 _geo_objs(geo_objs),
30 _geo_name(geo_name),
31 _mesh_density_strategy(mesh_density_strategy)
32{
33}
34
36{
37 // the polylines are processed also by the children, but the root is
38 // responsible to cleanup up
39 if (isRoot())
40 { // root
42 }
43}
44
46{
47 if (isRoot())
48 {
49 return;
50 }
51
52 for (auto& child : *this)
53 {
54 std::size_t const n_pnts(child->polygon().getNumberOfPoints());
55 for (std::size_t k(1); k < n_pnts; k++)
56 {
58 polygon().getPointID(k - 1),
59 polygon().getPointID(k)))
60 {
62 .markSegment(k, true);
63 }
64 }
65 }
66}
67
69{
70 if (polygon().isPntInPolygon(*station))
71 {
72 // try to insert station into the child nodes
73 for (auto* child : *this)
74 {
75 if (child->polygon().isPntInPolygon(*station))
76 {
77 bool rval(dynamic_cast<GMSHPolygonTree*>(child)->insertStation(
78 station));
79 // stop recursion if sub SimplePolygonTree is a leaf
80 if (rval && child->getNumberOfChildren() == 0)
81 {
82 _stations.push_back(station);
83 }
84 return rval;
85 }
86 }
87 // station did not fit into child nodes -> insert the station into this
88 // node
89 _stations.push_back(station);
90 return true;
91 }
92 return false;
93}
94
96{
97 if (!polygon().isPartOfPolylineInPolygon(*ply))
98 {
99 return;
100 }
101
102 // check if polyline segments are inside of the polygon, intersect the
103 // polygon or are part of the boundary of the polygon
104 for (auto* child : *this)
105 {
106 dynamic_cast<GMSHPolygonTree*>(child)->insertPolyline(ply);
107 }
108
109 // calculate possible intersection points between the node polygon and the
110 // given polyline ply
111 // pay attention: loop bound is not fix!
112 GeoLib::Point tmp_pnt;
113 GeoLib::PointVec& pnt_vec(*(_geo_objs.getPointVecObj(_geo_name)));
114 for (auto segment_it(ply->begin()); segment_it != ply->end(); ++segment_it)
115 {
116 if (ply->isSegmentMarked(segment_it.getSegmentNumber()))
117 {
118 continue;
119 }
120
121 if (polygon().containsSegment(*segment_it))
122 {
123 ply->markSegment(segment_it.getSegmentNumber(), true);
124 continue;
125 }
126
127 std::size_t seg_num(0);
128 GeoLib::Point intersection_pnt;
129 while (polygon().getNextIntersectionPointPolygonLine(
130 *segment_it, intersection_pnt, seg_num))
131 {
132 // insert the intersection point to point vector of GEOObjects
133 // instance
134 const std::size_t pnt_vec_size(pnt_vec.size());
135 std::size_t pnt_id(
136 pnt_vec.push_back(new GeoLib::Point(intersection_pnt)));
137 if (pnt_vec_size < pnt_vec.size())
138 { // case: new point
139 // modify the polygon
140 polygon().insertPoint(seg_num + 1, pnt_id);
141 // modify the polyline
142 ply->insertPoint(segment_it.getSegmentNumber(), pnt_id);
143 }
144 else
145 { // case: existing point
146 // check if point id is within the polygon
147 if (!polygon().isPointIDInPolyline(pnt_id))
148 {
149 polygon().insertPoint(seg_num + 1, pnt_id);
150 }
151
152 // check if point id is in polyline
153 if (!ply->isPointIDInPolyline(pnt_id))
154 {
155 ply->insertPoint(segment_it.getSegmentNumber() + 1, pnt_id);
156 }
157 }
158
159 std::size_t tmp_seg_num(seg_num + 1);
160 if (!polygon().getNextIntersectionPointPolygonLine(
161 *segment_it, tmp_pnt, tmp_seg_num))
162 {
163 // check a point of the segment except the end points
164 for (std::size_t i(0); i < 3; i++)
165 {
166 tmp_pnt[i] = ((*segment_it).getBeginPoint()[i] +
167 (*segment_it).getEndPoint()[i]) /
168 2;
169 }
170 if (polygon().isPntInPolygon(tmp_pnt))
171 {
172 ply->markSegment(segment_it.getSegmentNumber(), true);
173 // insert line segment as constraint
175 new GMSHLine((*segment_it).getBeginPoint().getID(),
176 (*segment_it).getEndPoint().getID()));
177 }
178 }
179 seg_num++;
180
181 // check a point of the segment except the end points
182 for (std::size_t i(0); i < 3; i++)
183 {
184 tmp_pnt[i] = ((*segment_it).getBeginPoint()[i] +
185 (*segment_it).getEndPoint()[i]) /
186 2;
187 }
188
190
191 if (polygon().isPntInPolygon(tmp_pnt))
192 {
193 ply->markSegment(segment_it.getSegmentNumber(), true);
194 // insert line segment as constraint
196 new GMSHLine((*segment_it).getBeginPoint().getID(),
197 (*segment_it).getEndPoint().getID()));
198 }
199 }
200 }
201
202 _plys.push_back(ply);
203}
204
208{
209 std::size_t const ply_segment_number(seg_it.getSegmentNumber());
211 {
212 GeoLib::PointVec& pnt_vec(*(_geo_objs.getPointVecObj(_geo_name)));
213 for (auto seg_it_p(p->begin()); seg_it_p != p->end(); ++seg_it_p)
214 {
215 GeoLib::Point s; // intersection point
216 if (GeoLib::lineSegmentIntersect(*seg_it, *seg_it_p, s))
217 {
218 const std::size_t pnt_vec_size(pnt_vec.size());
219 // point id of new point in GEOObjects instance
220 const std::size_t pnt_id(
221 pnt_vec.push_back(new GeoLib::Point(s)));
222 if (pnt_vec_size < pnt_vec.size())
223 { // case: new point
224 // modify polyline already in this node
225 p->insertPoint(seg_it_p.getSegmentNumber() + 1, pnt_id);
226 // modify polyline
227 ply->insertPoint(ply_segment_number + 1, pnt_id);
228 }
229 else
230 { // case: point exists already in geometry
231 // check if point is not already in polyline p
232 std::size_t const k(seg_it_p.getSegmentNumber());
233 if (p->getPointID(k) != pnt_id &&
234 p->getPointID(k + 1) != pnt_id)
235 {
236 p->insertPoint(k + 1, pnt_id);
237 }
238 // check if point is not already in polyline ply
239 if (ply->getPointID(ply_segment_number) != pnt_id &&
240 ply->getPointID(ply_segment_number + 1) != pnt_id)
241 {
242 ply->insertPoint(ply_segment_number + 1, pnt_id);
243 }
244 }
245 }
246 }
247 }
248}
249
251{
252 if (auto* adaptive_mesh_density =
254 {
255 // collect points
256 std::vector<GeoLib::Point const*> pnts;
257 const std::size_t n_pnts_polygon(polygon().getNumberOfPoints());
258 for (std::size_t k(0); k < n_pnts_polygon; k++)
259 {
260 pnts.push_back(polygon().getPoint(k));
261 }
263
264 const std::size_t n_plys(_plys.size());
265 for (std::size_t k(0); k < n_plys; k++)
266 {
267 const std::size_t n_pnts_in_kth_ply(_plys[k]->getNumberOfPoints());
268 for (std::size_t j(0); j < n_pnts_in_kth_ply; j++)
269 {
270 pnts.push_back(_plys[k]->getPoint(j));
271 }
272 }
273
274 // give collected points to the mesh density strategy
275 adaptive_mesh_density->initialize(pnts);
276 // insert constraints
277 adaptive_mesh_density->addPoints(_stations);
278 std::vector<GeoLib::Point const*> stations;
280 adaptive_mesh_density->addPoints(stations);
281 }
282}
283
284void GMSHPolygonTree::createGMSHPoints(std::vector<GMSHPoint*>& gmsh_pnts) const
285{
286 const std::size_t n_pnts_polygon(polygon().getNumberOfPoints());
287 for (std::size_t k(0); k < n_pnts_polygon - 1; k++)
288 {
289 const std::size_t id(polygon().getPointID(k));
290 GeoLib::Point const* const pnt(polygon().getPoint(k));
291 // if this point was already part of another polyline
292 if (gmsh_pnts[id] != nullptr)
293 {
294 continue;
295 }
296 gmsh_pnts[id] = new GMSHPoint(
297 *pnt, id, _mesh_density_strategy.getMeshDensityAtPoint(pnt));
298 }
299
300 const std::size_t n_plys(_plys.size());
301 std::stringstream error_messages;
302 error_messages.precision(std::numeric_limits<double>::max_digits10);
303 for (std::size_t k(0); k < n_plys; k++)
304 {
305 const std::size_t n_pnts_in_ply(_plys[k]->getNumberOfPoints());
306 for (std::size_t j(0); j < n_pnts_in_ply; j++)
307 {
308 if (polygon().isPntInPolygon(*(_plys[k]->getPoint(j))))
309 {
310 const std::size_t id(_plys[k]->getPointID(j));
311 // if this point was already part of another polyline
312 if (gmsh_pnts[id] != nullptr)
313 {
314 continue;
315 }
316 GeoLib::Point const* const pnt(_plys[k]->getPoint(j));
317 gmsh_pnts[id] = new GMSHPoint(
318 *pnt, id,
319 _mesh_density_strategy.getMeshDensityAtPoint(pnt));
320 }
321 else
322 {
323 auto const& p = *(_plys[k]->getPoint(j));
324 error_messages << "\n\tpoint with id " << p.getID()
325 << " and coordinates (" << p[0] << ", " << p[1]
326 << ", " << p[2]
327 << ") is outside of the polygon.";
328 }
329 }
330 }
331 if (!parent())
332 {
333 auto const error_message = error_messages.str();
334 if (!error_message.empty())
335 {
336 OGS_FATAL("{}", error_message);
337 }
338 }
339
340 // walk through children
341 for (auto* child : *this)
342 {
343 dynamic_cast<GMSHPolygonTree*>(child)->createGMSHPoints(gmsh_pnts);
344 }
345}
346
347void GMSHPolygonTree::writeLineLoop(std::size_t& line_offset,
348 std::size_t& sfc_offset, std::ostream& out,
349 bool const write_physical) const
350{
351 const std::size_t n_pnts(polygon().getNumberOfPoints());
352 for (std::size_t k(1), first_pnt_id(polygon().getPointID(0)); k < n_pnts;
353 k++)
354 {
355 std::size_t const second_pnt_id = polygon().getPointID(k);
356 out << "Line(" << line_offset + k - 1 << ") = {" << first_pnt_id << ","
357 << second_pnt_id << "};\n";
358 first_pnt_id = second_pnt_id;
359 }
360 out << "Line Loop(" << line_offset + n_pnts - 1 << ") = {";
361 for (std::size_t k(0); k < n_pnts - 2; k++)
362 {
363 out << line_offset + k << ",";
364 }
365 out << line_offset + n_pnts - 2 << "};\n";
366 out << "Plane Surface(" << sfc_offset << ") = {" << line_offset + n_pnts - 1
367 << "};\n";
368 if (write_physical)
369 {
370 out << "Physical Curve(" << sfc_offset << ") = {";
371 for (std::size_t k(0); k < n_pnts - 2; k++)
372 {
373 out << line_offset + k << ",";
374 }
375 out << line_offset + n_pnts - 2 << "};\n";
376 out << "Physical Surface(" << sfc_offset << ") = {" << sfc_offset
377 << "};\n";
378 }
379 line_offset += n_pnts;
380 sfc_offset++;
381}
382
383void GMSHPolygonTree::writeLineConstraints(std::size_t& line_offset,
384 std::size_t sfc_number,
385 std::ostream& out) const
386{
387 for (auto polyline : _plys)
388 {
389 const std::size_t n_pnts(polyline->getNumberOfPoints());
390 std::size_t first_pnt_id(polyline->getPointID(0));
391 for (std::size_t k(1); k < n_pnts; k++)
392 {
393 auto const second_pnt_id = polyline->getPointID(k);
394 if (polyline->isSegmentMarked(k - 1) &&
395 polygon().isPntInPolygon(*(polyline->getPoint(k))) &&
396 !GeoLib::containsEdge(polygon(), first_pnt_id, second_pnt_id))
397 {
398 out << "Line(" << line_offset + k - 1 << ") = {" << first_pnt_id
399 << "," << second_pnt_id << "};\n";
400 out << "Line { " << line_offset + k - 1 << " } In Surface { "
401 << sfc_number << " };\n";
402 }
403 first_pnt_id = second_pnt_id;
404 }
405 line_offset += n_pnts;
406 }
407}
408
410 std::size_t& line_offset, std::size_t sfc_number, std::ostream& out) const
411{
412 for (auto* child : *this)
413 {
414 dynamic_cast<GMSHPolygonTree*>(child)
415 ->writeSubPolygonsAsLineConstraints(line_offset, sfc_number, out);
416 }
417
418 if (!isRoot())
419 {
420 const std::size_t n_pnts(polygon().getNumberOfPoints());
421 std::size_t first_pnt_id(polygon().getPointID(0));
422 for (std::size_t k(1); k < n_pnts; k++)
423 {
424 auto const second_pnt_id = polygon().getPointID(k);
425 out << "Line(" << line_offset + k - 1 << ") = {" << first_pnt_id
426 << "," << second_pnt_id << "};\n";
427 first_pnt_id = second_pnt_id;
428 out << "Line { " << line_offset + k - 1 << " } In Surface { "
429 << sfc_number << " };\n";
430 }
431 line_offset += n_pnts;
432 }
433}
434
435void GMSHPolygonTree::writeStations(std::size_t& pnt_id_offset,
436 std::size_t sfc_number,
437 std::ostream& out) const
438{
439 for (auto const* station : _stations)
440 {
441 out << "Point(" << pnt_id_offset << ") = {" << (*station)[0] << ", "
442 << (*station)[1] << ", 0.0, "
443 << _mesh_density_strategy.getMeshDensityAtStation(station)
444 << "}; // Station "
445 << static_cast<GeoLib::Station const*>(station)->getName() << " \n";
446 out << "Point { " << pnt_id_offset << " } In Surface { " << sfc_number
447 << " };\n";
448 ++pnt_id_offset;
449 }
450}
451
452void GMSHPolygonTree::writeAdditionalPointData(std::size_t& pnt_id_offset,
453 std::size_t sfc_number,
454 std::ostream& out) const
455{
456 if (auto const* adaptive_mesh_density =
458 {
459 std::vector<GeoLib::Point*> steiner_pnts;
460 adaptive_mesh_density->getSteinerPoints(steiner_pnts, 0);
461 const std::size_t n(steiner_pnts.size());
462 for (std::size_t k(0); k < n; k++)
463 {
464 if (polygon().isPntInPolygon(*(steiner_pnts[k])))
465 {
466 out << "Point(" << pnt_id_offset + k << ") = {"
467 << (*(steiner_pnts[k]))[0] << "," << (*(steiner_pnts[k]))[1]
468 << ", 0.0, ";
469 out << _mesh_density_strategy.getMeshDensityAtPoint(
470 steiner_pnts[k])
471 << "};\n";
472 out << "Point { " << pnt_id_offset + k << " } In Surface { "
473 << sfc_number << " };\n";
474 }
475 delete steiner_pnts[k];
476 }
477 pnt_id_offset += n;
478 }
479
480#ifndef NDEBUG
481 if (auto* adaptive_mesh_density =
483 {
484 auto const quad_tree_geo =
485 adaptive_mesh_density->getQuadTreeGeometry(_geo_objs);
486 std::vector<std::size_t> const& id_map(
487 (_geo_objs.getPointVecObj(quad_tree_geo))->getIDMap());
488 auto& plys = _geo_objs.getPolylineVecObj(quad_tree_geo)->getVector();
489 for (std::size_t k(0); k < plys.size(); k++)
490 {
491 GeoLib::resetPointIDs(*plys[k], id_map);
492 }
493 }
494#endif
495}
496
498 std::vector<GeoLib::Point const*>& pnts) const
499{
500 for (auto const* child : *this)
501 {
502 dynamic_cast<GMSHPolygonTree const*>(child)->getPointsFromSubPolygons(
503 pnts);
504 }
505}
506
508 std::vector<GeoLib::Point const*>& stations) const
509{
510 const std::size_t n_stations(_stations.size());
511 for (std::size_t k(0); k < n_stations; k++)
512 {
513 stations.push_back(_stations[k]);
514 }
515
516 for (auto const* child : *this)
517 {
518 dynamic_cast<GMSHPolygonTree const*>(child)
520 }
521}
522
523} // end namespace GMSH
524} // end namespace FileIO
#define OGS_FATAL(...)
Definition Error.h:19
std::string getName(std::string const &line)
Returns the name/title from the "Zone"-description.
void writeSubPolygonsAsLineConstraints(std::size_t &line_offset, std::size_t sfc_number, std::ostream &out) const
std::vector< GeoLib::PolylineWithSegmentMarker * > _plys
GMSHMeshDensityStrategy & _mesh_density_strategy
void insertPolyline(GeoLib::PolylineWithSegmentMarker *ply)
virtual void writeLineConstraints(std::size_t &line_offset, std::size_t sfc_number, std::ostream &out) const
std::string const & _geo_name
void writeAdditionalPointData(std::size_t &pnt_id_offset, std::size_t sfc_number, std::ostream &out) const
std::vector< GeoLib::Point const * > _stations
GMSHPolygonTree(GeoLib::PolygonWithSegmentMarker *polygon, GMSHPolygonTree *parent, GeoLib::GEOObjects &geo_objs, std::string const &geo_name, GMSHMeshDensityStrategy &mesh_density_strategy)
void getStationsInsideSubPolygons(std::vector< GeoLib::Point const * > &stations) const
void writeStations(std::size_t &pnt_id_offset, std::size_t sfc_number, std::ostream &out) const
void createGMSHPoints(std::vector< GMSHPoint * > &gmsh_pnts) const
void getPointsFromSubPolygons(std::vector< GeoLib::Point const * > &pnts) const
void checkIntersectionsSegmentExistingPolylines(GeoLib::PolylineWithSegmentMarker *ply, GeoLib::Polyline::SegmentIterator const &seg_it)
GeoLib::GEOObjects & _geo_objs
bool insertStation(GeoLib::Point const *station)
std::vector< GMSHLine * > _gmsh_lines_for_constraints
virtual void writeLineLoop(std::size_t &line_offset, std::size_t &sfc_offset, std::ostream &out, bool const write_physical) const
Container class for geometric objects.
Definition GEOObjects.h:46
This class manages pointers to Points in a std::vector along with a name. It also handles the deletio...
Definition PointVec.h:25
std::size_t push_back(Point *pnt)
Definition PointVec.cpp:124
bool isSegmentMarked(std::size_t seg_num) const
void markSegment(std::size_t seg_num, bool mark_val=true)
bool insertPoint(std::size_t pos, std::size_t pnt_id) override
std::size_t getSegmentNumber() const
Definition Polyline.cpp:376
std::size_t getPointID(std::size_t const i) const
Definition Polyline.cpp:149
virtual bool insertPoint(std::size_t pos, std::size_t pnt_id)
Definition Polyline.cpp:44
SegmentIterator begin() const
Definition Polyline.h:177
bool isPointIDInPolyline(std::size_t pnt_id) const
Definition Polyline.cpp:143
SegmentIterator end() const
Definition Polyline.h:179
SimplePolygonTree(Polygon *polygon, SimplePolygonTree *parent)
const SimplePolygonTree * parent() const
Polygon const & polygon() const
A Station (observation site) is basically a Point with some additional information.
Definition Station.h:26
std::size_t size() const
Definition TemplateVec.h:88
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:249
bool containsEdge(const Polyline &ply, std::size_t id0, std::size_t id1)
Definition Polyline.cpp:494
void resetPointIDs(Polyline &polyline, std::vector< std::size_t > const &mapping)
Resets the point IDs of the polyline corresponding to the mapping.
Definition Polyline.cpp:464
bool lineSegmentIntersect(GeoLib::LineSegment const &s0, GeoLib::LineSegment const &s1, GeoLib::Point &s)