# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
Tests for the geometry module.
"""

import numpy as np
from numpy.testing import assert_allclose
import pytest

from ..geometry import EllipseGeometry


@pytest.mark.parametrize('astep, linear_growth', [(0.2, False), (20., True)])
def test_geometry(astep, linear_growth):
    geometry = EllipseGeometry(255., 255., 100., 0.4, np.pi/2, astep,
                               linear_growth)

    sma1, sma2 = geometry.bounding_ellipses()
    assert_allclose((sma1, sma2), (90.0, 110.0), atol=0.01)

    # using an arbitrary angle of 0.5 rad. This is to avoid a polar
    # vector that sits on top of one of the ellipse's axis.
    vertex_x, vertex_y = geometry.initialize_sector_geometry(0.6)
    assert_allclose(geometry.sector_angular_width, 0.0571, atol=0.01)
    assert_allclose(geometry.sector_area, 63.83, atol=0.01)
    assert_allclose(vertex_x, [215.4, 206.6, 213.5, 204.3], atol=0.1)
    assert_allclose(vertex_y, [316.1, 329.7, 312.5, 325.3], atol=0.1)


def test_to_polar():
    # trivial case of a circle centered in (0.,0.)
    geometry = EllipseGeometry(0., 0., 100., 0.0, 0., 0.2, False)

    r, p = geometry.to_polar(100., 0.)
    assert_allclose(r, 100., atol=0.1)
    assert_allclose(p, 0., atol=0.0001)

    r, p = geometry.to_polar(0., 100.)
    assert_allclose(r, 100., atol=0.1)
    assert_allclose(p, np.pi/2., atol=0.0001)

    # vector with length 100. at 45 deg angle
    r, p = geometry.to_polar(70.71, 70.71)
    assert_allclose(r, 100., atol=0.1)
    assert_allclose(p, np.pi/4., atol=0.0001)

    # position angle tilted 45 deg from X axis
    geometry = EllipseGeometry(0., 0., 100., 0.0, np.pi/4., 0.2, False)

    r, p = geometry.to_polar(100., 0.)
    assert_allclose(r, 100., atol=0.1)
    assert_allclose(p, np.pi*7./4., atol=0.0001)

    r, p = geometry.to_polar(0., 100.)
    assert_allclose(r, 100., atol=0.1)
    assert_allclose(p, np.pi/4., atol=0.0001)

    # vector with length 100. at 45 deg angle
    r, p = geometry.to_polar(70.71, 70.71)
    assert_allclose(r, 100., atol=0.1)
    assert_allclose(p, np.pi*2., atol=0.0001)


def test_area():
    # circle with center at origin
    geometry = EllipseGeometry(0., 0., 100., 0.0, 0., 0.2, False)

    # sector at 45 deg on circle
    vertex_x, vertex_y = geometry.initialize_sector_geometry(45./180.*np.pi)
    assert_allclose(vertex_x, [65.21, 79.70, 62.03, 75.81], atol=0.01)
    assert_allclose(vertex_y, [62.03, 75.81, 65.21, 79.70], atol=0.01)

    # sector at 0 deg on circle
    vertex_x, vertex_y = geometry.initialize_sector_geometry(0)
    assert_allclose(vertex_x, [89.97, 109.97, 89.97, 109.96], atol=0.01)
    assert_allclose(vertex_y, [-2.25, -2.75, 2.25, 2.75], atol=0.01)


def test_area2():
    # circle with center at 100.,100.
    geometry = EllipseGeometry(100., 100., 100., 0.0, 0., 0.2, False)

    # sector at 45 deg on circle
    vertex_x, vertex_y = geometry.initialize_sector_geometry(45./180.*np.pi)
    assert_allclose(vertex_x, [165.21, 179.70, 162.03, 175.81], atol=0.01)
    assert_allclose(vertex_y, [162.03, 175.81, 165.21, 179.70], atol=0.01)

    # sector at 225 deg on circle
    vertex_x, vertex_y = geometry.initialize_sector_geometry(225./180.*np.pi)
    assert_allclose(vertex_x, [34.79, 20.30, 37.97, 24.19], atol=0.01)
    assert_allclose(vertex_y, [37.97, 24.19, 34.79, 20.30], atol=0.01)


def test_reset_sma():
    geometry = EllipseGeometry(0., 0., 100., 0.0, 0., 0.2, False)
    sma, step = geometry.reset_sma(0.2)
    assert_allclose(sma, 83.33, atol=0.01)
    assert_allclose(step, -0.1666, atol=0.001)

    geometry = EllipseGeometry(0., 0., 100., 0.0, 0., 20., True)
    sma, step = geometry.reset_sma(20.)
    assert_allclose(sma, 80., atol=0.01)
    assert_allclose(step, -20., atol=0.01)


def test_update_sma():
    geometry = EllipseGeometry(0., 0., 100., 0.0, 0., 0.2, False)
    sma = geometry.update_sma(0.2)
    assert_allclose(sma, 120., atol=0.01)

    geometry = EllipseGeometry(0., 0., 100., 0.0, 0., 20., True)
    sma = geometry.update_sma(20.)
    assert_allclose(sma, 120., atol=0.01)


def test_polar_angle_sector_limits():
    geometry = EllipseGeometry(0., 0., 100., 0.3, np.pi/4, 0.2, False)
    geometry.initialize_sector_geometry(np.pi/3)
    phi1, phi2 = geometry.polar_angle_sector_limits()
    assert_allclose(phi1, 1.022198, atol=0.0001)
    assert_allclose(phi2, 1.072198, atol=0.0001)


def test_bounding_ellipses():
    geometry = EllipseGeometry(0., 0., 100., 0.3, np.pi/4, 0.2, False)
    sma1, sma2 = geometry.bounding_ellipses()
    assert_allclose((sma1, sma2), (90.0, 110.0), atol=0.01)


def test_radius():
    geometry = EllipseGeometry(0., 0., 100., 0.3, np.pi/4, 0.2, False)
    r = geometry.radius(0.0)
    assert_allclose(r, 100.0, atol=0.01)

    r = geometry.radius(np.pi/2)
    assert_allclose(r, 70.0, atol=0.01)
