@@ -107,20 +107,40 @@ def rasterize_skull(outer_mesh, inner_mesh, dx_mm: float = 1.0,
107107 # Rasterize using trimesh containment checks
108108 log .info ("Rasterizing skull to %s grid (dx=%.1f mm)..." , shape , dx_mm )
109109
110- # Build query points (subsample if too large)
111- xx , yy , zz = np .meshgrid (* [v for _ , _ , v in axes ], indexing = "ij" )
112- points = np .column_stack ([xx .ravel (), yy .ravel (), zz .ravel ()])
113-
114- log .info (" Checking %d points against outer mesh..." , len (points ))
115- inside_outer = outer_mesh .contains (points )
116- log .info (" Checking %d points against inner mesh..." , len (points ))
117- inside_inner = inner_mesh .contains (points )
110+ # Use trimesh voxelization — much faster than per-point containment
111+ pitch = dx_mm
112+ log .info (" Voxelizing outer mesh (pitch=%.1f mm)..." , pitch )
113+ outer_filled = outer_mesh .voxelized (pitch ).fill ()
114+ log .info (" Voxelizing inner mesh..." )
115+ inner_filled = inner_mesh .voxelized (pitch ).fill ()
118116
119117 labels = np .zeros (shape , dtype = np .int32 )
120- labels_flat = labels .ravel ()
121- labels_flat [inside_outer & ~ inside_inner ] = 2 # skull
122- labels_flat [inside_inner ] = 4 # brain
123- labels = labels_flat .reshape (shape )
118+
119+ def _map_voxels_to_grid (voxel_grid , grid_mins , grid_shape , dx ):
120+ """Map trimesh VoxelGrid boolean matrix to our coordinate grid."""
121+ matrix = voxel_grid .matrix
122+ origin = voxel_grid .transform [:3 , 3 ]
123+ # Voxel indices where the mesh is filled
124+ filled_ijk = np .argwhere (matrix ) # (N, 3)
125+ # Convert to world coordinates
126+ world = origin + filled_ijk * dx
127+ # Convert to our grid indices
128+ grid_ijk = np .round ((world - grid_mins ) / dx ).astype (int )
129+ # Clip to valid range
130+ valid = np .all ((grid_ijk >= 0 ) & (grid_ijk < grid_shape ), axis = 1 )
131+ return grid_ijk [valid ]
132+
133+ inner_idx = _map_voxels_to_grid (inner_filled , mins , shape , dx_mm )
134+ outer_idx = _map_voxels_to_grid (outer_filled , mins , shape , dx_mm )
135+
136+ # Brain = inside inner mesh
137+ if len (inner_idx ) > 0 :
138+ labels [inner_idx [:, 0 ], inner_idx [:, 1 ], inner_idx [:, 2 ]] = 4
139+ # Skull = inside outer but not inside inner
140+ if len (outer_idx ) > 0 :
141+ outer_mask = labels [outer_idx [:, 0 ], outer_idx [:, 1 ], outer_idx [:, 2 ]] != 4
142+ skull_idx = outer_idx [outer_mask ]
143+ labels [skull_idx [:, 0 ], skull_idx [:, 1 ], skull_idx [:, 2 ]] = 2
124144
125145 n_water = np .sum (labels == 0 )
126146 n_skull = np .sum (labels == 2 )
0 commit comments