OGS
Polyline.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 "Polyline.h"
5
6#include <algorithm>
7
9#include "BaseLib/Error.h"
10#include "BaseLib/Logging.h"
12#include "MathLib/MathTools.h"
13#include "PointVec.h"
14
15namespace GeoLib
16{
17Polyline::Polyline(const std::vector<Point*>& pnt_vec) : _ply_pnts(pnt_vec) {}
18
23
24bool Polyline::addPoint(std::size_t pnt_id)
25{
26 if (pnt_id >= _ply_pnts.size())
27 {
28 return false;
29 }
30 std::size_t const n_pnts(_ply_pnt_ids.size());
31
32 // don't insert point if this would result in identical IDs for two adjacent
33 // points
34 if (n_pnts > 0 && _ply_pnt_ids.back() == pnt_id)
35 {
36 return false;
37 }
38
39 _ply_pnt_ids.push_back(pnt_id);
40
41 return true;
42}
43
44bool Polyline::insertPoint(std::size_t pos, std::size_t pnt_id)
45{
46 if (pnt_id >= _ply_pnts.size())
47 {
48 return false;
49 }
50 if (pos > _ply_pnt_ids.size())
51 {
52 return false;
53 }
54
55 if (pos == _ply_pnt_ids.size())
56 {
57 return addPoint(pnt_id);
58 }
59
60 // check if inserting pnt_id would result in two identical IDs for adjacent
61 // points
62 if (pos == 0 && pnt_id == _ply_pnt_ids[0])
63 {
64 return false;
65 }
66 if (pos != 0)
67 {
68 if (pos == (_ply_pnt_ids.size() - 1) && pnt_id == _ply_pnt_ids[pos])
69 {
70 return false;
71 }
72 if (pnt_id == _ply_pnt_ids[pos - 1] || pnt_id == _ply_pnt_ids[pos])
73 {
74 return false;
75 }
76 }
77
78 auto const pos_dt(
79 static_cast<std::vector<std::size_t>::difference_type>(pos));
80 auto it(_ply_pnt_ids.begin() + pos_dt);
81 _ply_pnt_ids.insert(it, pnt_id);
82
83 return true;
84}
85
86void Polyline::removePoint(std::size_t pos)
87{
88 if (pos >= _ply_pnt_ids.size())
89 {
90 return;
91 }
92
93 auto const pos_dt(
94 static_cast<std::vector<std::size_t>::difference_type>(pos));
95 _ply_pnt_ids.erase(_ply_pnt_ids.begin() + pos_dt);
96}
97
98std::size_t Polyline::getNumberOfPoints() const
99{
100 return _ply_pnt_ids.size();
101}
102
104{
105 return _ply_pnt_ids.empty() ? 0 : _ply_pnt_ids.size() - 1;
106}
107
109{
110 if (_ply_pnt_ids.size() < 3)
111 {
112 return false;
113 }
114
115 return _ply_pnt_ids.front() == _ply_pnt_ids.back();
116}
117
119{
120 std::size_t const n_points(_ply_pnt_ids.size());
121 if (n_points < 4)
122 {
123 return true;
124 }
125
126 GeoLib::Point const& p0(*this->getPoint(0));
127 GeoLib::Point const& p1(*this->getPoint(1));
128 GeoLib::Point const& p2(*this->getPoint(2));
129 for (std::size_t i = 3; i < n_points; ++i)
130 {
131 if (!MathLib::isCoplanar(p0, p1, p2, *this->getPoint(i)))
132 {
133 DBUG(
134 "Point {:d} is not coplanar to the first three points of the "
135 "line.",
136 i);
137 return false;
138 }
139 }
140 return true;
141}
142
143bool Polyline::isPointIDInPolyline(std::size_t pnt_id) const
144{
145 return std::find(_ply_pnt_ids.begin(), _ply_pnt_ids.end(), pnt_id) !=
146 _ply_pnt_ids.end();
147}
148
149std::size_t Polyline::getPointID(std::size_t i) const
150{
151 assert(i < _ply_pnt_ids.size());
152 return _ply_pnt_ids[i];
153}
154
156{
157 assert(i < getNumberOfSegments());
159 _ply_pnts[_ply_pnt_ids[i + 1]], false);
160}
161
162void Polyline::setPointID(std::size_t idx, std::size_t id)
163{
164 assert(idx < _ply_pnt_ids.size());
165 _ply_pnt_ids[idx] = id;
166}
167
168const Point* Polyline::getPoint(std::size_t i) const
169{
170 assert(i < _ply_pnt_ids.size());
171 return _ply_pnts[_ply_pnt_ids[i]];
172}
173
174std::vector<Point*> const& Polyline::getPointsVec() const
175{
176 return _ply_pnts;
177}
178
180 const std::vector<Polyline*>& ply_vec, double prox)
181{
182 std::size_t nLines = ply_vec.size();
183
184 auto* new_ply = new Polyline(*ply_vec[0]);
185 std::vector<GeoLib::Point*> pnt_vec(new_ply->getPointsVec());
186
187 std::vector<Polyline*> local_ply_vec;
188 for (std::size_t i = 1; i < nLines; i++)
189 {
190 local_ply_vec.push_back(ply_vec[i]);
191 }
192
193 while (!local_ply_vec.empty())
194 {
195 bool ply_found(false);
196 prox *= prox; // square distance once to save time later
197 for (auto it = local_ply_vec.begin(); it != local_ply_vec.end(); ++it)
198 {
199 if (pnt_vec == (*it)->getPointsVec())
200 {
201 std::size_t nPoints((*it)->getNumberOfPoints());
202
203 // if (new_ply->getPointID(0) == (*it)->getPointID(0))
204 if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0),
205 (*it)->getPointID(0), prox))
206 {
207 auto* tmp = new Polyline((*it)->getPointsVec());
208 for (std::size_t k = 0; k < nPoints; k++)
209 {
210 tmp->addPoint((*it)->getPointID(nPoints - k - 1));
211 }
212
213 std::size_t new_ply_size(new_ply->getNumberOfPoints());
214 for (std::size_t k = 1; k < new_ply_size; k++)
215 {
216 tmp->addPoint(new_ply->getPointID(k));
217 }
218 delete new_ply;
219 new_ply = tmp;
220 ply_found = true;
221 }
222 // else if (new_ply->getPointID(0) ==
223 // (*it)->getPointID(nPoints-1))
224 else if (pointsAreIdentical(pnt_vec, new_ply->getPointID(0),
225 (*it)->getPointID(nPoints - 1),
226 prox))
227 {
228 auto* tmp = new Polyline(**it);
229 std::size_t new_ply_size(new_ply->getNumberOfPoints());
230 for (std::size_t k = 1; k < new_ply_size; k++)
231 {
232 tmp->addPoint(new_ply->getPointID(k));
233 }
234 delete new_ply;
235 new_ply = tmp;
236 ply_found = true;
237 }
238 // else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1)
239 // == (*it)->getPointID(0))
240 else if (pointsAreIdentical(
241 pnt_vec,
242 new_ply->getPointID(new_ply->getNumberOfPoints() -
243 1),
244 (*it)->getPointID(0), prox))
245 {
246 for (std::size_t k = 1; k < nPoints; k++)
247 {
248 new_ply->addPoint((*it)->getPointID(k));
249 }
250 ply_found = true;
251 }
252 // else if (new_ply->getPointID(new_ply->getNumberOfPoints()-1)
253 // == (*it)->getPointID(nPoints-1))
254 else if (pointsAreIdentical(
255 pnt_vec,
256 new_ply->getPointID(new_ply->getNumberOfPoints() -
257 1),
258 (*it)->getPointID(nPoints - 1), prox))
259 {
260 for (std::size_t k = 1; k < nPoints; k++)
261 {
262 new_ply->addPoint((*it)->getPointID(nPoints - k - 1));
263 }
264 ply_found = true;
265 }
266 if (ply_found)
267 {
268 local_ply_vec.erase(it);
269 break;
270 }
271 }
272 else
273 {
274 ERR("Error in Polyline::contructPolylineFromSegments() - Line "
275 "segments use different point vectors.");
276 }
277 }
278
279 if (!ply_found)
280 {
281 ERR("Error in Polyline::contructPolylineFromSegments() - Not all "
282 "segments are connected.");
283 delete new_ply;
284 new_ply = nullptr;
285 break;
286 }
287 }
288 return new_ply;
289}
290
292{
293 if (getNumberOfPoints() < 2)
294 {
295 ERR("Polyline::closePolyline(): Input polyline needs to be composed of "
296 "at least three points.");
297 }
298 if (!isClosed())
299 {
301 }
302}
303
305 const double epsilon_radius) const
306{
307 double dist(-1.0);
308 double lambda;
309 bool found = false;
310 double act_length_of_ply = 0.0;
311 // loop over all line segments of the polyline
312 for (std::size_t k = 0; k < getNumberOfSegments(); k++)
313 {
314 auto const& a = getPoint(k)->asEigenVector3d();
315 auto const& b = getPoint(k + 1)->asEigenVector3d();
316 double const seg_length((b - a).norm());
317 act_length_of_ply += seg_length;
318 // is the orthogonal projection of the j-th node to the
319 // line g(lambda) = _ply->getPoint(k) + lambda * (_ply->getPoint(k+1) -
320 // _ply->getPoint(k)) at the k-th line segment of the polyline, i.e. 0
321 // <= lambda <= 1?
323 *getPoint(k + 1), lambda,
324 dist) <= epsilon_radius)
325 {
326 double const lower_lambda(-epsilon_radius / seg_length);
327 double const upper_lambda(1 + epsilon_radius / seg_length);
328
329 if (lower_lambda <= lambda && lambda <= upper_lambda)
330 {
331 found = true;
332 dist = act_length_of_ply + dist;
333 break;
334 } // end if lambda
335 }
336 } // end line segment loop
337
338 if (!found)
339 {
340 dist = -1.0;
341 }
342 return dist;
343}
344
346{
347 std::reverse(_ply_pnt_ids.begin(), _ply_pnt_ids.end());
348}
349
351 std::size_t segment_number)
352 : _polyline(&polyline),
354 static_cast<std::vector<GeoLib::Point*>::size_type>(segment_number))
355{
356}
357
362
364 SegmentIterator const& rhs)
365{
366 if (&rhs == this)
367 {
368 return *this;
369 }
370
371 _polyline = rhs._polyline;
373 return *this;
374}
375
377{
378 return static_cast<std::size_t>(_segment_number);
379}
380
386
391
396
398{
399 return !(*this != other);
400}
401
403{
404 return other._segment_number != _segment_number ||
405 other._polyline != _polyline;
406}
407
409 std::vector<GeoLib::Point>::difference_type n)
410{
411 if (n < 0)
412 {
414 static_cast<std::vector<GeoLib::Point>::size_type>(-n);
415 }
416 else
417 {
419 static_cast<std::vector<GeoLib::Point>::size_type>(n);
420 }
421 if (_segment_number > _polyline->getNumberOfSegments())
422 {
423 OGS_FATAL("");
424 }
425 return *this;
426}
427
429 std::vector<GeoLib::Point>::difference_type n)
430{
431 SegmentIterator t(*this);
432 t += n;
433 return t;
434}
435
437 std::vector<GeoLib::Point>::difference_type n)
438{
439 if (n >= 0)
440 {
442 static_cast<std::vector<GeoLib::Point>::size_type>(n);
443 }
444 else
445 {
447 static_cast<std::vector<GeoLib::Point>::size_type>(-n);
448 }
449 if (_segment_number > _polyline->getNumberOfSegments())
450 {
451 OGS_FATAL("");
452 }
453 return *this;
454}
455
457 std::vector<GeoLib::Point>::difference_type n)
458{
460 t -= n;
461 return t;
462}
463
464void resetPointIDs(Polyline& polyline, std::vector<std::size_t> const& mapping)
465{
466 if (polyline.getPointsVec().size() != mapping.size())
467 {
468 OGS_FATAL(
469 "internal error in resetPointIDs(): polyline based on point vector "
470 "of size {}, given mapping has size {}",
471 polyline.getPointsVec().size(), mapping.size());
472 }
473 for (std::size_t i = 0; i < polyline.getNumberOfPoints(); ++i)
474 {
475 polyline.setPointID(i, mapping[polyline.getPointID(i)]);
476 }
477}
478
479void markUsedPoints(Polyline const& polyline, std::vector<bool>& used_points)
480{
481 if (polyline.getPointsVec().size() != used_points.size())
482 {
483 OGS_FATAL(
484 "internal error in markUsedPoints(): polyline based on point "
485 "vector of size {}, given used_points has size {}",
486 polyline.getPointsVec().size(), used_points.size());
487 }
488 for (std::size_t i = 0; i < polyline.getNumberOfPoints(); ++i)
489 {
490 used_points[polyline.getPointID(i)] = true;
491 }
492}
493
494bool containsEdge(const Polyline& ply, std::size_t id0, std::size_t id1)
495{
496 if (id0 == id1)
497 {
498 ERR("no valid edge id0 == id1 == {:d}.", id0);
499 return false;
500 }
501 if (id0 > id1)
502 {
503 std::swap(id0, id1);
504 }
505 const std::size_t n(ply.getNumberOfPoints() - 1);
506 for (std::size_t k(0); k < n; k++)
507 {
508 std::size_t ply_pnt0(ply.getPointID(k));
509 std::size_t ply_pnt1(ply.getPointID(k + 1));
510 if (ply_pnt0 > ply_pnt1)
511 {
512 std::swap(ply_pnt0, ply_pnt1);
513 }
514 if (ply_pnt0 == id0 && ply_pnt1 == id1)
515 {
516 return true;
517 }
518 }
519 return false;
520}
521
522bool operator==(Polyline const& lhs, Polyline const& rhs)
523{
524 if (lhs.getNumberOfPoints() != rhs.getNumberOfPoints())
525 {
526 return false;
527 }
528
529 const std::size_t n(lhs.getNumberOfPoints());
530 for (std::size_t k(0); k < n; k++)
531 {
532 if (lhs.getPointID(k) != rhs.getPointID(k))
533 {
534 return false;
535 }
536 }
537
538 return true;
539}
540
541bool pointsAreIdentical(const std::vector<Point*>& pnt_vec,
542 std::size_t i,
543 std::size_t j,
544 double prox)
545{
546 if (i == j)
547 {
548 return true;
549 }
550 return MathLib::sqrDist(*pnt_vec[i], *pnt_vec[j]) < prox;
551}
552
553std::unique_ptr<Polyline> createPolyline(GeoLib::PointVec const& points_vec,
554 std::vector<std::size_t>&& point_ids)
555{
556 auto const& point_id_map = points_vec.getIDMap();
557 auto polyline = std::make_unique<Polyline>(points_vec.getVector());
558 for (auto point_id : point_ids)
559 {
560 if (point_id >= point_id_map.size())
561 {
562 WARN("The point id {} doesn't exist in the underlying PointVec.",
563 point_id);
564 continue;
565 }
566 polyline->addPoint(point_id_map[point_id]);
567 }
568 return polyline;
569}
570} // end namespace GeoLib
#define OGS_FATAL(...)
Definition Error.h:19
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:22
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
This class manages pointers to Points in a std::vector along with a name. It also handles the deletio...
Definition PointVec.h:25
const std::vector< std::size_t > & getIDMap() const
Definition PointVec.h:86
GeoLib::Polyline const * _polyline
Definition Polyline.h:75
SegmentIterator & operator++()
Definition Polyline.cpp:381
SegmentIterator operator-(std::vector< GeoLib::Point >::difference_type n)
Definition Polyline.cpp:456
SegmentIterator & operator+=(std::vector< GeoLib::Point >::difference_type n)
Definition Polyline.cpp:408
LineSegment operator*() const
Definition Polyline.cpp:387
SegmentIterator & operator=(SegmentIterator const &rhs)
Definition Polyline.cpp:363
bool operator==(SegmentIterator const &other) const
Definition Polyline.cpp:397
SegmentIterator operator+(std::vector< GeoLib::Point >::difference_type n)
Definition Polyline.cpp:428
std::vector< GeoLib::Point * >::size_type _segment_number
Definition Polyline.h:76
std::size_t getSegmentNumber() const
Definition Polyline.cpp:376
bool operator!=(SegmentIterator const &other) const
Definition Polyline.cpp:402
SegmentIterator(Polyline const &polyline, std::size_t segment_number)
Definition Polyline.cpp:350
SegmentIterator & operator-=(std::vector< GeoLib::Point >::difference_type n)
Definition Polyline.cpp:436
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition Polyline.h:29
double getDistanceAlongPolyline(const MathLib::Point3d &pnt, const double epsilon_radius) const
Definition Polyline.cpp:304
std::size_t getPointID(std::size_t const i) const
Definition Polyline.cpp:149
std::size_t getNumberOfSegments() const
Definition Polyline.cpp:103
static Polyline * constructPolylineFromSegments(const std::vector< Polyline * > &ply_vec, double prox=0.0)
Definition Polyline.cpp:179
std::size_t getNumberOfPoints() const
Definition Polyline.cpp:98
const Point * getPoint(std::size_t i) const
returns the i-th point contained in the polyline
Definition Polyline.cpp:168
virtual bool insertPoint(std::size_t pos, std::size_t pnt_id)
Definition Polyline.cpp:44
std::vector< std::size_t > _ply_pnt_ids
Definition Polyline.h:211
void setPointID(std::size_t idx, std::size_t id)
Definition Polyline.cpp:162
void reverseOrientation()
Definition Polyline.cpp:345
bool isClosed() const
Definition Polyline.cpp:108
virtual bool addPoint(std::size_t pnt_id)
Definition Polyline.cpp:24
const std::vector< Point * > & _ply_pnts
Definition Polyline.h:200
LineSegment getSegment(std::size_t i) const
Definition Polyline.cpp:155
Polyline(const std::vector< Point * > &pnt_vec)
Definition Polyline.cpp:17
bool isPointIDInPolyline(std::size_t pnt_id) const
Definition Polyline.cpp:143
bool isCoplanar() const
Definition Polyline.cpp:118
void removePoint(std::size_t pos)
Definition Polyline.cpp:86
std::vector< Point * > const & getPointsVec() const
Definition Polyline.cpp:174
std::vector< T * > const & getVector() const
Definition TemplateVec.h:94
Eigen::Vector3d const & asEigenVector3d() const
Definition Point3d.h:55
bool containsEdge(const Polyline &ply, std::size_t id0, std::size_t id1)
Definition Polyline.cpp:494
bool pointsAreIdentical(const std::vector< Point * > &pnt_vec, std::size_t i, std::size_t j, double prox)
Definition Polyline.cpp:541
void markUsedPoints(Polyline const &polyline, std::vector< bool > &used_points)
Resets the point IDs of the polyline corresponding to the mapping.
Definition Polyline.cpp:479
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 operator==(LineSegment const &s0, LineSegment const &s1)
std::unique_ptr< Polyline > createPolyline(GeoLib::PointVec const &points_vec, std::vector< std::size_t > &&point_ids)
Create a polyline from given point ids.
Definition Polyline.cpp:553
bool isCoplanar(const MathLib::Point3d &a, const MathLib::Point3d &b, const MathLib::Point3d &c, const MathLib::Point3d &d)
Checks if the four given points are located on a plane.
double calcProjPntToLineAndDists(Point3d const &pp, Point3d const &pa, Point3d const &pb, double &lambda, double &d0)
Definition MathTools.cpp:13
double sqrDist(MathLib::Point3d const &p0, MathLib::Point3d const &p1)
Definition Point3d.cpp:19