2019年5月3日金曜日

開発環境

The Ray Tracer Challenge: A Test-Driven Guide to Your First 3D Renderer (Jamis Buck(著)、Pragmatic Bookshelf)を入手した理由、感想、そしてChapter 1(Tuples, Points, and Vectors)を取り組んでみる。

Three.jsをちょっと触ったり初めてのThree.jsを読んだりしてたら、自分自身で3D描画のちょっとしたライブラリーのコードを書いてみたくなったので、適した本を探し始める。そして本著を発見、そして入手。

Three.jsはjsとついてることからも分かるように使用されてるプログラミング言語はJavaScriptだけど、普段Pythonのコードを書くことが多いからPythonの本だといいなぁと思ってところ、本著はプログラミング言語は問わずということでPythonを使えるということも本著を選択した一つの理由。また、Python以外の言語の学習にも使えるかも。

他にもTDD(test-driven development、テスト駆動開発)ということで、今のところはちょっとした3Dグラフィック描画のライブラリを書いてみたいだけだけど、後々、本格的なものにしたいと欲が出てきたときにも対応できそうなのも嬉しいことの一つ。

ということで、早速Chapter 1(Tuples, Points, and Vectors)から始め、ちょっとずつ取り組んでみることに。

Tules、OperationsのNegating Tuplesまで。

コード

Python 3

tuples_test.py

#!/usr/bin/env python3
from unittest import TestCase, main
from tuples import Tuple, Point, Vector


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))


if __name__ == '__main__':
    main()

tuples.py

#!/usr/bin/env python3

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)


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)

入出力結果(cmd(コマンドプロンプト)、Terminal、Bash、Jupyter(IPython))

C:\Users\...>py tuples_test.py
Traceback (most recent call last):
  File "tuples_test.py", line 3, in <module>
    from tuples import Point, Vector
ImportError: cannot import name 'Point' from 'tuples' (...\tuples.py)

C:\Users\...>py tuples_test.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

C:\Users\...>py tuples_test.py
E.
======================================================================
ERROR: test_add (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 29, in test_add
    a1 = Tuple(3, -2, 5, 1)
NameError: name 'Tuple' is not defined

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (errors=1)

C:\Users\...>py tuples_test.py
E.
======================================================================
ERROR: test_add (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 29, in test_add
    a1 = Tuple(3, -2, 5, 1)
NameError: name 'Tuple' is not defined

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (errors=1)

C:\Users\...>py tuples_test.py
F.
======================================================================
FAIL: test_add (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 31, in test_add
    self.assertEqual(a1 + a2, Tuple(1, 1, 6, 1))
AssertionError: <tuples.Tuple object at 0x101973898> != <tuples.Tuple object at 0x1019738d0>

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)
C:\Users\...>py tuples_test.py
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

C:\Users\...>py tuples_test.py
..E
======================================================================
ERROR: test_sub (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 30, in test_sub
    self.assertEqual(p1 - p2, Vector(-2, -4, -6))
TypeError: unsupported operand type(s) for -: 'Point' and 'Point'

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (errors=1)

C:\Users\...>py tuples_test.py
..E
======================================================================
ERROR: test_sub (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 30, in test_sub
    self.assertEqual(p1 - p2, Vector(-2, -4, -6))
  File "...\tuples.py", line 27, in __sub__
    self.z - other.z, self.w - other.w)
TypeError: __init__() takes 4 positional arguments but 5 were given

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (errors=1)

C:\Users\...>py tuples_test.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

C:\Users\...>py tuples_test.py
..F
======================================================================
FAIL: test_sub (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 31, in test_sub
    self.assertEqual(type(p1 - p2), Vector)
AssertionError: <class 'tuples.Point'> != <class 'tuples.Vector'>

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)
C:\Users\...>py tuples_test.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.000s

OK

C:\Users\...>py tuples_test.py
...F
======================================================================
FAIL: test_sub_vector_from_point (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 36, in test_sub_vector_from_point
    self.assertEqual(p - v, Point(-2, -4, -6))
AssertionError: <tuples.Vector object at 0x101583d68> != <tuples.Point object at 0x101583e10>

----------------------------------------------------------------------
Ran 4 tests in 0.001s

FAILED (failures=1)
C:\Users\...>py tuples_test.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

C:\Users\...>py tuples_test.py
....E
======================================================================
ERROR: test_sub_vectors (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 41, in test_sub_vectors
    self.assertEqual(v1 - v2, Vector(-2, -4, -6))
  File "...\tuples.py", line 49, in __sub__
    t = super().__sub__(other)
  File "...\tuples.py", line 27, in __sub__
    self.z - other.z, self.w - other.w)
TypeError: __init__() takes 4 positional arguments but 5 were given

----------------------------------------------------------------------
Ran 5 tests in 0.001s

FAILED (errors=1)

C:\Users\...>py tuples_test.py
.....
----------------------------------------------------------------------
Ran 5 tests in 0.000s

OK

C:\Users\...>py tuples_test.py
......
----------------------------------------------------------------------
Ran 6 tests in 0.000s

OK

C:\Users\...>py tuples_test.py
..E....
======================================================================
ERROR: test_neg (__main__.TupleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tuples_test.py", line 50, in test_neg
    self.assertEqual(-a, Tuple(-1, 2, -3, 4))
TypeError: bad operand type for unary -: 'Tuple'

----------------------------------------------------------------------
Ran 7 tests in 0.001s

FAILED (errors=1)

C:\Users\...>py tuples_test.py
.......
----------------------------------------------------------------------
Ran 7 tests in 0.000s

OK

C:\Users\...>

0 コメント:

コメントを投稿