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