#include <iostream>
#include <cmath>
#include <climits>
using namespace std;

double ComputePanelWidth2(double fovDegrees, double d, double r) {
	double fovRadians = fovDegrees * M_PI / 180.0;
	if (r == 0)
    {
        // Ensure width is non-negative
        return 2.0f * d * std::tan(fovRadians / 2.0f);
    }
    
    float fovDistance = std::cos(fovRadians / 2.0f) * (d - r) + std::sqrt(r * r - std::pow((d - r) * std::sin(fovRadians / 2.0f), 2));
    return 2.0f * fovDistance * std::sin(fovRadians / 2.0f);
}

double ComputePanelWidth(double fovDegrees, double d, double r) {
    //double fovRadians = fovDegrees * M_PI / 180.0;
    //return std::sin(fovRadians) * (d - r) + std::sqrt(r * r - std::pow((d - r) * std::cos(fovRadians), 2));
    float targetWidth;
    float fovRad = fovDegrees * M_PI / 180.0;
    float fovHalfRad = fovRad / 2.0f;
    
    if (r == 0)
    {
        targetWidth = 2.0f * d * std::tan(fovRad / 2.0f);
        // Ensure width is non-negative
        return std::max(0.0f, targetWidth);
    }
    

    // Precompute sin and cos of half FOV
    float sinFovHalf = std::sin(fovHalfRad);
    float cosFovHalf = std::cos(fovHalfRad);

    // Calculate y_c = d - r (as per formula derivation)
    float yc = d - r;

    // Calculate term inside the square root: r² - y_c² * sin²(FOV/2)
    float termInsideSqrt = (r * r) - (yc * yc * sinFovHalf * sinFovHalf);

    // Check condition: term inside sqrt must be non-negative
    if (termInsideSqrt >= 0)
    {
        // Calculate generalized t = cos(FOV/2)*y_c + sqrt( r² - y_c² * sin²(FOV/2) )
        float t_generalized = cosFovHalf * yc + std::sqrt(termInsideSqrt);

        // Check condition: t (distance to intersection) must be positive
        if (t_generalized > 0)
        {
            // Calculate Panel Width = 2 * t * sin(FOV/2)
            targetWidth = 2.0f * t_generalized * sinFovHalf;
        }
        else
        {
            // Intersection occurs behind the viewer or at the origin, width is effectively zero
            targetWidth = 0.0f;
        }
    }
    return targetWidth;
}

int main() {
	// your code goes here
	double fov = 60.0;   // degrees
    double d = 1.8;
    double r = 0;

    for (double nfov = 50; nfov <=68; nfov++)
    {
    	std::cout << "Panel width fov: " << nfov << " " << ComputePanelWidth(nfov, d, r) << " " << ComputePanelWidth2(nfov, d, r) << std::endl;
    }
	return 0;
}