float vsSpline3D::ClosestTimeTo( const vsVector3D& position ) { //lastBestT is a composite value; //the whole part is the "before" knot, and the fraction //is the 't' for that segment. float lastBestT = 0.5f; float lastMove = 1.f; float scale = 0.75f; vsVector3D lastBestPoint; vsVector3D lastBestTangent; int iterations = 0; while ( lastMove > 0.0001f ) { lastBestPoint = PositionAtTime(lastBestT); lastBestTangent = VelocityAtTime(lastBestT); vsVector3D delta = position - lastBestPoint; float move = lastBestTangent.Dot(delta) / lastBestTangent.SqLength(); move = vsClamp(move, -lastMove*scale, lastMove*scale); lastBestT = vsClamp( lastBestT+move, 0.f, 1.f ); lastMove = vsFabs(move); iterations++; } return lastBestT; }
vsVector3D vpDrawable::CalculateOptimisedPositionForIndex(int index, int ignoringOptimisedIndex) { int preIndex = 0; int postIndex = m_optimisedIndexCount; for ( int i = 0; i < m_optimisedIndexCount; i++ ) { if ( i != ignoringOptimisedIndex ) { int optIndex = m_optimisedIndex[i]; if ( optIndex <= index ) preIndex = optIndex; if ( optIndex >= index ) { postIndex = optIndex; break; } } } vsVector3D correctPos = m_samplePos[index]; if ( preIndex == index || postIndex == index ) return correctPos; // okay. We're on an optimised line segment from preIndex to postIndex; we want to find where // on that line segment is closest to 'correctPos'. vsVector3D segmentA = m_samplePos[preIndex]; vsVector3D segmentB = m_samplePos[postIndex]; vsVector3D segmentDirection = segmentB - segmentA; float segmentLength = segmentDirection.Length(); segmentDirection *= 1.0f / segmentLength; // Use a dot product to find the projection of 'segmentA->correctPos' onto 'segmentA->segmentB', and use that to pick // the nearest spot on the line segment. float projectionLength = segmentDirection.Dot( correctPos - segmentA ); // clamp it into (0..segmentLength). projectionLength = vsClamp(projectionLength, 0.f, segmentLength); return (segmentA + (segmentDirection * projectionLength)); // done! }