F32 CatmullRomBase::arcLength( F32 t1, F32 t2 ) { if ( t2 <= t1 ) return 0.0f; if ( t1 < mTimes[0] ) t1 = mTimes[0]; if ( t2 > mTimes[mCount-1] ) t2 = mTimes[mCount-1]; // find segment and parameter U32 seg1; for ( seg1 = 0; seg1 < mCount-1; ++seg1 ) { if ( t1 <= mTimes[seg1+1] ) { break; } } F32 u1 = (t1 - mTimes[seg1])/(mTimes[seg1+1] - mTimes[seg1]); // find segment and parameter U32 seg2; for ( seg2 = 0; seg2 < mCount-1; ++seg2 ) { if ( t2 <= mTimes[seg2+1] ) { break; } } F32 u2 = (t2 - mTimes[seg2])/(mTimes[seg2+1] - mTimes[seg2]); F32 result; // both parameters lie in one segment if ( seg1 == seg2 ) { result = segmentArcLength( seg1, u1, u2 ); } // parameters cross segments else { result = segmentArcLength( seg1, u1, 1.0f ); for ( U32 i = seg1+1; i < seg2; ++i ) result += mLengths[i]; result += segmentArcLength( seg2, 0.0f, u2 ); } return result; }
void CatmullRomBase::_initialize( U32 count, const F32 *times ) { //AssertFatal( times, "CatmullRomBase::_initialize() - Got null position!" ) AssertFatal( count > 1, "CatmullRomBase::_initialize() - Must have more than 2 points!" ) // set up arrays mTimes = new F32[count]; mCount = count; // set up curve segment lengths mLengths = new F32[count-1]; mTotalLength = 0.0f; for ( U32 i = 0; i < count-1; ++i ) { mLengths[i] = segmentArcLength(i, 0.0f, 1.0f); mTotalLength += mLengths[i]; } // copy the times if we have them. F32 l = 0.0f; for ( U32 i = 0; i < count; ++i ) { if ( times ) mTimes[i] = times[i]; else { if ( mIsZero( mTotalLength ) ) mTimes[i] = 0.0f; else mTimes[i] = l / mTotalLength; if ( i < count-1 ) l += mLengths[i]; } } }
/*! Init curve with curve points and times. If no control points are passed they will be calculated automatically @param points Array of points on the Bézier curve (w = time) @param controlPoints Array of control points with size = 2*(numPointsAndTimes-1) */ void SLCurveBezier::init(const SLVVec4f& points, const SLVVec3f& controlPoints) { assert(points.size() > 1); dispose(); // set up arrays _points.clear(); _points.resize(points.size()); _controls.resize(2*(points.size()-1)); // copy interpolated data SLuint i; for (i = 0; i < _points.size(); ++i) { _points[i] = points[i]; } if (controlPoints.size()==0) { if (points.size() > 2) { // create approximating control points for (i = 0; i < _points.size()-1; ++i) { if (i > 0) _controls[2*i] = (_points[i] + (_points[i+1]-_points[i-1])/3.0f).vec3(); if (i < _points.size()-2) _controls[2*i+1] = (_points[i+1] - (_points[i+2]-_points[i ])/3.0f).vec3(); } _controls[0] = (SLVec4f(_controls[1]) - (_points[1] - _points[0])/3.0f).vec3(); _controls[2*_points.size()-3] = (SLVec4f(_controls[2*_points.size()-4]) + (_points[_points.size()-1] - _points[_points.size()-2])/3.0f).vec3(); } else { _controls[0] = (_points[0] + (_points[1]-_points[0])/3.0f).vec3(); _controls[1] = (_points[1] - (_points[1]-_points[0])/3.0f).vec3(); } } else { // copy approximating control points for (i = 0; i < 2*(_points.size()-1); ++i) _controls[i] = controlPoints[i]; } // set up curve segment lengths _lengths.clear(); _lengths.resize(_points.size()-1); _totalLength = 0.0f; _totalLength = 0.0f; for (SLuint i = 0; i < _points.size()-1; ++i) { _lengths[i] = segmentArcLength(i, 0.0f, 1.0f); _totalLength += _lengths[i]; } }
/*! Calculate length of curve between parameters t1 and t2 */ SLfloat SLCurveBezier::arcLength(SLfloat t1, SLfloat t2) { if (t2 <= t1) return 0.0f; if (t1 < _points[0].w) t1 = _points[0].w; if (t2 > _points[_points.size()-1].w) t2 = _points[_points.size()-1].w; // find segment and parameter unsigned int seg1; for (seg1 = 0; seg1 < _points.size()-1; ++seg1) if (t1 < _points[seg1+1].w) break; SLfloat u1 = (t1 - _points[seg1].w)/(_points[seg1+1].w - _points[seg1].w); // find segment and parameter unsigned int seg2; for (seg2 = 0; seg2 < _points.size()-1; ++seg2) if (t2 <= _points[seg2+1].w) break; SLfloat u2 = (t2 - _points[seg2].w)/(_points[seg2+1].w - _points[seg2].w); // both parameters lie in one segment SLfloat result; if (seg1 == seg2) result = segmentArcLength(seg1, u1, u2); // parameters cross segments else { result = segmentArcLength(seg1, u1, 1.0f); for (SLuint i = seg1+1; i < seg2; ++i) result += _lengths[i]; result += segmentArcLength(seg2, 0.0f, u2); } return result; }