Radium Engine  1.5.20
Loading...
Searching...
No Matches
PolyLine.cpp
1#include <Core/Geometry/PolyLine.hpp>
2
3namespace Ra {
4namespace Core {
5namespace 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
21PolyLine::PolyLine( const Vector3Array& pts ) : m_pts( pts ) {
22 update();
23}
24
25void PolyLine::setPoints( const Vector3Array& pts ) {
26 m_pts = pts;
27 update();
28}
29
30Scalar 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
39Scalar PolyLine::distance( const Vector3& p ) const {
40 return std::sqrt( squaredDistance( p ) );
41}
42
43Scalar 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
49Scalar 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;
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
91Vector3 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
109uint 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
T clear(T... args)
T max(T... args)
T min(T... args)
Scalar cotan(const Vector_ &v1, const Vector_ &v2)
constexpr T saturate(T v)
Clamps the value between 0 and 1.
Definition Math.hpp:120
@ Geometry
"Geometry" render objects are those loaded using Radium::IO and generated by GeometrySystem
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T push_back(T... args)
T reserve(T... args)
T sqrt(T... args)