Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 39 additions & 50 deletions docs/API_MAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ _Re-run `py utils/generate_api_map.py` whenever public APIs change._

## experiments/Convert_VTK_To_USD/convert_vtk_to_usd_using_class.py

- `def create_deformed_mesh(base_mesh_data, time_step, num_steps=10)` (line 276): Create a deformed version of the mesh for animation.
- `def verify_usd_file(usd_path)` (line 391): Verify USD file integrity.
- `def create_deformed_pv_mesh(base, time_step, num_steps=10)` (line 237): Return a sinusoidally scaled copy of base with a synthetic pressure field.
- `def verify_usd_file(usd_path)` (line 315): Verify USD file integrity.

## experiments/DisplacementField_To_USD/displacement_field_to_usd.py

Expand Down Expand Up @@ -115,12 +115,13 @@ _Re-run `py utils/generate_api_map.py` whenever public APIs change._

## src/physiomotion4d/convert_vtk_to_usd.py

- **class ConvertVTKToUSD** (line 36): Advanced VTK to USD converter with colormap and anatomical labeling support.
- `def __init__(self, data_basename, input_polydata, mask_ids=None, compute_normals=False, convert_to_surface=True, times_per_second=24.0, log_level=logging.INFO)` (line 66): Initialize converter.
- `def supports_mesh_type(self, mesh)` (line 119): Check if mesh type is supported for conversion.
- `def list_available_arrays(self)` (line 147): List all point data arrays available across all time steps.
- `def set_colormap(self, color_by_array=None, colormap='plasma', intensity_range=None)` (line 193): Configure colormap for visualization.
- `def convert(self, output_usd_file, convert_to_surface=None, compute_normals=None)` (line 227): Convert VTK meshes to USD.
- **class ConvertVTKToUSD** (line 38): Advanced VTK to USD converter with colormap and anatomical labeling support.
- `def __init__(self, data_basename, input_polydata, mask_ids=None, compute_normals=False, convert_to_surface=True, times_per_second=24.0, separate_by='none', solid_color=(0.8, 0.8, 0.8), log_level=logging.INFO)` (line 68): Initialize converter.
- `def from_files(cls, data_basename, vtk_files, *, extract_surface=True, separate_by='none', times_per_second=24.0, solid_color=(0.8, 0.8, 0.8), time_codes=None, static_merge=False, mask_ids=None, log_level=logging.INFO)` (line 135): Create a converter by loading VTK files from disk.
- `def supports_mesh_type(self, mesh)` (line 217): Check if mesh type is supported for conversion.
- `def list_available_arrays(self)` (line 245): List all point data arrays available across all time steps.
- `def set_colormap(self, color_by_array=None, colormap='plasma', intensity_range=None)` (line 291): Configure colormap for visualization.
- `def convert(self, output_usd_file, convert_to_surface=None, compute_normals=None)` (line 325): Convert VTK meshes to USD.

## src/physiomotion4d/image_tools.py

Expand Down Expand Up @@ -342,18 +343,6 @@ _Re-run `py utils/generate_api_map.py` whenever public APIs change._
- `def list_mesh_paths_under(self, stage_or_path, parent_path='/World/Meshes')` (line 1103): List paths of all mesh prims under a parent path.
- `def repair_mesh_primvar_element_sizes(self, stage_or_path, mesh_path, *, time_code=None, save=True)` (line 1130): Repair missing/incorrect primvar elementSize metadata for a mesh.

## src/physiomotion4d/vtk_to_usd/converter.py

- **class VTKToUSDConverter** (line 21): High-level converter for VTK files to USD.
- `def __init__(self, settings=None)` (line 37): Initialize converter.
- `def convert_file(self, vtk_file, output_usd, mesh_name='Mesh', material=None, extract_surface=True)` (line 48): Convert a single VTK file to USD.
- `def convert_files_static(self, vtk_files, output_usd, mesh_name='Mesh', material=None, extract_surface=True)` (line 114): Convert multiple VTK files into one static USD stage (no time samples).
- `def convert_sequence(self, vtk_files, output_usd, mesh_name='Mesh', time_codes=None, material=None, extract_surface=True)` (line 190): Convert a sequence of VTK files to time-varying USD.
- `def convert_mesh_data(self, mesh_data, output_usd, mesh_name='Mesh', material=None)` (line 316): Convert MeshData directly to USD.
- `def convert_mesh_data_sequence(self, mesh_data_sequence, output_usd, mesh_name='Mesh', time_codes=None, material=None)` (line 378): Convert sequence of MeshData to time-varying USD.
- `def convert_vtk_file(vtk_file, output_usd, settings=None, **kwargs)` (line 555): Convenience function to convert a single VTK file.
- `def convert_vtk_sequence(vtk_files, output_usd, settings=None, **kwargs)` (line 576): Convenience function to convert a sequence of VTK files.

