## 2019年9月11日水曜日

### Python - Triangles - Wavefront OBJFiles - OBJ File with Polygon Data - Triangulating polygons

The Ray Tracer Challenge: A Test-Driven Guide to Your First 3D Renderer (Jamis Buck(著)、Pragmatic Bookshelf)、Chapter 15(Triangles)のWavefront OBJFiles、Test #11: OBJ File with Polygon Dataを取り組んでみる。

コード

obj_file_test.py

```#!/usr/bin/env python3
from unittest import TestCase, main
from obj_file import Parser
import io
from tuples import Point

class ParserTest(TestCase):
def setUp(self):
pass

def tearDown(self):
pass

def test_ingoring_unrecognized_lines(self):
gibberish = io.StringIO('''There was a young lady named Bright
who traveled much faster than light.
She set out one day
in a relative way,
and came back the previous night.
''')
parser = Parser(gibberish)
self.assertEqual(parser.ignored_lines, 5)

def test_vertex_records(self):
f = io.StringIO('''v -1 1 0
v -1.0000 0.5000 0.0000
v 1 0 0
v 1 1 0
''')
parser = Parser(f)
self.assertEqual(parser.vertices[1], Point(-1, 1, 0))
self.assertEqual(parser.vertices[2], Point(-1, 0.5, 0))
self.assertEqual(parser.vertices[3], Point(1, 0, 0))
self.assertEqual(parser.vertices[4], Point(1, 1, 0))

def test_parsing_triangle_faces(self):
f = io.StringIO('''v -1 1 0
v -1 0 0
v 1 0 0
v 1 1 0

f 1 2 3
f 1 3 4
''')
parser = Parser(f)
group = parser.default_group
t1 = group[0]
t2 = group[1]
spam = [t1.point1, t1.point2, t1.point3,
t2.point1, t2.point2, t2.point3]
egg = [parser.vertices[1],
parser.vertices[2],
parser.vertices[3],
parser.vertices[1],
parser.vertices[3],
parser.vertices[4]]
for s, t in zip(spam, egg):
self.assertEqual(s, t)

def test_triangulating_polygons(self):
f = io.StringIO('''v -1 1 0
v -1 0 0
v 1 0 0
v 1 1 0
v 0 2 0

f 1 2 3 4 5
''')
parser = Parser(f)
group = parser.default_group
t1 = group[0]
t2 = group[1]
t3 = group[2]
spam = [t1.point1, t1.point2, t1.point3,
t2.point1, t2.point2, t2.point3,
t3.point1, t3.point2, t3.point3]
egg = [parser.vertices[1], parser.vertices[2], parser.vertices[3],
parser.vertices[1], parser.vertices[3], parser.vertices[4],
parser.vertices[1], parser.vertices[4], parser.vertices[5]]
for s, t in zip(spam, egg):
self.assertEqual(s, t)

if __name__ == '__main__':
main()
```

obj_file.py

```from tuples import Point
from triangles import Triangle

class Parser:
def __init__(self, fh):
self.ignored_lines = 0
self.vertices = [None]
self.faces = []
for line in fh:
cols = line.split()
if len(cols) < 4 or cols[0] not in ['v', 'f']:
self.ignored_lines += 1
continue
if cols[0] == 'v':
try:
point = Point(*[float(col) for col in cols[1:]])
except ValueError as err:
self.ignored_lines += 1
else:
self.vertices.append(point)
elif cols[0] == 'f':
try:
face = [int(col) for col in cols[1:]]
except ValueError as err:
self.ignored_lines += 1
else:
self.faces.append(face)
self.default_group = []
for face in self.faces:
if len(face) == 3:
self.default_group.append(
Triangle(*[self.vertices[i] for i in face]))
if len(face) == 5:
for i, _ in enumerate(self.vertices[2:-1], 2):
self.default_group.append(
Triangle(self.vertices[1],
self.vertices[i],
self.vertices[i + 1]))
```

```C:\Users\...>py obj_file_test.py
....
----------------------------------------------------------------------
Ran 4 tests in 0.001s

OK

C:\Users\...>
```