22import os
33import threading
44import time
5+ import xml .etree .ElementTree as ET
56import zipfile
67from collections .abc import Callable
78from concurrent .futures import ThreadPoolExecutor
2223from . import geode_functions
2324from .geode_objects import geode_objects
2425from .geode_objects .types import GeodeObjectType
26+ from .geode_objects .geode_model import GeodeModel
2527from .geode_objects .geode_object import GeodeObject
2628
2729
@@ -184,11 +186,69 @@ def create_data_folder_from_id(data_id: str) -> str:
184186 return data_path
185187
186188
189+ def model_components (
190+ data_id : str , model : GeodeModel , viewable_file : str
191+ ) -> dict [str , Any ]:
192+ vtm_file_path = geode_functions .data_file_path (data_id , viewable_file )
193+ tree = ET .parse (vtm_file_path )
194+ root = tree .find ("vtkMultiBlockDataSet" )
195+ if root is None :
196+ flask .abort (500 , "Failed to read viewable file" )
197+ uuid_to_flat_index = {}
198+ current_index = 0
199+ assert root is not None
200+ for elem in root .iter ():
201+ if "uuid" in elem .attrib and elem .tag == "DataSet" :
202+ uuid_to_flat_index [elem .attrib ["uuid" ]] = current_index
203+ current_index += 1
204+ model_mesh_components = model .mesh_components ()
205+ mesh_components = []
206+ for mesh_component , ids in model_mesh_components .items ():
207+ component_type = mesh_component .get ()
208+ for id in ids :
209+ geode_id = id .string ()
210+ component_name = geode_id
211+ viewer_id = uuid_to_flat_index [geode_id ]
212+ boundaries = model .boundaries (id )
213+ boundaries_uuid = [boundary .id ().string () for boundary in boundaries ]
214+ internals = model .internals (id )
215+ internals_uuid = [internal .id ().string () for internal in internals ]
216+ mesh_component_object = {
217+ "viewer_id" : viewer_id ,
218+ "geode_id" : geode_id ,
219+ "name" : component_name ,
220+ "type" : component_type ,
221+ "boundaries" : boundaries_uuid ,
222+ "internals" : internals_uuid ,
223+ }
224+ mesh_components .append (mesh_component_object )
225+
226+ model_collection_components = model .collection_components ()
227+ collection_components = []
228+ for collection_component , ids in model_collection_components .items ():
229+ component_type = collection_component .get ()
230+ for id in ids :
231+ geode_id = id .string ()
232+ items = model .items (id )
233+ items_uuid = [item .id ().string () for item in items ]
234+ collection_component_object = {
235+ "geode_id" : geode_id ,
236+ "name" : geode_id ,
237+ "type" : component_type ,
238+ "items" : items_uuid ,
239+ }
240+ collection_components .append (collection_component_object )
241+ return {
242+ "mesh_components" : mesh_components ,
243+ "collection_components" : collection_components ,
244+ }
245+
246+
187247def save_all_viewables_and_return_info (
188248 geode_object : GeodeObject ,
189249 data : Data ,
190250 data_path : str ,
191- ) -> dict [str , str | list [ str ] ]:
251+ ) -> dict [str , Any ]:
192252 with ThreadPoolExecutor () as executor :
193253 native_files , viewable_path , light_path = executor .map (
194254 lambda args : args [0 ](args [1 ]),
@@ -218,7 +278,8 @@ def save_all_viewables_and_return_info(
218278 name = geode_object .identifier .name ()
219279 if not name :
220280 flask .abort (400 , "Geode object has no name defined." )
221- return {
281+
282+ response : dict [str , Any ] = {
222283 "native_file" : data .native_file ,
223284 "viewable_file" : data .viewable_file ,
224285 "id" : data .id ,
@@ -227,11 +288,14 @@ def save_all_viewables_and_return_info(
227288 "binary_light_viewable" : binary_light_viewable .decode ("utf-8" ),
228289 "geode_object_type" : data .geode_object ,
229290 }
291+ if isinstance (geode_object , GeodeModel ):
292+ response |= model_components (data .id , geode_object , data .viewable_file )
293+ return response
230294
231295
232296def generate_native_viewable_and_light_viewable_from_object (
233297 geode_object : GeodeObject ,
234- ) -> dict [str , str | list [ str ] ]:
298+ ) -> dict [str , Any ]:
235299 data = Data .create (
236300 geode_object = geode_object .geode_object_type (),
237301 viewer_object = geode_object .viewer_type (),
@@ -243,7 +307,7 @@ def generate_native_viewable_and_light_viewable_from_object(
243307
244308def generate_native_viewable_and_light_viewable_from_file (
245309 geode_object_type : GeodeObjectType , input_file : str
246- ) -> dict [str , str | list [ str ] ]:
310+ ) -> dict [str , Any ]:
247311 generic_geode_object = geode_objects [geode_object_type ]
248312 data = Data .create (
249313 geode_object = geode_object_type ,
0 commit comments