Skip to content

Commit 7523ff3

Browse files
authored
ENH:VTK_To_USD and ConvertVTKToUSD consolidation (#44)
* Consolidate VTK-to-USD conversion under ConvertVTKToUSD as single API - Add from_files() classmethod to ConvertVTKToUSD, accepting file paths and loading via pv.read(); adds separate_by, solid_color, static_merge, time_codes - Add _convert_static_merge() method for multi-file static scenes - Add _convert_unified() splitting logic via split_mesh_data_by_connectivity / split_mesh_data_by_cell_type imported from vtk_to_usd internals - Rewrite WorkflowConvertVTKToUSD.run() to call ConvertVTKToUSD.from_files() exclusively; update post-processing scan path from /World/Meshes to /World/{mesh_name} - Delete vtk_to_usd/converter.py (VTKToUSDConverter and helpers removed) - Remove VTKToUSDConverter / convert_vtk_file / convert_vtk_sequence from vtk_to_usd/__init__.py exports; update module docstring - Remove vtk_to_usd from physiomotion4d top-level __init__.py public API - Update three experiment scripts to use ConvertVTKToUSD.from_files() - Rewrite test_vtk_to_usd_library.py tests to use ConvertVTKToUSD; update all prim-path assertions from /World/Meshes/X to /World/X/Mesh - Regenerate docs/API_MAP.md https://claude.ai/code/session_01B16tgwah5XemvxzrGpzUZj * STYLE: Fix ruff formatting * FIX: Harden ConvertVTKToUSD input validation and label time-code alignment Validate time_codes length and non-decreasing order in from_files(); propagate extract_surface to convert_to_surface so surfaces are not extracted twice; align per-label time codes to the frames actually present rather than using the full series; use data_basename in static-merge prim names; remove dead up_axis/triangulate from WorkflowConvertVTKToUSD and its CLI; discover vessel prim dynamically in experiment scripts; add diffuseColor assertion to material test. * ENH: Cache topology-validation mesh data; always author time-varying prims Populate _cached_mesh_data in from_files() so _convert_unified() reuses the MeshData built during topology validation instead of converting VTK a second time. Remove the single-frame shortcut that called create_mesh(); create_time_varying_mesh() is now used unconditionally so every prim carries explicit time samples. Add 12 synthetic tests covering the cache (Gap B), time-codes validation (Gap A), single-frame time samples (Gap C), static-merge prim naming (Gap E), and mask_ids label filtering (Gap D).
1 parent debdcb0 commit 7523ff3

12 files changed

Lines changed: 770 additions & 1197 deletions

docs/API_MAP.md

Lines changed: 65 additions & 62 deletions
Large diffs are not rendered by default.

experiments/Convert_VTK_To_USD/convert_chop_alterra_valve_to_usd.py

Lines changed: 36 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,11 @@
3737
# Import USDTools for post-processing colormap
3838
from physiomotion4d.usd_tools import USDTools
3939

40-
# Import the vtk_to_usd library
41-
from physiomotion4d.vtk_to_usd import (
42-
ConversionSettings,
43-
MaterialData,
44-
VTKToUSDConverter,
45-
cell_type_name_for_vertex_count,
46-
read_vtk_file,
47-
validate_time_series_topology,
48-
)
40+
from physiomotion4d import ConvertVTKToUSD
41+
42+
# cell_type_name_for_vertex_count and read_vtk_file are internal APIs used for diagnostics
43+
from physiomotion4d.vtk_to_usd import cell_type_name_for_vertex_count
44+
from physiomotion4d.vtk_to_usd.vtk_reader import read_vtk_file
4945

5046
# %% [markdown]
5147
# ## 1. Discover and Organize Time-Series Files
@@ -71,25 +67,10 @@
7167
colormap_range_min = 25
7268
colormap_range_max = 200
7369

74-
conversion_settings = ConversionSettings(
75-
triangulate_meshes=True,
76-
compute_normals=False, # Use existing normals if available
77-
preserve_point_arrays=True,
78-
preserve_cell_arrays=True,
79-
separate_objects_by_cell_type=False,
80-
separate_objects_by_connectivity=True, # Essential for alterra vtk file
81-
up_axis="Y",
82-
times_per_second=60.0, # 60 FPS for smooth animation
83-
use_time_samples=True,
84-
)
85-
86-
stent_material = MaterialData(
87-
name="Alterra_valve",
88-
diffuse_color=(0.5, 0.5, 0.5),
89-
roughness=0.4,
90-
metallic=0.9,
91-
use_vertex_colors=False,
92-
)
70+
# Conversion parameters
71+
separate_by = "connectivity" # Essential for alterra vtk file
72+
times_per_second = 60.0
73+
solid_color = (0.5, 0.5, 0.5)
9374

9475
# %%
9576
output_dir.mkdir(parents=True, exist_ok=True)
@@ -155,8 +136,6 @@
155136
# ## 3. Convert TPV25
156137

157138
# %%
158-
converter = VTKToUSDConverter(conversion_settings)
159-
160139
alterra_files = [file_path for _, file_path in alterra_series]
161140
alterra_times = [float(time_step) for time_step, _ in alterra_series]
162141

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

171-
# Read MeshData
172-
mesh_data_sequence = [read_vtk_file(f, extract_surface=True) for f in alterra_files]
173-
174-
# Validate topology consistency across time series
175-
validation_report = validate_time_series_topology(
176-
mesh_data_sequence, filenames=alterra_files
177-
)
178-
if not validation_report["is_consistent"]:
179-
print(
180-
f"Warning: Found {len(validation_report['warnings'])} topology/primvar issues"
181-
)
182-
if validation_report["topology_changes"]:
183-
print(
184-
f" Topology changes in {len(validation_report['topology_changes'])} frames"
185-
)
186-
187-
# Convert to USD (preserves all primvars from VTK)
188-
stage = converter.convert_mesh_data_sequence(
189-
mesh_data_sequence=mesh_data_sequence,
190-
output_usd=output_usd,
191-
mesh_name="AlterraValve",
150+
# topology validation and conversion happen inside from_files()
151+
stage = ConvertVTKToUSD.from_files(
152+
data_basename="AlterraValve",
153+
vtk_files=alterra_files,
154+
extract_surface=True,
155+
separate_by=separate_by,
156+
times_per_second=times_per_second,
157+
solid_color=solid_color,
192158
time_codes=alterra_times,
193-
material=stent_material,
194-
)
159+
).convert(str(output_usd))
195160

196161
# %%
197162
usd_tools = USDTools()
198-
if conversion_settings.separate_objects_by_connectivity is True:
199-
vessel_path = "/World/Meshes/AlterraValve_object3"
200-
elif conversion_settings.separate_objects_by_cell_type is True:
201-
vessel_path = "/World/Meshes/AlterraValve_triangle1"
163+
# ConvertVTKToUSD places prims at /World/{basename}/{part_name}.
164+
# Discover the target prim dynamically so the path stays valid regardless
165+
# of how many connected components or cell types the VTK file produces.
166+
if separate_by == "connectivity":
167+
mesh_paths = usd_tools.list_mesh_paths_under(
168+
stage, parent_path="/World/AlterraValve"
169+
)
170+
candidates = [
171+
p for p in mesh_paths if p.split("/")[-1].startswith("AlterraValve_object")
172+
]
173+
vessel_path = candidates[-1] if candidates else "/World/AlterraValve/Mesh"
174+
elif separate_by == "cell_type":
175+
mesh_paths = usd_tools.list_mesh_paths_under(
176+
stage, parent_path="/World/AlterraValve"
177+
)
178+
triangle_paths = [p for p in mesh_paths if p.split("/")[-1].endswith("_Triangle")]
179+
vessel_path = triangle_paths[0] if triangle_paths else "/World/AlterraValve/Mesh"
202180
else:
203-
vessel_path = "/World/Meshes/AlterraValve"
181+
vessel_path = "/World/AlterraValve/Mesh"
204182

205183
# Select primvar for coloring
206184
primvars = usd_tools.list_mesh_primvars(str(output_usd), vessel_path)

experiments/Convert_VTK_To_USD/convert_chop_tpv25_valve_to_usd.py

Lines changed: 32 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,11 @@
3636
# Import USDTools for post-processing colormap
3737
from physiomotion4d.usd_tools import USDTools
3838

39-
# Import the vtk_to_usd library
40-
from physiomotion4d.vtk_to_usd import (
41-
ConversionSettings,
42-
MaterialData,
43-
VTKToUSDConverter,
44-
cell_type_name_for_vertex_count,
45-
read_vtk_file,
46-
validate_time_series_topology,
47-
)
39+
from physiomotion4d import ConvertVTKToUSD
40+
41+
# cell_type_name_for_vertex_count and read_vtk_file are internal APIs used for diagnostics
42+
from physiomotion4d.vtk_to_usd import cell_type_name_for_vertex_count
43+
from physiomotion4d.vtk_to_usd.vtk_reader import read_vtk_file
4844

4945
# %% [markdown]
5046
# ## 1. Discover and Organize Time-Series Files
@@ -70,25 +66,10 @@
7066
colormap_range_min = 25
7167
colormap_range_max = 200
7268

73-
conversion_settings = ConversionSettings(
74-
triangulate_meshes=True,
75-
compute_normals=False, # Use existing normals if available
76-
preserve_point_arrays=True,
77-
preserve_cell_arrays=True,
78-
separate_objects_by_cell_type=False,
79-
separate_objects_by_connectivity=True, # Essential for tpv25 vtk file
80-
up_axis="Y",
81-
times_per_second=60.0, # 60 FPS for smooth animation
82-
use_time_samples=True,
83-
)
84-
85-
stent_material = MaterialData(
86-
name="tpv25_valve",
87-
diffuse_color=(0.5, 0.5, 0.5),
88-
roughness=0.4,
89-
metallic=0.9,
90-
use_vertex_colors=False,
91-
)
69+
# Conversion parameters
70+
separate_by = "connectivity" # Essential for tpv25 vtk file
71+
times_per_second = 60.0
72+
solid_color = (0.5, 0.5, 0.5)
9273

9374
# %%
9475
output_dir.mkdir(parents=True, exist_ok=True)
@@ -154,8 +135,6 @@
154135
# ## 3. Convert TPV25
155136

156137
# %%
157-
converter = VTKToUSDConverter(conversion_settings)
158-
159138
tpv25_files = [file_path for _, file_path in tpv25_series]
160139
tpv25_times = [float(time_step) for time_step, _ in tpv25_series]
161140

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

170-
# Read MeshData
171-
mesh_data_sequence = [read_vtk_file(f, extract_surface=True) for f in tpv25_files]
172-
173-
# Validate topology consistency across time series
174-
validation_report = validate_time_series_topology(
175-
mesh_data_sequence, filenames=tpv25_files
176-
)
177-
if not validation_report["is_consistent"]:
178-
print(
179-
f"Warning: Found {len(validation_report['warnings'])} topology/primvar issues"
180-
)
181-
if validation_report["topology_changes"]:
182-
print(
183-
f" Topology changes in {len(validation_report['topology_changes'])} frames"
184-
)
185-
186-
# Convert to USD (preserves all primvars from VTK)
187-
stage = converter.convert_mesh_data_sequence(
188-
mesh_data_sequence=mesh_data_sequence,
189-
output_usd=output_usd,
190-
mesh_name="TPV25Valve",
149+
# topology validation and conversion happen inside from_files()
150+
stage = ConvertVTKToUSD.from_files(
151+
data_basename="TPV25Valve",
152+
vtk_files=tpv25_files,
153+
extract_surface=True,
154+
separate_by=separate_by,
155+
times_per_second=times_per_second,
156+
solid_color=solid_color,
191157
time_codes=tpv25_times,
192-
material=stent_material,
193-
)
158+
).convert(str(output_usd))
194159

195160
# %%
196161
usd_tools = USDTools()
197-
if conversion_settings.separate_objects_by_connectivity is True:
198-
vessel_path = "/World/Meshes/TPV25Valve_object4"
199-
elif conversion_settings.separate_objects_by_cell_type is True:
200-
vessel_path = "/World/Meshes/TPV25Valve_triangle1"
162+
# ConvertVTKToUSD places prims at /World/{basename}/{part_name}.
163+
# Discover the target prim dynamically so the path stays valid regardless
164+
# of how many connected components or cell types the VTK file produces.
165+
if separate_by == "connectivity":
166+
mesh_paths = usd_tools.list_mesh_paths_under(stage, parent_path="/World/TPV25Valve")
167+
candidates = [
168+
p for p in mesh_paths if p.split("/")[-1].startswith("TPV25Valve_object")
169+
]
170+
vessel_path = candidates[-1] if candidates else "/World/TPV25Valve/Mesh"
171+
elif separate_by == "cell_type":
172+
mesh_paths = usd_tools.list_mesh_paths_under(stage, parent_path="/World/TPV25Valve")
173+
triangle_paths = [p for p in mesh_paths if p.split("/")[-1].endswith("_Triangle")]
174+
vessel_path = triangle_paths[0] if triangle_paths else "/World/TPV25Valve/Mesh"
201175
else:
202-
vessel_path = "/World/Meshes/TPV25Valve"
176+
vessel_path = "/World/TPV25Valve/Mesh"
203177

204178
# Select primvar for coloring
205179
primvars = usd_tools.list_mesh_primvars(str(output_usd), vessel_path)

0 commit comments

Comments
 (0)