Loading [MathJax]/extensions/TeX/AMSsymbols.js
Radium Engine  1.5.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
PolyLine.cpp
1 #include <Core/Geometry/PolyLine.hpp>
2 
3 namespace Ra {
4 namespace Core {
5 namespace Geometry {
6 
8  m_ptsDiff.clear();
9  m_lengths.clear();
10  CORE_ASSERT( m_pts.size() > 1, "Line must have at least two points" );
11  m_ptsDiff.reserve( m_pts.size() - 1 );
12  m_lengths.reserve( m_pts.size() - 1 );
13  Scalar len = 0;
14  for ( uint i = 0; i < m_pts.size() - 1; ++i ) {
15  m_ptsDiff.push_back( m_pts[i + 1] - m_pts[i] );
16  len += m_ptsDiff.back().norm();
17  m_lengths.push_back( len );
18  }
19 }
20 
21 PolyLine::PolyLine( const Vector3Array& pts ) : m_pts( pts ) {
22  update();
23 }
24 
25 void PolyLine::setPoints( const Vector3Array& pts ) {
26  m_pts = pts;
27  update();
28 }
29 
30 Scalar PolyLine::squaredDistance( const Vector3& p ) const {
31  CORE_ASSERT( m_pts.size() > 1, "Line must have at least two points" );
32  Scalar sqDist = std::numeric_limits<Scalar>::max();
33  for ( uint i = 0; i < m_ptsDiff.size(); ++i ) {
34  sqDist = std::min( Geometry::pointToSegmentSq( p, m_pts[i], m_ptsDiff[i] ), sqDist );
35  }
36  return sqDist;
37 }
38 
39 Scalar PolyLine::distance( const Vector3& p ) const {
40  return std::sqrt( squaredDistance( p ) );
41 }
42 
43 Scalar PolyLine::projectOnSegment( const Vector3& p, uint segment ) const {
44  CORE_ASSERT( segment < m_ptsDiff.size(), "invalid segment index" );
45  const Scalar tSegment = Geometry::projectOnSegment( p, m_pts[segment], m_ptsDiff[segment] );
46  return getLineParameter( segment, tSegment );
47 }
48 
49 Scalar PolyLine::project( const Vector3& p ) const {
50  CORE_ASSERT( m_pts.size() > 1, "Line must have at least two points" );
51  Scalar sqDist = std::numeric_limits<Scalar>::max();
52  uint segment = 0;
53  std::vector<Scalar> ts;
54  std::vector<Scalar> ds;
55  ts.reserve( m_ptsDiff.size() );
56  ds.reserve( m_ptsDiff.size() );
57 
58  for ( uint i = 0; i < m_ptsDiff.size(); ++i ) {
59  Scalar proj = Geometry::projectOnSegment( p, m_pts[i], m_ptsDiff[i] );
60  Scalar d = ( p - ( m_pts[i] + proj * ( m_ptsDiff[i] ) ) ).squaredNorm();
61  ds.push_back( d );
62  ts.push_back( proj );
63  if ( d < sqDist ) {
64  sqDist = d;
65  segment = i;
66  }
67  }
68 
69  CORE_ASSERT( segment < m_ptsDiff.size(), "Invalid index" );
70  Scalar t = ts[segment];
71  if ( t > 0 && t < 1 ) {
72  bool prev = segment > 0 && ts[segment - 1] > 0 && ts[segment - 1] < 1;
73  bool next = segment < m_ptsDiff.size() - 1 && ts[segment + 1] > 0 && ts[segment + 1] < 1;
74  if ( prev || next ) {
75  if ( prev && next ) { prev = ds[segment - 1] < ds[segment + 1]; }
76  uint i = prev ? segment - 1 : segment;
77  Vector3 ba = -m_ptsDiff[i];
78  Vector3 bc = m_ptsDiff[i + 1];
79  Vector3 bp = p - m_pts[i + 1];
80  Scalar c1 = Math::cotan( ba, bp );
81  Scalar c2 = Math::cotan( bp, bc );
82 
83  Scalar t1 = getLineParameter( i, ts[i] );
84  Scalar t2 = getLineParameter( i + 1, ts[i + 1] );
85  return ( c1 * t1 + c2 * t2 ) / ( c1 + c2 );
86  }
87  }
88  return getLineParameter( segment, t );
89 }
90 
91 Vector3 PolyLine::f( Scalar t ) const {
92  // Clamp the parameter between 0 and 1 and scale it.
93  const Scalar param = length() * Math::saturate( t );
94 
95  // Try to locate the segment section where f(t) belongs.
96  uint i = 0;
97  Scalar lprev = 0.f;
98  while ( m_lengths[i] < param ) {
99  lprev = m_lengths[i];
100  ++i;
101  }
102 
103  CORE_ASSERT( i < m_ptsDiff.size(), "Invalid index" );
104 
105  // Now we know point f(t) is between point Pi and Pi+1;
106  return m_pts[i] + ( ( param - lprev ) / ( m_lengths[i] - lprev ) ) * m_ptsDiff[i];
107 }
108 
109 uint PolyLine::getNearestSegment( const Vector3& p ) const {
110  CORE_ASSERT( m_pts.size() > 1, "Line must have at least two points" );
111  Scalar sqDist = std::numeric_limits<Scalar>::max();
112  uint segment = 0;
113  for ( uint i = 0; i < m_ptsDiff.size(); ++i ) {
114  Scalar proj = Geometry::projectOnSegment( p, m_pts[i], m_ptsDiff[i] );
115  Scalar d = ( p - ( m_pts[i] + proj * ( m_ptsDiff[i] ) ) ).squaredNorm();
116  if ( d < sqDist ) {
117  sqDist = d;
118  segment = i;
119  }
120  }
121 
122  CORE_ASSERT( segment < m_ptsDiff.size(), "Invalid index" );
123  return segment;
124 }
125 
126 } // namespace Geometry
127 } // namespace Core
128 } // namespace Ra
uint getNearestSegment(const Vector3 &p) const
Returns the index of the nearest segment.
Definition: PolyLine.cpp:109
PolyLine(const Vector3Array &pt)
Create a polyline from a given set of points.
Definition: PolyLine.cpp:21
Vector3 f(Scalar t) const
Definition: PolyLine.cpp:91
void update()
Update the precomputed values after new points have been set.
Definition: PolyLine.cpp:7
Scalar distance(const Vector3 &p) const
Return the distance between the line and a given point p.
Definition: PolyLine.cpp:39
Scalar getLineParameter(uint segment, Scalar tSegment) const
Definition: PolyLine.hpp:97
void setPoints(const Vector3Array &pt)
Update the points of the polyline.
Definition: PolyLine.cpp:25
Scalar squaredDistance(const Vector3 &p) const
Return the squared distance between the line and a given point p.
Definition: PolyLine.cpp:30
Scalar projectOnSegment(const Vector3 &p, uint segment) const
Definition: PolyLine.cpp:43
Scalar project(const Vector3 &p) const
Definition: PolyLine.cpp:49
Scalar length() const
Get the total length of the line .
Definition: PolyLine.hpp:85
Scalar cotan(const Vector_ &v1, const Vector_ &v2)
constexpr T saturate(T v)
Clamps the value between 0 and 1.
Definition: Math.hpp:120
Definition: Cage.cpp:3