/// <summary>
        /// Gets the time of impact between two moving objects.
        /// </summary>
        /// <param name="objectA">The object A.</param>
        /// <param name="targetPoseA">The target pose of A.</param>
        /// <param name="objectB">The object B.</param>
        /// <param name="targetPoseB">The target pose of B.</param>
        /// <param name="allowedPenetration">
        /// The allowed penetration. A positive allowed penetration value makes sure that the objects
        /// have a measurable contact at the time of impact.
        /// </param>
        /// <returns>The time of impact in the range [0, 1].</returns>
        /// <remarks>
        /// <para>
        /// Both objects are moved from their current pose (time = 0) to the given target pose (time =
        /// 1). If they collide during this movement the first time of impact is returned. A time of
        /// impact of 1 can mean that the objects do not collide or they collide at their target
        /// positions.
        /// </para>
        /// <para>
        /// The result is undefined if the objects are already in contact at their start poses.
        /// </para>
        /// <para>
        /// <strong>Notes to Inheritors:</strong> The base implementation already computes the time of
        /// impact for convex shapes. For other shapes it returns 1. Optimized versions should be
        /// implemented in derived classes.
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="objectA"/> or <paramref name="objectB"/> is <see langword="null"/>.
        /// </exception>
        public virtual float GetTimeOfImpact(CollisionObject objectA, Pose targetPoseA, CollisionObject objectB, Pose targetPoseB, float allowedPenetration)
        {
            if (objectA == null)
            {
                throw new ArgumentNullException("objectA");
            }
            if (objectB == null)
            {
                throw new ArgumentNullException("objectB");
            }

            // Handle convex shapes here, because this is so common.
            if (objectA.GeometricObject.Shape is ConvexShape && objectB.GeometricObject.Shape is ConvexShape)
            {
                switch (CollisionDetection.ContinuousCollisionDetectionMode)
                {
                case ContinuousCollisionDetectionMode.Full:
                    return(CcdHelper.GetTimeOfImpactCA(objectA, targetPoseA, objectB, targetPoseB, allowedPenetration, CollisionDetection));

                default:
                    return(CcdHelper.GetTimeOfImpactLinearSweep(objectA, targetPoseA, objectB, targetPoseB, allowedPenetration));
                }
            }

            return(1);
        }
        /// <inheritdoc/>
        public override float GetTimeOfImpact(CollisionObject objectA, Pose targetPoseA, CollisionObject objectB, Pose targetPoseB, float allowedPenetration)
        {
            // We can use conservative advancement because a plane is convex enough so it will work.
            switch (CollisionDetection.ContinuousCollisionDetectionMode)
            {
            case ContinuousCollisionDetectionMode.Full:
                return(CcdHelper.GetTimeOfImpactCA(objectA, targetPoseA, objectB, targetPoseB, allowedPenetration, CollisionDetection));

            default:
                return(CcdHelper.GetTimeOfImpactLinearCA(objectA, targetPoseA, objectB, targetPoseB, allowedPenetration, CollisionDetection));
            }
        }