Browse Source

added class Triangle; Surface: replaced attribute `triangles{_vertex_indices->}`

Fabian Peter Hammerle 5 years ago
parent
commit
bda380c591
3 changed files with 58 additions and 13 deletions
  1. 32 8
      freesurfer_surface/__init__.py
  2. 5 5
      tests/test_surface.py
  3. 21 0
      tests/test_triangle.py

+ 32 - 8
freesurfer_surface/__init__.py

@@ -63,6 +63,30 @@ def setlocale(temporary_locale):
 Vertex = collections.namedtuple('Vertex', ['right', 'anterior', 'superior'])
 
 
+class Triangle:
+
+    # pylint: disable=too-few-public-methods
+
+    _VERTEX_INDICES_TYPE = typing.Tuple[int]
+
+    _vertex_indices: _VERTEX_INDICES_TYPE
+
+    def __init__(self, vertex_indices: _VERTEX_INDICES_TYPE):
+        self.vertex_indices = vertex_indices
+
+    @property
+    def vertex_indices(self):
+        return self._vertex_indices
+
+    @vertex_indices.setter
+    def vertex_indices(self, indices: _VERTEX_INDICES_TYPE):
+        assert len(indices) == 3
+        self._vertex_indices = indices
+
+    def __eq__(self, other: 'Triangle') -> bool:
+        return self.vertex_indices == other.vertex_indices
+
+
 class Label:
 
     # pylint: disable=too-few-public-methods
@@ -153,7 +177,7 @@ class Surface:
     creator: typing.Optional[bytes] = None
     creation_datetime: typing.Optional[datetime.datetime] = None
     vertices: typing.List[Vertex] = []
-    triangles_vertex_indices: typing.List[typing.Tuple[int]] = []
+    triangles: typing.List[Triangle] = []
     using_old_real_ras: bool = False
     volume_geometry_info: typing.Optional[typing.Tuple[bytes]] = None
     command_lines: typing.List[bytes] = []
@@ -185,11 +209,11 @@ class Surface:
         vertices_num, triangles_num = struct.unpack('>II', stream.read(4 * 2))
         self.vertices = [Vertex(*struct.unpack('>fff', stream.read(4 * 3)))
                          for _ in range(vertices_num)]
-        self.triangles_vertex_indices = [struct.unpack('>III', stream.read(4 * 3))
-                                         for _ in range(triangles_num)]
+        self.triangles = [Triangle(struct.unpack('>III', stream.read(4 * 3)))
+                          for _ in range(triangles_num)]
         assert all(vertex_idx < vertices_num
-                   for triangle_vertex_index in self.triangles_vertex_indices
-                   for vertex_idx in triangle_vertex_index)
+                   for triangle in self.triangles
+                   for vertex_idx in triangle.vertex_indices)
         assert stream.read(4) == self._TAG_OLD_USEREALRAS
         using_old_real_ras, = struct.unpack('>I', stream.read(4))
         assert using_old_real_ras in [0, 1], using_old_real_ras
@@ -225,12 +249,12 @@ class Surface:
                 + b'created by ' + self.creator
                 + b' on ' + self._triangular_creation_datetime_strftime()
                 + b'\n\n'
-                + struct.pack('>II', len(self.vertices), len(self.triangles_vertex_indices))
+                + struct.pack('>II', len(self.vertices), len(self.triangles))
             )
             for vertex in self.vertices:
                 surface_file.write(struct.pack('>fff', *vertex))
-            for triangle_vertex_indices in self.triangles_vertex_indices:
-                surface_file.write(struct.pack('>III', *triangle_vertex_indices))
+            for triangle in self.triangles:
+                surface_file.write(struct.pack('>III', *triangle.vertex_indices))
             surface_file.write(self._TAG_OLD_USEREALRAS
                                + struct.pack('>I', 1 if self.using_old_real_ras else 0))
             surface_file.write(self._TAG_OLD_SURF_GEOM

+ 5 - 5
tests/test_surface.py

@@ -3,7 +3,7 @@ import os
 
 import pytest
 
-from freesurfer_surface import setlocale, Vertex, Annotation, Surface
+from freesurfer_surface import setlocale, Vertex, Triangle, Annotation, Surface
 
 from conftest import SUBJECTS_DIR
 
@@ -15,7 +15,7 @@ def test_read_triangular():
     assert surface.creator == b'fabianpeter'
     assert surface.creation_datetime == datetime.datetime(2019, 5, 9, 22, 37, 41)
     assert len(surface.vertices) == 155622
-    assert len(surface.triangles_vertex_indices) == 311240
+    assert len(surface.triangles) == 311240
     assert not surface.using_old_real_ras
     assert surface.volume_geometry_info == (
         b'valid = 1  # volume info valid\n',
@@ -89,9 +89,9 @@ def test_write_read_triangular_same(tmpdir):
                                  Vertex(1.0, 2.0, 3.0),
                                  Vertex(2.0, 4.0, 6.0),
                                  Vertex(3.0, 5.0, 7.0)]
-    expected_surface.triangles_vertex_indices = [(0, 1, 2),
-                                                 (0, 1, 3),
-                                                 (3, 2, 1)]
+    expected_surface.triangles = [Triangle((0, 1, 2)),
+                                  Triangle((0, 1, 3)),
+                                  Triangle((3, 2, 1))]
     expected_surface.using_old_real_ras = False
     expected_surface.volume_geometry_info = tuple(b'?\n' for _ in range(8))
     expected_surface.command_lines = [b'?', b'!']

+ 21 - 0
tests/test_triangle.py

@@ -0,0 +1,21 @@
+import pytest
+
+from freesurfer_surface import Triangle
+
+
+def test_init():
+    triangle = Triangle((0, 21, 42))
+    assert triangle.vertex_indices == (0, 21, 42)
+
+
+def test_init_invalid_indices_len():
+    with pytest.raises(Exception):
+        Triangle((0, 21, 42, 84))
+
+
+def test_eq():
+    assert Triangle((0, 1, 2)) == Triangle((0, 1, 2))
+    # pylint: disable=unneeded-not
+    assert not Triangle((0, 1, 2)) == Triangle((0, 1, 4))
+    assert not Triangle((0, 1, 2)) == Triangle((0, 4, 2))
+    assert not Triangle((0, 1, 2)) == Triangle((4, 1, 2))