## src/physiomotion4d/vtk_to_usd/data_structures.py

- **class DataType** (line 13): Data type enumeration for generic arrays.
Expand Down Expand Up @@ -428,10 +417,10 @@ _Re-run `py utils/generate_api_map.py` whenever public APIs change._

## src/physiomotion4d/workflow_convert_vtk_to_usd.py

- **class WorkflowConvertVTKToUSD** (line 29): Workflow to convert one or more VTK files to USD with configurable
- `def __init__(self, vtk_files, output_usd, *, separate_by_connectivity=True, separate_by_cell_type=False, mesh_name='Mesh', times_per_second=60.0, up_axis='Y', triangulate=True, extract_surface=True, time_series_pattern='\\.t(\\d+)\\.(vtk|vtp|vtu)$', appearance='solid', solid_color=(0.8, 0.8, 0.8), anatomy_type='heart', colormap_primvar=None, colormap_name='viridis', colormap_intensity_range=None, log_level=logging.INFO)` (line 35): Initialize the VTK-to-USD workflow.
- `def discover_time_series(self, paths, pattern='\\.t(\\d+)\\.(vtk|vtp|vtu)$')` (line 105): Discover and sort time-series VTK files by extracted time index.
- `def run(self)` (line 141): Run the full workflow: convert VTK to USD, then apply the chosen appearance.
- **class WorkflowConvertVTKToUSD** (line 23): Workflow to convert one or more VTK files to USD with configurable
- `def __init__(self, vtk_files, output_usd, *, separate_by_connectivity=True, separate_by_cell_type=False, mesh_name='Mesh', times_per_second=60.0, up_axis='Y', triangulate=True, extract_surface=True, time_series_pattern='\\.t(\\d+)\\.(vtk|vtp|vtu)$', appearance='solid', solid_color=(0.8, 0.8, 0.8), anatomy_type='heart', colormap_primvar=None, colormap_name='viridis', colormap_intensity_range=None, log_level=logging.INFO)` (line 29): Initialize the VTK-to-USD workflow.
- `def discover_time_series(self, paths, pattern='\\.t(\\d+)\\.(vtk|vtp|vtu)$')` (line 99): Discover and sort time-series VTK files by extracted time index.
- `def run(self)` (line 135): Run the full workflow: convert VTK to USD, then apply the chosen appearance.

## src/physiomotion4d/workflow_create_statistical_model.py

Expand Down Expand Up @@ -712,32 +701,32 @@ _Re-run `py utils/generate_api_map.py` whenever public APIs change._

## tests/test_vtk_to_usd_library.py

