///SimsimplexConvexCast calculateTimeOfImpact calculates the time of impact+normal for the linear cast (sweep) between two moving objects.
		///Precondition is that objects should not penetration/overlap at the start from the interval. Overlap can be tested using btGjkPairDetector.
		/// 
		///Typically the conservative advancement reaches solution in a few iterations, clip it to 32 for degenerate cases.
		///See discussion about this here http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=565
		internal override bool calcTimeOfImpact(
				ref btTransform fromA,
				ref btTransform toA,
				ref btTransform fromB,
				ref btTransform toB,
				CastResult result )
		{

			m_simplexSolver.reset();

			btVector3 linVelA, linVelB;
			toA.m_origin.Sub( ref fromA.m_origin, out linVelA );
			toB.m_origin.Sub( ref fromB.m_origin, out linVelB );

			double lambda = btScalar.BT_ZERO;

			btTransform interpolatedTransA; fromA.Get( out interpolatedTransA );
			btTransform interpolatedTransB; fromB.Get( out interpolatedTransB );

			///take relative motion
			btVector3 r; linVelA.Sub( ref linVelB, out r );
			btVector3 v;
			btVector3 tmp;
			btVector3 tmp2;

			r.Invert( out v );
			fromA.m_basis.ApplyInverse( ref v, out tmp );
			m_convexA.localGetSupportingVertex( ref tmp, out tmp2 );
			btVector3 supVertexA; fromA.Apply( ref tmp2, out supVertexA );
			//btVector3 supVertexA = fromA( m_convexA.localGetSupportingVertex( -r * fromA.getBasis() ) );

			fromB.m_basis.ApplyInverse( ref r, out tmp );
			m_convexB.localGetSupportingVertex( ref tmp, out tmp2 );
			btVector3 supVertexB; fromB.Apply( ref tmp2, out supVertexB );
			//btVector3 supVertexB = fromB( m_convexB.localGetSupportingVertex( r * fromB.getBasis() ) );
			supVertexA.Sub( ref supVertexB, out v );
			//v = supVertexA - supVertexB;
			int maxIter = MAX_ITERATIONS;

			btVector3 n = btVector3.Zero;

			//btVector3 c;


			double dist2 = v.length2();
			btVector3 w;
			double VdotR;

			while( ( dist2 > btScalar.SIMD_LARGE_EPSILON ) && ( maxIter-- != 0 ) )
			{
				//btVector3 tmp, tmp2;
				v.Invert( out tmp );
				interpolatedTransA.m_basis.ApplyInverse( ref tmp, out tmp2 );
				m_convexA.localGetSupportingVertex( ref tmp2, out tmp );
				interpolatedTransA.Apply( ref tmp, out supVertexA );
				//supVertexA = interpolatedTransA( m_convexA.localGetSupportingVertex( -v * interpolatedTransA.getBasis() ) );
				interpolatedTransB.m_basis.ApplyInverse( ref v, out tmp2 );
				m_convexB.localGetSupportingVertex( ref tmp2, out tmp );
				interpolatedTransB.Apply( ref tmp, out supVertexB );
				//supVertexB = interpolatedTransB( m_convexB.localGetSupportingVertex( v * interpolatedTransB.getBasis() ) );
				supVertexA.Sub( ref supVertexB, out w );
				//w = supVertexA - supVertexB;

				double VdotW = v.dot( ref w );

				if( lambda > (double)( 1.0 ) )
				{
					return false;
				}

				if( VdotW > btScalar.BT_ZERO )
				{
					VdotR = v.dot( ref r );

					if( VdotR >= -( btScalar.SIMD_EPSILON * btScalar.SIMD_EPSILON ) )
						return false;
					else
					{
						lambda = lambda - VdotW / VdotR;
						//interpolate to next lambda
						//	x = s + lambda * r;
						interpolatedTransA.m_origin.setInterpolate3( ref fromA.m_origin, ref toA.m_origin, lambda );
						interpolatedTransB.m_origin.setInterpolate3( ref fromB.m_origin, ref toB.m_origin, lambda );
						//m_simplexSolver.reset();
						//check next line
						supVertexA.Sub( ref supVertexB, out w );
						//w = supVertexA - supVertexB;

						n = v;

					}
				}
				///Just like regular GJK only add the vertex if it isn't already (close) to current vertex, it would lead to divisions by zero and NaN etc.
				if( !m_simplexSolver.inSimplex( ref w ) )
					m_simplexSolver.addVertex( ref w, ref supVertexA, ref supVertexB );

				if( m_simplexSolver.closest( out v ) )
				{
					dist2 = v.length2();

					//todo: check this normal for validity
					//n=v;
					//Console.WriteLine("V=%f , %f, %f\n",v,v[1],v[2]);
					//Console.WriteLine("DIST2=%f\n",dist2);
					//Console.WriteLine("numverts = %i\n",m_simplexSolver.numVertices());
				}
				else
				{
					dist2 = btScalar.BT_ZERO;
				}
			}

			//int numiter = MAX_ITERATIONS - maxIter;
			//	Console.WriteLine("number of iterations: %d", numiter);

			//don't report a time of impact when moving 'away' from the hitnormal


			result.m_fraction = lambda;
			if( n.length2() >= ( btScalar.SIMD_EPSILON * btScalar.SIMD_EPSILON ) )
				n.normalized( out result.m_normal );
			else
				result.m_normal = btVector3.Zero;

			//don't report time of impact for motion away from the contact normal (or causes minor penetration)
			if( result.m_normal.dot( ref r ) >= -result.m_allowedPenetration )
				return false;

			btVector3 hitA, hitB;
			m_simplexSolver.compute_points( out hitA, out hitB );
			result.m_hitPoint = hitB;
			return true;
		}