def test_orthogonal_camera(self): cam = OrthogonalCamera(aspect_ratio=2.0) # Fire one ray for each corner of the image plane ray1 = cam.fire_ray(0.0, 0.0) ray2 = cam.fire_ray(1.0, 0.0) ray3 = cam.fire_ray(0.0, 1.0) ray4 = cam.fire_ray(1.0, 1.0) # Verify that the rays are parallel by verifying that cross-products vanish assert are_close(0.0, ray1.dir.cross(ray2.dir).squared_norm()) assert are_close(0.0, ray1.dir.cross(ray3.dir).squared_norm()) assert are_close(0.0, ray1.dir.cross(ray4.dir).squared_norm()) # Verify that the ray hitting the corners have the right coordinates assert ray1.at(1.0).is_close(Point(0.0, 2.0, -1.0)) assert ray2.at(1.0).is_close(Point(0.0, -2.0, -1.0)) assert ray3.at(1.0).is_close(Point(0.0, 2.0, 1.0)) assert ray4.at(1.0).is_close(Point(0.0, -2.0, 1.0))
def is_close(self, other, epsilon=1e-6): """Return True if the three RGB components of two colors are close by less than `epsilon`""" return (are_close(self.r, other.r, epsilon=epsilon) and are_close(self.g, other.g, epsilon=epsilon) and are_close(self.b, other.b, epsilon=epsilon))
def _are_xyz_close(a, b, epsilon=1e-5): # This works thanks to Python's duck typing. In C++ and other languages # you should probably rely on function templates or something like return (are_close(a.x, b.x, epsilon=epsilon) and are_close(a.y, b.y, epsilon=epsilon) and are_close(a.z, b.z, epsilon=epsilon))