- `def get_data_dir()` (line 35): Get the data directory path.
- `def check_kcl_heart_data()` (line 42): Check if KCL Heart Model data is available.
- `def check_valve4d_data()` (line 49): Check if CHOP Valve4D data is available.
- `def get_or_create_average_surface(test_directories)` (line 56): Get or create average_surface.vtp from average_mesh.vtk.
- `def kcl_average_surface(test_directories)` (line 102): Fixture providing the KCL average heart surface.
- **class TestGenericArray** (line 118): Test GenericArray data structure validation and reshaping.
- `def test_scalar_1d_array(self)` (line 121): Test that 1D scalar arrays (num_components=1) are kept as-is.
- `def test_flat_multicomponent_array_reshape(self)` (line 134): Test that flat 1D arrays with num_components>1 are reshaped to 2D.
- `def test_2d_array_valid(self)` (line 150): Test that 2D arrays with correct shape are accepted.
- `def test_flat_array_not_divisible_raises_error(self)` (line 163): Test that flat arrays with length not divisible by num_components raise error.
- `def test_2d_array_wrong_shape_raises_error(self)` (line 174): Test that 2D arrays with wrong shape raise error.
- `def test_3d_array_raises_error(self)` (line 185): Test that 3D arrays are rejected.
- `def test_flat_array_large_components(self)` (line 196): Test reshaping with large num_components (e.g., 9 for 3x3 tensors).
- **class TestVTKReader** (line 212): Test VTK file reading capabilities.
- `def test_read_vtp_file(self, kcl_average_surface)` (line 215): Test reading VTP (PolyData) files.
- `def test_read_legacy_vtk_file(self)` (line 236): Test reading legacy VTK files.
- `def test_generic_arrays_preserved(self, kcl_average_surface)` (line 263): Test that generic data arrays are preserved during reading.
- **class TestVTKToUSDConversion** (line 287): Test VTK to USD conversion capabilities.
- `def test_single_file_conversion(self, test_directories, kcl_average_surface)` (line 290): Test converting a single VTK file to USD.
- `def test_conversion_with_material(self, test_directories, kcl_average_surface)` (line 332): Test conversion with custom material.
- `def test_conversion_settings(self, test_directories, kcl_average_surface)` (line 379): Test conversion with custom settings.
- `def test_primvar_preservation(self, test_directories, kcl_average_surface)` (line 414): Test that VTK data arrays are preserved as USD primvars.
- **class TestTimeSeriesConversion** (line 454): Test time-series conversion capabilities.
- `def test_time_series_conversion(self, test_directories, kcl_average_surface)` (line 457): Test converting multiple VTK files as time series.
- **class TestIntegration** (line 507): Integration tests combining multiple features.
- `def test_end_to_end_conversion(self, test_directories, kcl_average_surface)` (line 510): Test complete conversion workflow with all features.
- `def get_data_dir()` (line 32): Get the data directory path.
- `def check_kcl_heart_data()` (line 39): Check if KCL Heart Model data is available.
- `def check_valve4d_data()` (line 46): Check if CHOP Valve4D data is available.
- `def get_or_create_average_surface(test_directories)` (line 53): Get or create average_surface.vtp from average_mesh.vtk.
- `def kcl_average_surface(test_directories)` (line 99): Fixture providing the KCL average heart surface.
- **class TestGenericArray** (line 115): Test GenericArray data structure validation and reshaping.
- `def test_scalar_1d_array(self)` (line 118): Test that 1D scalar arrays (num_components=1) are kept as-is.
- `def test_flat_multicomponent_array_reshape(self)` (line 131): Test that flat 1D arrays with num_components>1 are reshaped to 2D.
- `def test_2d_array_valid(self)` (line 147): Test that 2D arrays with correct shape are accepted.
- `def test_flat_array_not_divisible_raises_error(self)` (line 160): Test that flat arrays with length not divisible by num_components raise error.
- `def test_2d_array_wrong_shape_raises_error(self)` (line 171): Test that 2D arrays with wrong shape raise error.
- `def test_3d_array_raises_error(self)` (line 182): Test that 3D arrays are rejected.
- `def test_flat_array_large_components(self)` (line 193): Test reshaping with large num_components (e.g., 9 for 3x3 tensors).
- **class TestVTKReader** (line 209): Test VTK file reading capabilities.
- `def test_read_vtp_file(self, kcl_average_surface)` (line 212): Test reading VTP (PolyData) files.
- `def test_read_legacy_vtk_file(self)` (line 233): Test reading legacy VTK files.
- `def test_generic_arrays_preserved(self, kcl_average_surface)` (line 260): Test that generic data arrays are preserved during reading.
- **class TestVTKToUSDConversion** (line 284): Test VTK to USD conversion capabilities.
- `def test_single_file_conversion(self, test_directories, kcl_average_surface)` (line 287): Test converting a single VTK file to USD.
- `def test_conversion_with_material(self, test_directories, kcl_average_surface)` (line 319): Test conversion with a custom solid color material.
- `def test_conversion_settings(self, test_directories, kcl_average_surface)` (line 349): Test that ConvertVTKToUSD applies correct default stage metadata.
- `def test_primvar_preservation(self, test_directories, kcl_average_surface)` (line 372): Test that VTK data arrays are preserved as USD primvars.
- **class TestTimeSeriesConversion** (line 408): Test time-series conversion capabilities.
- `def test_time_series_conversion(self, test_directories, kcl_average_surface)` (line 411): Test converting multiple VTK files as a time series.
- **class TestIntegration** (line 451): Integration tests combining multiple features.
- `def test_end_to_end_conversion(self, test_directories, kcl_average_surface)` (line 454): Test complete conversion workflow with all features.

