public static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane)
        {
            // Find the distance from the origin
            float ballDistance = Vector3.Dot(plane.Normal, sphere.Position) - sphere.Radius;

            // Check for the intersection
            return(ballDistance <= plane.D);
        }
        /// <summary>
        /// Detecta la colisión entre caja y plano
        /// </summary>
        /// <param name="box">Caja</param>
        /// <param name="plane">Plano</param>
        /// <param name="data">Datos de la colisión</param>
        /// <returns>Devuelve verdadero si hay colisión, o falso en el resto de los casos</returns>
        public static bool BoxAndHalfSpace(CollisionBox box, CollisionPlane plane, ref CollisionData data)
        {
            if (data.ContactsLeft <= 0)
            {
                // Si no hay más contactos disponibles se sale de la función.
                return(false);
            }

            // Comprobar la intersección
            if (!IntersectionTests.BoxAndHalfSpace(box, plane))
            {
                return(false);
            }

            // Hay intersección, ahora hay que encontrar los puntos de intersección.
            // Podemos hacerlo únicamente chequeando los vértices.
            // Si la caja está descansando sobre el plano o un eje, se reportarán cuatro o dos puntos de contacto.

            uint contactsUsed = 0;

            for (int i = 0; i < 8; i++)
            {
                // Calcular la positición de cada vértice
                Vector3 vertexPos = box.GetCorner(i);

                // Calcular la distancia al plano
                float vertexDistance = Vector3.Dot(vertexPos, plane.Normal);

                // Comparar las distancias
                if (vertexDistance <= plane.D)
                {
                    // Crear la información del contacto.

                    // El punto de contacto está a medio camino entre el vértice y el plano.
                    // Se obtiene multiplicando la dirección por la mitad de la distancia de separación, y añadiendo la posición del vértice.
                    Contact contact = data.CurrentContact;
                    contact.ContactPoint  = vertexPos;
                    contact.ContactNormal = plane.Normal;
                    contact.Penetration   = plane.D - vertexDistance;

                    // Establecer los datos del contacto
                    RigidBody one = box.Body;
                    RigidBody two = null;
                    contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution);

                    // Añadir contacto
                    data.AddContact();

                    contactsUsed++;
                    if (contactsUsed == data.ContactsLeft)
                    {
                        return(true);
                    }
                }
            }

            return(true);
        }
        /// <summary>
        /// Does an intersection test on an arbitrarily aligned box and a
        /// half-space.
        ///
        /// The box is given as a transform matrix, including
        /// position, and a vector of half-sizes for the extend of the
        /// box along each local axis.
        ///
        /// The half-space is given as a direction (i.e. unit) vector and the
        /// offset of the limiting plane from the origin, along the given
        /// direction.
        /// </summary>
        public static bool BoxAndHalfSpace(CollisionBox box, CollisionPlane plane)
        {
            // Work out the projected radius of the box onto the plane direction
            float projectedRadius = TransformToAxis(box, plane.Normal);

            // Work out how far the box is from the origin
            float boxDistance = Vector3.Dot(plane.Normal, box.Position) - projectedRadius;

            // Check for the intersection
            if (boxDistance <= plane.D)
            {
                return(true);
            }

            return(false);
        }
        /// <summary>
        /// Detecta la colisión entre una esfera y un plano
        /// </summary>
        /// <param name="sphere">Esfera</param>
        /// <param name="plane">Plano</param>
        /// <param name="data">Rellena los datos de colisión</param>
        /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns>
        public static bool SphereAndTruePlane(CollisionSphere sphere, CollisionPlane plane, ref CollisionData data)
        {
            if (data.ContactsLeft <= 0)
            {
                // Si no hay más contactos disponibles se sale de la función.
                return(false);
            }

            // Almacenar la posición de la esfera
            Vector3 position = sphere.Position;

            // Encontrar la distancia al plano
            float centreDistance = Vector3.Dot(plane.Normal, position) - plane.D;

            if (centreDistance * centreDistance > sphere.Radius * sphere.Radius)
            {
                return(false);
            }

            // Chequear la cara del plano en la que estamos para calcular normal y penetración
            Vector3 normal      = plane.Normal;
            float   penetration = -centreDistance;

            if (centreDistance < 0)
            {
                normal     *= -1;
                penetration = -penetration;
            }
            penetration += sphere.Radius;

            // Crear el contacto. Tiene una normal en la dirección del plano.
            Contact contact = data.CurrentContact;

            contact.ContactNormal = normal;
            contact.Penetration   = penetration;
            contact.ContactPoint  = position - plane.Normal * centreDistance;

            RigidBody two = null;

            contact.SetBodyData(ref sphere.Body, ref two, data.Friction, data.Restitution);

            data.AddContact();

            return(true);
        }
        /// <summary>
        /// Detecta la colisión entre una esfera y un plano
        /// </summary>
        /// <param name="sphere">Esfera</param>
        /// <param name="plane">Plano</param>
        /// <param name="data">Rellena los datos de colisión</param>
        /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns>
        private static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane, ref CollisionData data)
        {
            if (data.ContactsLeft <= 0)
            {
                // Si no hay más contactos disponibles se sale de la función.
                return(false);
            }

            // Distancia del centro al plano
            float centerToPlane = Math.Abs(Vector3.Dot(plane.Normal, sphere.Position) + plane.D);

            // Obtener la penetración de la esfera en el plano.
            float penetration = centerToPlane - sphere.Radius;

            if (penetration >= 0)
            {
                return(false);
            }

            // Crear el contacto. Tiene una normal en la dirección del plano.
            Contact contact = data.CurrentContact;

            contact.ContactNormal = plane.Normal;
            contact.Penetration   = -penetration;
            contact.ContactPoint  = sphere.Position - plane.Normal * centerToPlane;

            // No hay cuerpo para el plano. Se considera escenario.
            RigidBody one = sphere;
            RigidBody two = null;

            contact.SetBodyData(ref one, ref two, data.Friction, data.Restitution);

            // Añadir el contacto
            data.AddContact();

            return(true);
        }
        /// <summary>
        /// Detecta la colisión entre una esfera y un plano
        /// </summary>
        /// <param name="sphere">Esfera</param>
        /// <param name="plane">Plano</param>
        /// <param name="data">Rellena los datos de colisión</param>
        /// <returns>Devuelve verdadero si hay colisión o falso en el resto de los casos</returns>
        public static bool SphereAndHalfSpace(CollisionSphere sphere, CollisionPlane plane, ref CollisionData data)
        {
            if (data.ContactsLeft <= 0)
            {
                // Si no hay más contactos disponibles se sale de la función.
                return(false);
            }

            // Almacenar la posición de la esfera
            Vector3 position = sphere.Position;

            // Obtener la distancia al plano.
            float ballDistance = Vector3.Dot(plane.Normal, position) - sphere.Radius - plane.D;

            if (ballDistance >= 0)
            {
                return(false);
            }

            // Crear el contacto. Tiene una normal en la dirección del plano.
            Contact contact = data.CurrentContact;

            contact.ContactNormal = plane.Normal;
            contact.Penetration   = -ballDistance;
            contact.ContactPoint  = position - plane.Normal * (ballDistance + sphere.Radius);

            // No hay cuerpo para el plano. Se considera escenario.
            RigidBody two = null;

            contact.SetBodyData(ref sphere.Body, ref two, data.Friction, data.Restitution);

            // Añadir el contacto
            data.AddContact();

            return(true);
        }
 /// <summary>
 /// Detecta la intersección entre una esfera y un plano
 /// </summary>
 /// <param name="sphere">Esfera</param>
 /// <param name="plane">Plano</param>
 /// <returns>Devuelve verdadero si hay intersección</returns>
 public static bool SphereAndPlane(CollisionSphere sphere, CollisionPlane plane)
 {
     return(SphereAndPlane(sphere, plane.Normal, plane.D) == 0);
 }
 /// <summary>
 /// Detecta la intersección entre una caja y un plano
 /// </summary>
 /// <param name="box">Caja</param>
 /// <param name="plane">Plano</param>
 /// <returns>Devuelve verdadero si hay intersección</returns>
 public static bool BoxAndPlane(CollisionBox box, CollisionPlane plane)
 {
     return(BoxAndPlane(box, plane.Normal, plane.D));
 }