Skip to content

Commit 4225eab

Browse files
committed
OMF-8 - Progress on V1 converter:
- points and lines complete - data section partially converted
1 parent adff6d5 commit 4225eab

File tree

2 files changed

+73
-13
lines changed

2 files changed

+73
-13
lines changed

omf/attribute.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ class CategoryColormap(ContentModel):
483483
schema = "org.omf.v2.colormap.category"
484484

485485
indices = properties.List(
486-
"indices corresponding to CateogryAttribute array values",
486+
"indices corresponding to CategoryAttribute array values",
487487
properties.Integer(""),
488488
)
489489
values = properties.List(

omf/compat/omf_v1.py

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from .interface import IOMFReader, InvalidOMFFile
99

10-
from .. import base, pointset, texture
10+
from .. import attribute, base, lineset, pointset, texture
1111

1212
COMPATIBILITY_VERSION = b'OMF-v0.9.0'
1313
_default = object()
@@ -29,6 +29,10 @@ def load(self, include_binary: bool = True, project_json: bool = None):
2929
self._project = self._read_json(json_start)
3030
return self._copy_project(project_uuid)
3131

32+
def _test_data_needed(self, *args, **kwargs):
33+
# temporary placeholder
34+
raise InvalidOMFFile('Test data required')
35+
3236
def _read_header(self):
3337
"""Checks magic number and version; gets project uid and json start"""
3438
self._f.seek(0)
@@ -47,8 +51,8 @@ def _read_json(self, json_start):
4751
return json.loads(self._f.read().decode('utf-8'))
4852

4953
# Safe access to attributes
50-
@staticmethod
51-
def __get_attr(src, attr, optional=False, converter=None, default=_default):
54+
@classmethod
55+
def __get_attr(cls, src, attr, optional=False, converter=None, default=_default):
5256
if attr not in src:
5357
if not optional:
5458
raise InvalidOMFFile(f"Attribute {attr} missing")
@@ -67,8 +71,8 @@ def __require_attr(cls, src, attr, required_value):
6771
if value != required_value:
6872
raise InvalidOMFFile(f"Invalid attribute {attr}. Expected: {required_value}, actual: {value}")
6973

70-
@staticmethod
71-
def __copy_attr(src, src_attr, dst, dst_attr=None,
74+
@classmethod
75+
def __copy_attr(cls, src, src_attr, dst, dst_attr=None,
7276
optional_src=False, optional_dst=False, converter=None, default=_default):
7377
if dst_attr is None:
7478
dst_attr = src_attr
@@ -91,14 +95,29 @@ def __copy_attr(src, src_attr, dst, dst_attr=None,
9195
else:
9296
setattr(dst, dst_attr, value)
9397

94-
# reading numpy arrays
98+
# reading arrays
9599
def _load_array(self, scalar_array):
96100
scalar_class = self.__get_attr(scalar_array, '__class__')
97-
shape_lookup = {'Vector3Array': ('*', 3),
98-
}
101+
converter_lookup = {
102+
'StringArray': self._test_data_needed,
103+
'DateTimeArray': self._test_data_needed,
104+
'ColorArray': self._test_data_needed,
105+
}
106+
shape_lookup = {
107+
'ScalarArray': ('*',),
108+
'Int2Array': ('*', 2),
109+
'Int3Array': ('*', 3),
110+
'Vector2Array': ('*', 2),
111+
'Vector3Array': ('*', 3),
112+
}
113+
converter = self.__get_attr(converter_lookup, scalar_class, optional=True)
114+
if converter is not None:
115+
return converter(scalar_array)
116+
99117
shape = self.__get_attr(shape_lookup, scalar_class)
100118
shape = tuple(-1 if s == '*' else s for s in shape)
101119
base_vector = self.__get_attr(scalar_array, 'array')
120+
102121
start = self.__get_attr(base_vector, 'start')
103122
length = self.__get_attr(base_vector, 'length')
104123
dtype = self.__get_attr(base_vector, 'dtype')
@@ -168,8 +187,31 @@ def _copy_textures(self, src, dst):
168187
dst.textures = [self._copy_texture(texture_uuid) for texture_uuid in texture_uuids]
169188

170189
# data columns
171-
def _copy_data(self, src, dst):
172-
pass
190+
def _copy_scalar_data(self, data_v1):
191+
data = attribute.NumericAttribute()
192+
self._copy_scalar_array(data_v1, 'array', data)
193+
if self.__get_attr(data_v1, 'colormap', optional=True) is not None:
194+
self._test_data_needed(data_v1, data)
195+
return data
196+
197+
def _copy_project_element_data(self, data_uuid, valid_locations):
198+
data_v1 = self.__get_attr(self._project, data_uuid)
199+
data_class = self.__get_attr(data_v1, '__class__')
200+
201+
converters = {'ScalarData': self._copy_scalar_data}
202+
converter = self.__get_attr(converters, data_class)
203+
data = converter(data_v1)
204+
location = self.__get_attr(data_v1, 'location')
205+
if location not in valid_locations:
206+
raise InvalidOMFFile(f'Invalid data location: {location}')
207+
self._copy_content_model(data_v1, data)
208+
return data
209+
210+
def _copy_data(self, src, dst, valid_locations):
211+
data_uuids = self.__get_attr(src, 'data', optional=True)
212+
if data_uuids is None:
213+
return
214+
dst.attributes = [self._copy_project_element_data(data_uuid, valid_locations) for data_uuid in data_uuids]
173215

174216
# points
175217
def _copy_pointset_element(self, points_v1):
@@ -185,17 +227,35 @@ def _copy_pointset_element(self, points_v1):
185227
valid_locations = ('vertices',)
186228
return points, valid_locations
187229

230+
# line sets
231+
def _copy_lineset_element(self, lines_v1):
232+
geometry_uuid = self.__get_attr(lines_v1, 'geometry')
233+
geometry_v1 = self.__get_attr(self._project, geometry_uuid)
234+
235+
lines = lineset.LineSet()
236+
self.__copy_attr(lines_v1, 'subtype', lines.metadata)
237+
self._copy_project_element_geometry(geometry_v1, lines)
238+
self._copy_scalar_array(geometry_v1, 'vertices', lines)
239+
self._copy_scalar_array(geometry_v1, 'segments', lines)
240+
241+
valid_locations = ('vertices', 'segments')
242+
return lines, valid_locations
243+
188244
# element list
189245
def _copy_project_element(self, element_uuid):
190246
element_v1 = self.__get_attr(self._project, element_uuid)
191247
element_class = self.__get_attr(element_v1, '__class__')
192248

193-
converters = {'PointSetElement': self._copy_pointset_element}
249+
converters = {'PointSetElement': self._copy_pointset_element,
250+
'LineSetElement': self._copy_lineset_element,
251+
'SurfaceElement': self._test_data_needed,
252+
'VolumeElement': self._test_data_needed,
253+
}
194254
converter = self.__get_attr(converters, element_class)
195255
element, valid_locations = converter(element_v1)
196256

197257
self._copy_content_model(element_v1, element)
198-
self._copy_data(element_v1, element)
258+
self._copy_data(element_v1, element, valid_locations)
199259
self.__copy_attr(element_v1, 'color', element.metadata)
200260
return element
201261

0 commit comments

Comments
 (0)