#include "Sphere.h"
#include "Ray.h"
bool Sphere::intersect(
    const Ray & ray, const double min_t, double & t, Eigen::Vector3d & n) const
{
    /**
     * Based on
     * Fundamentals in Computer Graphics - Fourth Edition, Chapter 4.4.1. Ray-Sphere Intersection.
     * Steve Marschner & Peter Shirley
     */

    /* Intersection points occur when points on the ray satisfy the implicit equation. */

    double a = ray.direction.dot(ray.direction);
    double b = ray.direction.dot(ray.origin - center);
    double c = (ray.origin - center).dot(ray.origin - center) - radius * radius;
    double discriminant = (2 * b) * (2 * b) - 4 * a * c;

    /* If the discriminant is less than zero, the ray does not intersect with the sphere. */
    if (discriminant < 0) return false;

    /* Calculate the first intersection t. */
    double under_root = b * b - a * c;
    double ta = (0 - b - sqrt(under_root)) / a;
    double tb = (0 - b + sqrt(under_root)) / a;
    /* Choose the smallest that is still larger than min_t. */
    if (ta < min_t && tb < min_t) {
        return false;
    } else if (ta < min_t) {
        t = tb;
    } else if (tb < min_t) {
        t = ta;
    } else {
        t = std::min(ta, tb);
    }

    /* Calculate the surface normal vector at the point of intersection. */
    n = 2 * (ray.origin + t * ray.direction - center);
    /* Normalize the vector. */
    n = n.normalized();

    return true;
}
