Example #1
0
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!
}