Exemple #1
0
 def setUp(self):
     self.clean_state()
     self.diameter = 0.1
     self.aperture_origin = Position.from_xyz((10.0, 20.0, 30.0))
     self.aperture_direction = Direction.from_xyz((1.0, 2.0, 3.0))
     self.placement = Ray(self.aperture_origin, self.aperture_direction.normalized())
     self.aperture = Aperture(placement=self.placement, diameter=self.diameter)
     self.initial_wavefront = WaveFront.unit_sphere
     self.orthogonal_directions = [
         self.aperture_direction.cross(Direction.right).normalized(),
         self.aperture_direction.cross(Direction.forward).normalized(),
         self.aperture_direction.cross(Direction.backward).normalized(),
     ]
Exemple #2
0
class TestAperture(unittest.TestCase):
    """
    Test Aperture class
    """

    def clean_state(self):
        self.aperture = None
        self.diameter = None
        self.aperture_origin = None
        self.aperture_direction = None
        self.orthogonal_directions = None
        self.placement = None
        self.ray_location = None
        self.orthogonal_direction = None
        self.scale_factor = None
        self.test_ray_distance = None
        self.test_ray = None
        self.initial_wavefront = None
        self.filtered_wavefront = None

    def setUp(self):
        self.clean_state()
        self.diameter = 0.1
        self.aperture_origin = Position.from_xyz((10.0, 20.0, 30.0))
        self.aperture_direction = Direction.from_xyz((1.0, 2.0, 3.0))
        self.placement = Ray(self.aperture_origin, self.aperture_direction.normalized())
        self.aperture = Aperture(placement=self.placement, diameter=self.diameter)
        self.initial_wavefront = WaveFront.unit_sphere
        self.orthogonal_directions = [
            self.aperture_direction.cross(Direction.right).normalized(),
            self.aperture_direction.cross(Direction.forward).normalized(),
            self.aperture_direction.cross(Direction.backward).normalized(),
        ]

    def tearDown(self):
        self.clean_state()

    def test_aperture_radius(self):
        self.assertAlmostEqual(self.diameter / 2.0, self.aperture.radius)

    def test_aperture_correctly_measures_ray_distances(self):
        self.then_test_with_multiple_location_directions_and_scales()

    def then_test_with_multiple_location_directions_and_scales(self):
        for self.ray_location in [
            Position.from_xyz((44.0, 33.0, 2.0)),
            Position.from_xyz((-9.0, 3.0, -2.0)),
        ]:
            self.then_test_location_with_multiple_direction_and_scales()

    def then_test_location_with_multiple_direction_and_scales(self):
        for self.orthogonal_direction in self.orthogonal_directions:
            self.then_test_location_and_direction_with_multiple_scales()

    def then_test_location_and_direction_with_multiple_scales(self):
        for self.scale_factor in [1.0, 0.1, 0.01, 0.001, 1000.0]:
            self.then_test_location_direction_and_scale()

    def then_test_location_direction_and_scale(self):
        self.when_test_ray_is_constructed()
        self.when_test_ray_distance_is_measured()
        self.then_test_ray_distance_is_correct()

    def when_test_ray_is_constructed(self):
        scaled_normal = self.orthogonal_direction.scale(self.scale_factor)
        ray_endpoint = self.aperture_origin.add(scaled_normal)
        ray_direction = ray_endpoint.difference(self.ray_location).normalized()
        self.test_ray = Ray(self.ray_location, ray_direction)

    def when_test_ray_distance_is_measured(self):
        self.test_ray_distance = self.aperture.distance_to_ray(self.test_ray)

    def then_test_ray_distance_is_correct(self):
        self.assertAlmostEqual(self.scale_factor, self.test_ray_distance)

    def test_volume_calculations(self):
        # Testing the test to be sure expected volume is correct.
        # The correct math using 1-cosine(angle) is inaccurate for small angles.
        # Instead a more complex tangent based formula is used.
        # This test makes sure the more complex formula is still correct.
        self.assertEqual(0.0, self.volume_of_spherical_cone(0.0))
        for angle in [0.1, 0.2, 0.5, 1.0, 0.01]:
            cosine = math.cos(angle)
            tangent = math.tan(angle)
            expected_height_factor = 1.0 - cosine
            actual_height_factor = self.height_factor_of_spherical_cone(tangent)
            self.assertAlmostEqual(expected_height_factor, actual_height_factor)

    def volume_of_spherical_cone(self, tangent):
        height_factor = self.height_factor_of_spherical_cone(tangent)
        volume = height_factor * math.pi * 2.0 / 3.0
        return volume

    def height_factor_of_spherical_cone(self, tangent):
        tangent_squared = tangent * tangent
        secant_squared = 1 + tangent_squared
        secant = math.sqrt(secant_squared)
        alpha_squared = tangent_squared + 2.0 * (1.0 - secant)
        alpha = math.sqrt(alpha_squared)
        height_factor = alpha / secant
        return height_factor

    @unittest.skip("slow test because it does a lot of calculation")
    def test_aperture_filters_wavefront(self):
        self.when_wavefront_is_filtered()
        self.then_filter_wavefront_has_correct_properties()

    def when_wavefront_is_filtered(self):
        self.filtered_wavefront = self.aperture.filter_wavefront(self.initial_wavefront)

    def then_filter_wavefront_has_correct_properties(self):
        distance_to_aperture = vector_norm(self.aperture_origin.xyz)
        tangent = self.aperture.radius / distance_to_aperture
        expected_volume = self.volume_of_spherical_cone(tangent)
        actual_volume = self.filtered_wavefront.volume
        self.assertAlmostEqual(expected_volume, actual_volume, 3)