開発環境
- macOS Mojave - Apple (OS)
- Emacs (Text Editor)
- Windows 10 Pro (OS)
- Visual Studio Code (Text Editor)
- Python 3.7 (プログラミング言語)
The Ray Tracer Challenge: A Test-Driven Guide to Your First 3D Renderer (Jamis Buck(著)、Pragmatic Bookshelf)、Chapter 1(Tuples, Points, and Vectors)のOperations、Scalar Multiplication and Division、Magnitude、Normalization、Dot Product、Cross Productを取り組んでみる。
コード
Python 3
tuples_test.py
#!/usr/bin/env python3 from unittest import TestCase, main from tuples import Tuple, Point, Vector import math class TupleTest(TestCase): def setUp(self): pass def tearDown(self): pass def test_is_point(self): a = Point(4.3, -4.2, 3.1) self.assertEqual(a.x, 4.3, ) self.assertEqual(a.y, -4.2) self.assertEqual(a.z, 3.1) self.assertEqual(a.w, 1.0) self.assertEqual(type(a), Point) self.assertNotEqual(type(a), Vector) def test_add(self): a1 = Tuple(3, -2, 5, 1) a2 = Tuple(-2, 3, 1, 0) self.assertEqual(a1 + a2, Tuple(1, 1, 6, 1)) def test_sub(self): p1 = Point(3, 2, 1) p2 = Point(5, 6, 7) self.assertEqual(p1 - p2, Vector(-2, -4, -6)) self.assertEqual(type(p1 - p2), Vector) def test_sub_vector_from_point(self): p = Point(3, 2, 1) v = Vector(5, 6, 7) self.assertEqual(p - v, Point(-2, -4, -6)) def test_sub_vector(self): v1 = Vector(3, 2, 1) v2 = Vector(5, 6, 7) self.assertEqual(v1 - v2, Vector(-2, -4, -6)) def test_sub_vect_from_zero_vect(self): zero = Vector(0, 0, 0) v = Vector(1, -2, 3) self.assertEqual(zero - v, Vector(-1, 2, -3)) def test_neg(self): a = Tuple(1, -2, 3, -4) self.assertEqual(-a, Tuple(-1, 2, -3, 4)) def test_scalar_mul(self): a = Tuple(1, -2, 3, -4) self.assertEqual(a * 3.5, Tuple(3.5, -7, 10.5, -14)) self.assertEqual(a * 0.5, Tuple(0.5, -1, 1.5, -2)) def test_div(self): a = Tuple(1, -2, 3, -4) self.assertEqual(a / 2, Tuple(0.5, -1, 1.5, -2)) def test_mag_vector(self): vectors = [Vector(1, 0, 0), Vector(0, 1, 0), Vector(0, 0, 1), Vector(1, 2, 3), Vector(-1, -2, -3)] mags = [1, 1, 1, math.sqrt(14), math.sqrt(14)] for vector, mag in zip(vectors, mags): self.assertEqual(vector.magnitude(), mag) def test_normalizing_vector(self): v = Vector(4, 0, 0) self.assertEqual(v.normalize(), Vector(1, 0, 0)) v = Vector(1, 2, 3) self.assertEqual(v.normalize(), Vector(1 / math.sqrt(14), 2 / math.sqrt(14), 3 / math.sqrt(14))) norm = v.normalize() self.assertEqual(norm.magnitude(), 1) def test_dot_product(self): a = Vector(1, 2, 3) b = Vector(2, 3, 4) self.assertEqual(a.dot(b), 20) def test_cross_product(self): a = Vector(1, 2, 3) b = Vector(2, 3, 4) self.assertEqual(a.cross(b), Vector(-1, 2, - 1)) self.assertEqual(b.cross(a), Vector(1, -2, 1)) if __name__ == '__main__': main()
tuples.py
#!/usr/bin/env python3 import math EPSILON = 0.00001 def is_equal(a: float, b: float): return abs(a - b) < EPSILON class Tuple: def __init__(self, x: float, y: float, z: float, w: float): self.x = x self.y = y self.z = z self.w = w def __eq__(self, other): return is_equal(self.x, other.x) and is_equal(self.y, other.y) and \ is_equal(self.z, other.z) and is_equal(self.w, other.w) def __add__(self, other): return self.__class__(self.x + other.x, self.y + other.y, self.z + other.z, self.w + other.w) def __sub__(self, other): return self.__class__(self.x - other.x, self.y - other.y, self.z - other.z, self.w - other.w) def __neg__(self): return self.__class__(-self.x, -self.y, -self.z, -self.w) def __mul__(self, other): return self.__class__(self.x * other, self.y * other, self.z * other, self.w * other) def __truediv__(self, other): return self * (1 / other) def magnitude(self): return math.sqrt(self.x ** 2 + self.y ** 2 + self.z ** 2 + self.w ** 2) def normalize(self): mag = self.magnitude() return self.__class__(self.x, self.y, self.z, self.w) / mag def dot(self, other): return sum([a * b for a, b in zip([self.x, self.y, self.z], [other.x, other.y, other.z])]) class Point(Tuple): def __init__(self, x: float, y: float, z: float, w: float = 1): super().__init__(x, y, z, w) def __sub__(self, other): t = super().__sub__(other) if type(other) == Point: return Vector(t.x, t.y, t.z) elif type(other) == Vector: return Point(t.x, t.y, t.z) raise TypeError( "unsupported operand type(s) for -: " f"'{type(self)}' and '{type(other)}'") class Vector(Tuple): def __init__(self, x: float, y: float, z: float, w: float = 0): super().__init__(x, y, z, w) def __sub__(self, other): t = super().__sub__(other) return Vector(t.x, t.y, t.z) def cross(self, other): return Vector(self.y * other.z - self.z * other.y, self.z * other.x - self.x * other.z, self.x * other.y - self.y * other.x)
入出力結果(cmd(コマンドプロンプト)、Terminal、Bash, Jupyter(IPython))
C:\Users\...>py tuples_test.py ............. ---------------------------------------------------------------------- Ran 13 tests in 0.001s OK C:\Users\...>py tuples_test.py -v test_add (__main__.TupleTest) ... ok test_cross_product (__main__.TupleTest) ... ok test_div (__main__.TupleTest) ... ok test_dot_product (__main__.TupleTest) ... ok test_is_point (__main__.TupleTest) ... ok test_mag_vector (__main__.TupleTest) ... ok test_neg (__main__.TupleTest) ... ok test_normalizing_vector (__main__.TupleTest) ... ok test_scalar_mul (__main__.TupleTest) ... ok test_sub (__main__.TupleTest) ... ok test_sub_vect_from_zero_vect (__main__.TupleTest) ... ok test_sub_vector (__main__.TupleTest) ... ok test_sub_vector_from_point (__main__.TupleTest) ... ok ---------------------------------------------------------------------- Ran 13 tests in 0.001s OK C:\Users\...>
0 コメント:
コメントを投稿