## utils/claude_github_reviews.py

Expand Down
82 changes: 24 additions & 58 deletions experiments/Convert_VTK_To_USD/convert_chop_alterra_valve_to_usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,11 @@
# Import USDTools for post-processing colormap
from physiomotion4d.usd_tools import USDTools

# Import the vtk_to_usd library
from physiomotion4d.vtk_to_usd import (
ConversionSettings,
MaterialData,
VTKToUSDConverter,
cell_type_name_for_vertex_count,
read_vtk_file,
validate_time_series_topology,
)
from physiomotion4d import ConvertVTKToUSD

# cell_type_name_for_vertex_count and read_vtk_file are internal APIs used for diagnostics
from physiomotion4d.vtk_to_usd import cell_type_name_for_vertex_count
from physiomotion4d.vtk_to_usd.vtk_reader import read_vtk_file

# %% [markdown]
# ## 1. Discover and Organize Time-Series Files
Expand All @@ -71,25 +67,10 @@
colormap_range_min = 25
colormap_range_max = 200

conversion_settings = ConversionSettings(
triangulate_meshes=True,
compute_normals=False, # Use existing normals if available
preserve_point_arrays=True,
preserve_cell_arrays=True,
separate_objects_by_cell_type=False,
separate_objects_by_connectivity=True, # Essential for alterra vtk file
up_axis="Y",
times_per_second=60.0, # 60 FPS for smooth animation
use_time_samples=True,
)

stent_material = MaterialData(
name="Alterra_valve",
diffuse_color=(0.5, 0.5, 0.5),
roughness=0.4,
metallic=0.9,
use_vertex_colors=False,
)
# Conversion parameters
separate_by = "connectivity" # Essential for alterra vtk file
times_per_second = 60.0
solid_color = (0.5, 0.5, 0.5)

# %%
output_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -155,8 +136,6 @@
# ## 3. Convert TPV25

# %%
converter = VTKToUSDConverter(conversion_settings)

alterra_files = [file_path for _, file_path in alterra_series]
alterra_times = [float(time_step) for time_step, _ in alterra_series]

Expand All @@ -168,39 +147,26 @@
print(f"Number of time steps: {len(alterra_times)}")
print("\nThis may take several minutes...\n")

# Read MeshData
mesh_data_sequence = [read_vtk_file(f, extract_surface=True) for f in alterra_files]

# Validate topology consistency across time series
validation_report = validate_time_series_topology(
mesh_data_sequence, filenames=alterra_files
)
if not validation_report["is_consistent"]:
print(
f"Warning: Found {len(validation_report['warnings'])} topology/primvar issues"
)
if validation_report["topology_changes"]:
print(
f" Topology changes in {len(validation_report['topology_changes'])} frames"
)

# Convert to USD (preserves all primvars from VTK)
stage = converter.convert_mesh_data_sequence(
mesh_data_sequence=mesh_data_sequence,
output_usd=output_usd,
mesh_name="AlterraValve",
# topology validation and conversion happen inside from_files()
stage = ConvertVTKToUSD.from_files(
data_basename="AlterraValve",
vtk_files=alterra_files,
extract_surface=True,
separate_by=separate_by,
times_per_second=times_per_second,
solid_color=solid_color,
time_codes=alterra_times,
material=stent_material,
)
).convert(str(output_usd))

# %%
usd_tools = USDTools()
if conversion_settings.separate_objects_by_connectivity is True:
vessel_path = "/World/Meshes/AlterraValve_object3"
elif conversion_settings.separate_objects_by_cell_type is True:
vessel_path = "/World/Meshes/AlterraValve_triangle1"
# ConvertVTKToUSD places prims at /World/{basename}/{part_name}
if separate_by == "connectivity":
vessel_path = "/World/AlterraValve/AlterraValve_object3"
elif separate_by == "cell_type":
vessel_path = "/World/AlterraValve/AlterraValve_Triangle"
else:
vessel_path = "/World/Meshes/AlterraValve"
vessel_path = "/World/AlterraValve/Mesh"

