def setUp(self): self.clean_state() self.vector = (2.0, 3.0, 4.0) vector_length = vector_norm(self.vector) self.unit_vector = tuple(component / vector_length for component in self.vector) self.position = Position.from_xyz((10.0, 20.0, 30.0)) self.direction = Direction.from_xyz(self.vector) self.unit_direction = Direction.from_xyz(self.unit_vector) self.ray = Ray(self.position, self.direction) self.unit_ray = Ray(self.position, self.unit_direction) self.other_position = Position.from_xyz((-9.0, -88.0, 12.34)) self.other_direction = Direction.from_xyz((19.0, 8.0, -0.03)) self.other_ray = Ray(self.other_position, self.other_direction) offset = self.position.dot(self.unit_direction) plane_projector = (-offset,) + self.unit_vector self.plane = Plane(plane_projector) self.orthogonal_directions = [ Direction.from_xyz((0.2, 0.2, -0.25)), Direction.from_xyz((-7.0, 2.0, 2.0)) ] self.orthogonal_rays = [Ray(self.position, direction) for direction in self.orthogonal_directions]
def when_sphere_intersects_ray_through_interior_point(self): self.test_ray = Ray.from_origin_endpoint(self.starting_point, self.interior_point)
class TestPlane(unittest.TestCase): def clean_state(self): self.vector = None self.unit_vector = None self.position = None self.direction = None self.unit_direction = None self.ray = None self.plane = None self.orthogonal_directions = None self.orthogonal_rays = None self.other_position = None self.other_direction = None self.other_ray = None self.intersect_point = None def setUp(self): self.clean_state() self.vector = (2.0, 3.0, 4.0) vector_length = vector_norm(self.vector) self.unit_vector = tuple(component / vector_length for component in self.vector) self.position = Position.from_xyz((10.0, 20.0, 30.0)) self.direction = Direction.from_xyz(self.vector) self.unit_direction = Direction.from_xyz(self.unit_vector) self.ray = Ray(self.position, self.direction) self.unit_ray = Ray(self.position, self.unit_direction) self.other_position = Position.from_xyz((-9.0, -88.0, 12.34)) self.other_direction = Direction.from_xyz((19.0, 8.0, -0.03)) self.other_ray = Ray(self.other_position, self.other_direction) offset = self.position.dot(self.unit_direction) plane_projector = (-offset,) + self.unit_vector self.plane = Plane(plane_projector) self.orthogonal_directions = [ Direction.from_xyz((0.2, 0.2, -0.25)), Direction.from_xyz((-7.0, 2.0, 2.0)) ] self.orthogonal_rays = [Ray(self.position, direction) for direction in self.orthogonal_directions] def tearDown(self): self.clean_state() def test_plane_contains_position(self): point = self.position distance_from_plane = self.plane.distance_to_point(point) self.assertAlmostEqual(0.0, distance_from_plane) def test_plane_contains_orthogonal_rays(self): self.then_plane_contains_orthogonal_rays() def then_plane_contains_orthogonal_rays(self): for orthogonal_ray in self.orthogonal_rays: for scale in [-2.0, -1.0, 0.0, 0.4, 1.0]: point = orthogonal_ray.scaled_endpoint(scale) distance_from_plane = self.plane.distance_to_point(point) self.assertAlmostEqual(0.0, distance_from_plane) # this really is testing Ray.distance_to_point length_of_orthogonal_ray = orthogonal_ray.direction.length() expected_distance_from_ray = fabs(scale) * length_of_orthogonal_ray actual_distance_from_ray = self.ray.distance_to_point(point) self.assertAlmostEqual(expected_distance_from_ray, actual_distance_from_ray) def test_plane_distance(self): self.then_plane_has_correct_distances() def then_plane_has_correct_distances(self): ray_length = vector_norm(self.unit_direction) self.assertEqual(1.0, ray_length) ray = self.unit_ray for scale in [-2.0, -1.0, 0.0, 0.4, 1.0]: point = ray.scaled_endpoint(scale) distance_from_plane = self.plane.distance_to_point(point) self.assertAlmostEqual(scale, distance_from_plane) def test_plane_construction_from_ray(self): self.when_plane_constructed_from_ray() self.then_plane_contains_orthogonal_rays() self.then_plane_has_correct_distances() def when_plane_constructed_from_ray(self): self.plane = Plane.orthogonal_to_ray(self.ray) def test_plane_intersects_ray(self): self.when_plane_constructed_from_ray() self.when_plane_intersects_other_ray() self.then_intersection_point_lies_on_plane() self.then_point_lies_on_othe_ray() def when_plane_intersects_other_ray(self): self.intersect_point = self.plane.intersect(self.other_ray) def then_intersection_point_lies_on_plane(self): self.assertAlmostEqual(0.0, self.plane.distance_to_point(self.intersect_point), 5) def then_point_lies_on_othe_ray(self): self.assertLess(0.0, self.other_ray.distance_to_point(self.intersect_point), 5)
def test_ray_has_cardinal_rays(self): for direction_name in ['up', 'down', 'left', 'right', 'forward', 'backward', 'unknown']: target = Ray.get_named_cardinal_ray(direction_name) expected_direction = Direction.get_named_cardinal_direction(direction_name) self.assertEqual(expected_direction.xyz, target.direction.xyz) self.assertEqual(Position.origin.xyz, target.position.xyz)
def when_ray_created_from_origin_endpoint(self): self.ray = Ray.from_origin_endpoint(self.expected_position, Position.from_xyz(self.endpoint_xyz))
def when_ray_created(self): self.ray = Ray(self.expected_position, self.expected_direction)
class TestRay(unittest.TestCase): """ Test Ray Class """ def clean_state(self): self.expected_position = None self.expected_direction = None self.endpoint_xyz = None self.ten_scale_endpoint_xyz = None self.ray = None def setUp(self): self.clean_state() self.expected_position = Position.from_xyz((10.0, 20.0, 30.0)) self.expected_direction = Direction.from_xyz((0.5, 0.4, 0.3)) self.endpoint_xyz = (10.5, 20.4, 30.3) self.ten_scale_endpoint_xyz = (15.0, 24.0, 33.0) def tearDown(self): self.clean_state() def test_ray_normal_construction(self): self.when_ray_created() self.then_ray_has_normal_values() def when_ray_created(self): self.ray = Ray(self.expected_position, self.expected_direction) def then_ray_has_normal_values(self): self.then_ray_has_expected_position() self.then_ray_has_expected_direction() def then_ray_has_expected_position(self): self.assertAlmostEqual(self.expected_position.w, self.ray.position.w) self.assertAlmostEqual(self.expected_position.x, self.ray.position.x) self.assertAlmostEqual(self.expected_position.y, self.ray.position.y) self.assertAlmostEqual(self.expected_position.z, self.ray.position.z) def then_ray_has_expected_direction(self): self.assertAlmostEqual(self.expected_direction.w, self.ray.direction.w) self.assertAlmostEqual(self.expected_direction.x, self.ray.direction.x) self.assertAlmostEqual(self.expected_direction.y, self.ray.direction.y) self.assertAlmostEqual(self.expected_direction.z, self.ray.direction.z) def test_ray_construction_requires_valid_position(self): with self.assertRaises(TypeError): Ray("wrong stuff", self.expected_direction) def test_ray_construction_requires_valid_direction(self): with self.assertRaises(TypeError): Ray(self.expected_position, "wrong stuff") def test_ray_construction_refuses_swapped_arguments(self): with self.assertRaises(TypeError): Ray(self.expected_direction, self.expected_position) def test_ray_from_origin_endpoint(self): self.when_ray_created_from_origin_endpoint() self.then_ray_has_normal_values() def when_ray_created_from_origin_endpoint(self): self.ray = Ray.from_origin_endpoint(self.expected_position, Position.from_xyz(self.endpoint_xyz)) def test_ray_wont_mutate(self): self.when_ray_created() with self.assertRaises(AttributeError): self.ray.position = Position((1.0, 2.0, 3.0, 4.0)) with self.assertRaises(AttributeError): self.ray.direction = Direction((0.0, 2.0, 3.0, 4.0)) def test_ray_has_cardinal_rays(self): for direction_name in ['up', 'down', 'left', 'right', 'forward', 'backward', 'unknown']: target = Ray.get_named_cardinal_ray(direction_name) expected_direction = Direction.get_named_cardinal_direction(direction_name) self.assertEqual(expected_direction.xyz, target.direction.xyz) self.assertEqual(Position.origin.xyz, target.position.xyz) def test_ray_endpoint(self): self.when_ray_created() endpoint = self.ray.endpoint; self.assertTrue(endpoint.is_position) self.assertEqual(self.endpoint_xyz, endpoint.xyz) def test_ray_scaled_endpoint(self): self.when_ray_created() endpoint = self.ray.scaled_endpoint(10.0); self.assertTrue(endpoint.is_position) self.assertEqual(self.ten_scale_endpoint_xyz, endpoint.xyz) self.assertLess(self.ray.distance_to_point(endpoint), 0.000001) def test_distance_to_ray(self): for ray in [Ray.up, Ray.down]: scaled_ray = ray.scaled_direction(10.0) for orthogonal_ray in [Ray.right, Ray.left, Ray.forward, Ray.backward]: scale_factor = 4.0 scaled_orthogonal_ray = orthogonal_ray.scaled_direction(scale_factor) endpoint = scaled_orthogonal_ray.endpoint expected_distance = scale_factor actual_distance = ray.distance_to_point(endpoint) self.assertAlmostEqual(expected_distance, actual_distance) def test_ray_additon(self): self.when_ray_created() self.when_direction_added_to_ray() self.then_ray_has_translated_values() def when_direction_added_to_ray(self): self.ray = self.ray.add(Direction.from_xyz((100, 200, 300))) def then_ray_has_translated_values(self): self.then_ray_has_translated_position() self.then_ray_has_expected_direction() def then_ray_has_translated_position(self): self.assertTupleEqual((110, 220, 330), self.ray.position.xyz)