1+ import logging
2+
13import pyvista as pv
24from PyQt5 .QtCore import Qt
35from PyQt5 .QtWidgets import (
1315 QWidget ,
1416)
1517
18+ logger = logging .getLogger (__name__ )
19+
1620
1721class ObjectListWidget (QWidget ):
1822 def __init__ (self , parent = None , * , viewer = None , properties_widget = None ):
@@ -262,11 +266,19 @@ def export_selected_object(self):
262266 except ImportError :
263267 has_geoh5py = False
264268
265- if hasattr (object , "faces" ): # Likely a surface/mesh
269+ # Check if this is a grid/voxel type (UniformGrid, ImageData, StructuredGrid, RectilinearGrid)
270+ is_grid = type (mesh ).__name__ in ['UniformGrid' , 'ImageData' , 'StructuredGrid' , 'RectilinearGrid' ]
271+
272+ if is_grid :
273+ # Grid/voxel meshes support ASCII export
274+ formats = ["vtk" , "ascii" ]
275+ if has_geoh5py :
276+ formats .append ("geoh5" )
277+ elif hasattr (mesh , "faces" ): # Likely a surface/mesh
266278 formats = ["obj" , "vtk" , "ply" ]
267279 if has_geoh5py :
268280 formats .append ("geoh5" )
269- elif hasattr (object , "points" ): # Likely a point cloud
281+ elif hasattr (mesh , "points" ): # Likely a point cloud
270282 formats = ["vtp" ]
271283 if has_geoh5py :
272284 formats .append ("geoh5" )
@@ -279,6 +291,7 @@ def export_selected_object(self):
279291 "vtk" : "VTK (*.vtk)" ,
280292 "ply" : "PLY (*.ply)" ,
281293 "vtp" : "VTP (*.vtp)" ,
294+ "ascii" : "ASCII Grid (*.txt)" ,
282295 "geoh5" : "Geoh5 (*.geoh5)" ,
283296 }
284297 filters = ";;" .join ([filter_map [f ] for f in formats ])
@@ -312,6 +325,9 @@ def export_selected_object(self):
312325 if hasattr (mesh , "save" )
313326 else pv .save_meshio (file_path , mesh )
314327 )
328+ elif selected_format == "ascii" :
329+ # Export grid/voxel as ASCII: x, y, z, value format
330+ self ._export_grid_ascii (mesh , file_path , object_label )
315331 elif selected_format == "geoh5" :
316332 with geoh5py .Geoh5 (file_path , overwrite = True ) as geoh5 :
317333 if hasattr (mesh , "faces" ):
@@ -320,11 +336,58 @@ def export_selected_object(self):
320336 )
321337 else :
322338 geoh5 .add_points (name = object_label , vertices = mesh .points )
323- print (f"Exported { object_label } to { file_path } as { selected_format } " )
339+ logger . info (f"Exported { object_label } to { file_path } as { selected_format } " )
324340 except Exception as e :
325- print (f"Failed to export object: { e } " )
341+ logger . error (f"Failed to export object: { e } " )
326342 # Logic for exporting the object
327343
344+ def _export_grid_ascii (self , mesh , file_path , object_label ):
345+ """Export a grid/voxel mesh to ASCII format.
346+
347+ Format: x, y, z, value (one line per cell center)
348+
349+ Parameters
350+ ----------
351+ mesh : pyvista grid mesh
352+ The grid mesh to export
353+ file_path : str
354+ Path to the output file
355+ object_label : str
356+ Name of the object (used to determine which scalar array to export)
357+ """
358+ import numpy as np
359+
360+ # Get cell centers
361+ cell_centers = mesh .cell_centers ()
362+ centers = cell_centers .points
363+
364+ # Get scalar values - try to use the active scalars or the first available array
365+ scalar_name = mesh .active_scalars_name
366+ if scalar_name is None :
367+ # Try to find any cell data array
368+ if mesh .cell_data :
369+ scalar_name = list (mesh .cell_data .keys ())[0 ]
370+
371+ if scalar_name is not None :
372+ values = mesh .cell_data [scalar_name ]
373+ else :
374+ # If no scalar data, use zeros
375+ values = np .zeros (mesh .n_cells )
376+
377+ # Write to file
378+ with open (file_path , 'w' ) as f :
379+ f .write (f"# ASCII Grid Export: { object_label } \n " )
380+ f .write (f"# Format: x y z value\n " )
381+ f .write (f"# Number of cells: { mesh .n_cells } \n " )
382+ if scalar_name :
383+ f .write (f"# Scalar field: { scalar_name } \n " )
384+ f .write ("#\n " )
385+
386+ for i in range (len (centers )):
387+ x , y , z = centers [i ]
388+ value = values [i ]
389+ f .write (f"{ x :.6f} { y :.6f} { z :.6f} { value :.6f} \n " )
390+
328391 def remove_selected_object (self ):
329392 selected_items = self .treeWidget .selectedItems ()
330393 if not selected_items :
0 commit comments