def test_group_bounding_box_contains_children(self): s = Sphere() s.transform = Transformations.translation(2, 5, -3).dot( Transformations.scaling(2, 2, 2)) c = Cylinder() c.minimum = -2 c.maximum = 2 c.transform = Transformations.translation(-4, -1, 4).dot( Transformations.scaling(0.5, 1, 0.5)) shape = Group() shape.add_child(s) shape.add_child(c) box = shape.bounds_of() self.assertEqual(box.min, Point(-4.5, -3, -5)) self.assertEqual(box.max, Point(4, 7, 4.5))
def test_intersect_scaled_shape_with_ray(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = Shape.test_shape() s.transform = Transformations.scaling(2, 2, 2) xs = s.intersect(r) self.assertEqual(s.saved_ray.origin, Point(0, 0, -2.5)) self.assertEqual(s.saved_ray.direction, Vector(0, 0, 0.5))
def test_chained_transformations(self): p = Point(1, 0, 1) a = Transformations.rotation_x(math.pi / 2) b = Transformations.scaling(5, 5, 5) c = Transformations.translation(10, 5, 7) t = c.dot(b.dot(a)) self.assertEqual(Matrix.multiply_tuple(t, p), Point(15, 0, 7))
def test_findinf_n1_n2_at_various_intersections(self): a = GlassSphere() a.transform = Transformations.scaling(2, 2, 2) a.material.refractive_index = 1.5 b = GlassSphere() b.transform = Transformations.translation(0, 0, -0.25) b.material.refractive_index = 2.0 c = GlassSphere() c.transform = Transformations.translation(0, 0, 0.25) c.material.refractive_index = 2.5 r = Ray(Point(0, 0, -4), Vector(0, 0, 1)) xs = Intersection.intersections(Intersection(2, a), Intersection(2.75, b), Intersection(3.25, c), Intersection(4.75, b), Intersection(5.25, c), Intersection(6, a)) RefractiveIndices = namedtuple("RefractiveIndices", ["n1", "n2"]) refractive_indices_list = [ RefractiveIndices(1.0, 1.5), RefractiveIndices(1.5, 2.0), RefractiveIndices(2.0, 2.5), RefractiveIndices(2.5, 2.5), RefractiveIndices(2.5, 1.5), RefractiveIndices(1.5, 1.0) ] for index, refractive_index in enumerate(refractive_indices_list): comps = Computations.prepare_computations(xs[index], r, xs) print(comps.n1) print(comps.n2) self.assertEqual(comps.n1, refractive_index.n1) self.assertEqual(comps.n2, refractive_index.n2)
def test_pattern_object_and_pattern_transformation(self): shape = Sphere() shape.transform = Transformations.scaling(2, 2, 2) pattern = Pattern.test_pattern() pattern.transform = Transformations.translation(0.5, 1, 1.5) c = pattern.pattern_at_shape(shape, Point(2.5, 3, 3.5)) self.assertEqual(c, Color(0.75, 0.5, 0.25))
def test_intersect_scaled_sphere_with_ray(self): r = Ray(Point(0, 0, -5), Vector(0, 0, 1)) s = Sphere() s.transform = Transformations.scaling(2, 2, 2) xs = s.intersect(r) self.assertEqual(len(xs), 2) self.assertEqual(xs[0].t, 3) self.assertEqual(xs[1].t, 7)
def test_intersecting_transformed_group(self): g = Group() g.transform = Transformations.scaling(2, 2, 2) s = Sphere() s.transform = Transformations.translation(5, 0, 0) g.add_child(s) r = Ray(Point(10, 0, -10), Vector(0, 0, 1)) xs = g.intersect(r) self.assertEqual(len(xs), 2)
def test_finding_normal_on_child_object(self): g1 = Group() g1.transform = Transformations.rotation_y(math.pi / 2) g2 = Group() g2.transform = Transformations.scaling(1, 2, 3) g1.add_child(g2) s = Sphere() s.transform = Transformations.translation(5, 0, 0) g2.add_child(s) n = s.normal_at(Point(1.7321, 1.1547, -5.5774)) self.assertEqual(n, Vector(0.2857, 0.4286, -0.8571))
def test_converting_point_from_world_to_object_space(self): g1 = Group() g1.transform = Transformations.rotation_y(math.pi / 2) g2 = Group() g2.transform = Transformations.scaling(2, 2, 2) g1.add_child(g2) s = Sphere() s.transform = Transformations.translation(5, 0, 0) g2.add_child(s) p = s.world_to_object(Point(-2, 0, -10)) self.assertEqual(p, Point(0, 0, -1))
def test_converting_normal_from_object_to_world_space(self): g1 = Group() g1.transform = Transformations.rotation_y(math.pi / 2) g2 = Group() g2.transform = Transformations.scaling(1, 2, 3) g1.add_child(g2) s = Sphere() s.transform = Transformations.translation(5, 0, 0) g2.add_child(s) n = s.normal_to_world(Vector(math.sqrt(3) /3, math.sqrt(3) / 3, math.sqrt(3) / 3)) self.assertEqual(n, Vector(0.2857, 0.4286, -0.8571))
def test_default_world(self): light = PointLight(Point(-10, 10, -10), Color(1, 1, 1)) s1 = Sphere() s1.material.color = Color(0.8, 1.0, 0.6) s1.material.diffuse = 0.7 s1.material.specular = 0.2 s2 = Sphere() s2.transform = Transformations.scaling(0.5, 0.5, 0.5) w = World.default_world() self.assertEqual(w.light, light) self.assertTrue(s1 in w.objects) self.assertTrue(s2 in w.objects)
def test_individual_transformations(self): p = Point(1, 0, 1) a = Transformations.rotation_x(math.pi / 2) b = Transformations.scaling(5, 5, 5) c = Transformations.translation(10, 5, 7) # rotate first p2 = Matrix.multiply_tuple(a, p) self.assertEqual(p2, Point(1, -1, 0)) # apply scaling p3 = Matrix.multiply_tuple(b, p2) self.assertEqual(p3, Point(5, -5, 0)) # apply translation p4 = Matrix.multiply_tuple(c, p3) self.assertEqual(p4, Point(15, 0, 7))
def test_group_partitions_children(self): s1 = Sphere() s1.transform = Transformations.translation(-2, -2, 0) s2 = Sphere() s2.transform = Transformations.translation(-2, 2, 0) s3 = Sphere() s3.transform = Transformations.scaling(4, 4, 4) g = Group() g.add_child(s1) g.add_child(s2) g.add_child(s3) g.divide(1) self.assertEqual(g.members[0], s3) subgroup = g.members[1] self.assertIsInstance(subgroup, Group) self.assertEqual(len(subgroup.members), 2) self.assertEqual(subgroup.members[0].members, [s1]) self.assertEqual(subgroup.members[1].members, [s2])
class Clock: if __name__ == '__main__': canvas_size = 300 canvas = Canvas(canvas_size, canvas_size) color = Color(1, 1, 1) radius = canvas_size * 3 / 8 scale = Transformations.scaling(radius, radius, 0) origin = Point(0, 0, 0) center_translation = Transformations.translation( canvas_size / 2, canvas_size / 2, 0) center = Matrix.multiply_tuple(center_translation, origin) hour = Point(0, 1, 0) # twelve for _ in range(12): scaled_hour = Matrix.multiply_tuple(scale, hour) positioned_hour = scaled_hour + center canvas.write_pixel(round(positioned_hour.x), round(canvas.height - positioned_hour.y), color) hour_rotation = Transformations.rotation_z(math.pi / 6) hour = Matrix.multiply_tuple(hour_rotation, hour) canvas.canvas_to_ppm()
def test_transformation_matrix_z(self): from_point = Point(0, 0, 0) to = Point(0, 0, 1) up = Vector(0, 1, 0) t = World.view_transform(from_point, to, up) self.assertTrue(np.array_equal(t, Transformations.scaling(-1, 1, -1)))
import math from camera import Camera from color import Color from light import PointLight from material import Material from sphere import Sphere from transformations import Transformations from tuple import Point, Vector from world import World if __name__ == '__main__': # The floor is an extremely flattened sphere with a matte texture floor = Sphere() floor.transform = Transformations.scaling(10, 0.1, 10) floor.material = Material() floor.material.color = Color(1, 0.9, 0.9) floor.material.specular = 0 # The wall on the left has the same scale and color as the floor, but is also rotated and translated into place left_wall = Sphere() left_wall.transform = Transformations.translation(0, 0, 5) left_wall.transform = left_wall.transform.dot( Transformations.rotation_y(-math.pi / 4)) left_wall.transform = left_wall.transform.dot( Transformations.rotation_x(math.pi / 2)) left_wall.transform = left_wall.transform.dot( Transformations.scaling(10, 0.1, 10)) left_wall.material = floor.material # The wall on the right is identical to the left wall, but is rotated the opposite direction in y
def test_normal_transformed_sphere(self): s = Sphere() m = Transformations.scaling(1, 0.5, 1).dot(Transformations.rotation_z(math.pi / 5)) s.transform = m n = s.normal_at(Point(0, math.sqrt(2) / 2, -(math.sqrt(2) / 2))) self.assertEqual(n, Vector(0, 0.97014, -0.24254))
def test_reflection(self): transform = Transformations.scaling(-1, 1, 1) p = Point(2, 3, 4) self.assertEqual(Matrix.multiply_tuple(transform, p), Point(-2, 3, 4))
def test_multiply_inverse_scaling_matrix(self): transform = Transformations.scaling(2, 3, 4) inv = Matrix.inverse(transform) v = Vector(-4, 6, 8) self.assertEqual(Matrix.multiply_tuple(inv, v), Vector(-2, 2, 2))
def test_scaling_matrix_vector(self): transform = Transformations.scaling(2, 3, 4) v = Vector(-4, 6, 8) self.assertEqual(Matrix.multiply_tuple(transform, v), Vector(-8, 18, 32))
def test_scaling_matrix_point(self): transform = Transformations.scaling(2, 3, 4) p = Point(-4, 6, 8) self.assertEqual(Matrix.multiply_tuple(transform, p), Point(-8, 18, 32))
def test_shape_bounding_box_in_parent_space(self): shape = Sphere() shape.transform =Transformations.translation(1, -3, 5).dot(Transformations.scaling(0.5, 2, 4)) box = shape.parent_space_bounds_of() self.assertEqual(box.min, Point(0.5, -5, 1)) self.assertEqual(box.max, Point(1.5, -1, 9))
def test_scale_ray(self): r = Ray(Point(1, 2, 3), Vector(0, 1, 0)) m = Transformations.scaling(2, 3, 4) r2 = Ray.transform(r, m) self.assertEqual(r2.origin, Point(2, 6, 12)) self.assertEqual(r2.direction, Vector(0, 3, 0))
def test_pattern_object_transformation(self): shape = Sphere() shape.transform = Transformations.scaling(2, 2, 2) pattern = Pattern.test_pattern() c = pattern.pattern_at_shape(shape, Point(2, 3, 4)) self.assertEqual(c, Color(1, 1.5, 2))