# Select primvar for coloring
primvars = usd_tools.list_mesh_primvars(str(output_usd), vessel_path)
Expand Down
82 changes: 24 additions & 58 deletions experiments/Convert_VTK_To_USD/convert_chop_tpv25_valve_to_usd.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,11 @@
# Import USDTools for post-processing colormap
from physiomotion4d.usd_tools import USDTools

# Import the vtk_to_usd library
from physiomotion4d.vtk_to_usd import (
ConversionSettings,
MaterialData,
VTKToUSDConverter,
cell_type_name_for_vertex_count,
read_vtk_file,
validate_time_series_topology,
)
from physiomotion4d import ConvertVTKToUSD

# cell_type_name_for_vertex_count and read_vtk_file are internal APIs used for diagnostics
from physiomotion4d.vtk_to_usd import cell_type_name_for_vertex_count
from physiomotion4d.vtk_to_usd.vtk_reader import read_vtk_file

# %% [markdown]
# ## 1. Discover and Organize Time-Series Files
Expand All @@ -70,25 +66,10 @@
colormap_range_min = 25
colormap_range_max = 200

conversion_settings = ConversionSettings(
triangulate_meshes=True,
compute_normals=False, # Use existing normals if available
preserve_point_arrays=True,
preserve_cell_arrays=True,
separate_objects_by_cell_type=False,
separate_objects_by_connectivity=True, # Essential for tpv25 vtk file
up_axis="Y",
times_per_second=60.0, # 60 FPS for smooth animation
use_time_samples=True,
)

stent_material = MaterialData(
name="tpv25_valve",
diffuse_color=(0.5, 0.5, 0.5),
roughness=0.4,
metallic=0.9,
use_vertex_colors=False,
)
# Conversion parameters
separate_by = "connectivity" # Essential for tpv25 vtk file
times_per_second = 60.0
solid_color = (0.5, 0.5, 0.5)

# %%
output_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -154,8 +135,6 @@
# ## 3. Convert TPV25

# %%
converter = VTKToUSDConverter(conversion_settings)

tpv25_files = [file_path for _, file_path in tpv25_series]
tpv25_times = [float(time_step) for time_step, _ in tpv25_series]

Expand All @@ -167,39 +146,26 @@
print(f"Number of time steps: {len(tpv25_times)}")
print("\nThis may take several minutes...\n")

# Read MeshData
mesh_data_sequence = [read_vtk_file(f, extract_surface=True) for f in tpv25_files]

# Validate topology consistency across time series
validation_report = validate_time_series_topology(
mesh_data_sequence, filenames=tpv25_files
)
if not validation_report["is_consistent"]:
print(
f"Warning: Found {len(validation_report['warnings'])} topology/primvar issues"
)
if validation_report["topology_changes"]:
print(
f" Topology changes in {len(validation_report['topology_changes'])} frames"
)

# Convert to USD (preserves all primvars from VTK)
stage = converter.convert_mesh_data_sequence(
mesh_data_sequence=mesh_data_sequence,
output_usd=output_usd,
mesh_name="TPV25Valve",
# topology validation and conversion happen inside from_files()
stage = ConvertVTKToUSD.from_files(
data_basename="TPV25Valve",
vtk_files=tpv25_files,
extract_surface=True,
separate_by=separate_by,
times_per_second=times_per_second,
solid_color=solid_color,
time_codes=tpv25_times,
material=stent_material,
)
).convert(str(output_usd))

# %%
usd_tools = USDTools()
if conversion_settings.separate_objects_by_connectivity is True:
vessel_path = "/World/Meshes/TPV25Valve_object4"
elif conversion_settings.separate_objects_by_cell_type is True:
vessel_path = "/World/Meshes/TPV25Valve_triangle1"
# ConvertVTKToUSD places prims at /World/{basename}/{part_name}
if separate_by == "connectivity":
vessel_path = "/World/TPV25Valve/TPV25Valve_object4"
elif separate_by == "cell_type":
vessel_path = "/World/TPV25Valve/TPV25Valve_Triangle"
else:
vessel_path = "/World/Meshes/TPV25Valve"
vessel_path = "/World/TPV25Valve/Mesh"

# Select primvar for coloring
primvars = usd_tools.list_mesh_primvars(str(output_usd), vessel_path)
Expand Down
Loading
Loading