Volumes#

Volume adapters connect discrete 3D grids (simulation output, CT/MRI, or other VDB-backed data) to OpenVCAD’s continuous sampling model. Instead of baking data into dense meshes, you keep a sparse OpenVDB grid and query it at any world-space point. Sampling uses trilinear interpolation between voxel centers, so fields stay smooth for rendering, slicing, and compilers.

Typical uses include mapping Hounsfield units or bone density to material properties, reusing FEA or fluid fields on printable geometry, and importing artist-authored VDBs from external tools.

Interface you use in Python

  • Typed volumesFloatVolume, Vec2sVolume, Vec3sVolume, and Vec4sVolume wrap scalar or vector VDB grids. Call sample(x, y, z) for a value, bounding_box() for world-space bounds, and clone() when you need a thread-safe copy for concurrent evaluation.

  • VDB files — Use pyvcad.vdb_loader (load_float_volume, load_vec3s_volume, load_vec4s_volume) to open a named grid from a .vdb file, optionally centered on the origin.

  • DICOM stacksDICOMLoader reads a directory of slices, applies real-world spacing and rescale metadata where available, and builds a scalar FloatVolume (commonly HU). Call as_volume() when you are ready to sample.

  • Attributes — A FloatVolume is a continuous field; pass it to FloatAttribute(volume) (or set_volume on an existing FloatAttribute) and attach that attribute to geometry with set_attribute, same as expression-driven fields. Evaluation runs where your solid exists, using the volume’s values inside the part.

Examples#

The patterns below mirror the getting-started discussion of sampled scalar fields: load data, wrap in FloatAttribute, attach to a primitive or mesh.

VDB scalar grid

import pyvcad as pv

vol = pv.vdb_loader.load_float_volume("model.vdb", "density")
bbox_min, bbox_max = vol.bounding_box()
solid = pv.RectPrism.FromMinAndMax(bbox_min, bbox_max)
solid.set_attribute(pv.DefaultAttributes.DENSITY, pv.FloatAttribute(vol))

DICOM series → float volume

import pyvcad as pv

loader = pv.DICOMLoader("path/to/dicom_series")
vol = loader.as_volume()
solid = pv.RectPrism.FromMinAndMax(*vol.bounding_box())
solid.set_attribute(pv.DefaultAttributes.HU, pv.FloatAttribute(vol))

Volume types#

class pyvcad.FloatVolume#

A VDB volume storing scalar float values.

__init__(*args, **kwargs)#

Overloaded function.

  1. __init__(self: pyvcad.pyvcad.FloatVolume) -> None

Constructor. Creates an empty FloatVDBVolume.

  1. __init__(self: pyvcad.pyvcad.FloatVolume, grid: openvdb::v13_0::Grid<openvdb::v13_0::tree::Tree<openvdb::v13_0::tree::RootNode<openvdb::v13_0::tree::InternalNode<openvdb::v13_0::tree::InternalNode<openvdb::v13_0::tree::LeafNode<float, 3u>, 4u>, 5u>>>>, center: bool = False) -> None

Constructor. Creates a FloatVDBVolume from an existing grid.

Parameters:
  • grid (FloatGrid) – The OpenVDB grid to use.

  • center (bool) – If True, centers the volume about the origin. Defaults to False.

bounding_box(self: pyvcad.pyvcad.FloatVolume) tuple[pyvcad.pyvcad.Vec3, pyvcad.pyvcad.Vec3]#

Get the world space bounding box of the volume.

Returns:

The minimum and maximum coordinates.

Return type:

tuple[Vec3, Vec3]

clone(self: pyvcad.pyvcad.FloatVolume) pyvcad.pyvcad.FloatVolume#

Create a thread-safe clone of this volume.

Returns:

A cloned volume instance.

Return type:

FloatVolume

grid_type(self: pyvcad.pyvcad.FloatVolume) str#

Get the grid type name.

Returns:

The grid type name.

Return type:

str

sample(self: pyvcad.pyvcad.FloatVolume, x: SupportsFloat, y: SupportsFloat, z: SupportsFloat) float#

Sample the volume at the given coordinates.

Parameters:
  • x (float) – X coordinate.

  • y (float) – Y coordinate.

  • z (float) – Z coordinate.

Returns:

The sampled value.

Return type:

float

class pyvcad.Vec2sVolume#

A VDB volume storing 2D vector values with single precision.

__init__(self: pyvcad.pyvcad.Vec2sVolume) None#

Constructor. Creates an empty Vec2sVDBVolume.

bounding_box(self: pyvcad.pyvcad.Vec2sVolume) tuple[pyvcad.pyvcad.Vec3, pyvcad.pyvcad.Vec3]#

Get the world space bounding box of the volume.

Returns:

The minimum and maximum coordinates.

Return type:

tuple[Vec3, Vec3]

clone(self: pyvcad.pyvcad.Vec2sVolume) pyvcad.pyvcad.Vec2sVolume#

Create a thread-safe clone of this volume.

Returns:

A cloned volume instance.

Return type:

Vec2sVolume

grid_type(self: pyvcad.pyvcad.Vec2sVolume) str#

Get the grid type name.

Returns:

The grid type name.

Return type:

str

sample(self: pyvcad.pyvcad.Vec2sVolume, x: SupportsFloat, y: SupportsFloat, z: SupportsFloat) pyvcad.pyvcad.Vec2#

Sample the volume at the given coordinates.

Parameters:
  • x (float) – X coordinate.

  • y (float) – Y coordinate.

  • z (float) – Z coordinate.

Returns:

The sampled 2D vector value.

Return type:

Vec2

class pyvcad.Vec3sVolume#

A VDB volume storing 3D vector values with single precision.

__init__(*args, **kwargs)#

Overloaded function.

  1. __init__(self: pyvcad.pyvcad.Vec3sVolume) -> None

Constructor. Creates an empty Vec3sVDBVolume.

  1. __init__(self: pyvcad.pyvcad.Vec3sVolume, grid: openvdb::v13_0::Grid<openvdb::v13_0::tree::Tree<openvdb::v13_0::tree::RootNode<openvdb::v13_0::tree::InternalNode<openvdb::v13_0::tree::InternalNode<openvdb::v13_0::tree::LeafNode<openvdb::v13_0::math::Vec3<float>, 3u>, 4u>, 5u>>>>, center: bool = False) -> None

Constructor. Creates a Vec3sVDBVolume from an existing grid.

Parameters:
  • grid (Vec3SGrid) – The OpenVDB grid to use.

  • center (bool) – If True, centers the volume about the origin. Defaults to False.

bounding_box(self: pyvcad.pyvcad.Vec3sVolume) tuple[pyvcad.pyvcad.Vec3, pyvcad.pyvcad.Vec3]#

Get the world space bounding box of the volume.

Returns:

The minimum and maximum coordinates.

Return type:

tuple[Vec3, Vec3]

clone(self: pyvcad.pyvcad.Vec3sVolume) pyvcad.pyvcad.Vec3sVolume#

Create a thread-safe clone of this volume.

Returns:

A cloned volume instance.

Return type:

Vec3sVolume

grid_type(self: pyvcad.pyvcad.Vec3sVolume) str#

Get the grid type name.

Returns:

The grid type name.

Return type:

str

sample(self: pyvcad.pyvcad.Vec3sVolume, x: SupportsFloat, y: SupportsFloat, z: SupportsFloat) pyvcad.pyvcad.Vec3#

Sample the volume at the given coordinates.

Parameters:
  • x (float) – X coordinate.

  • y (float) – Y coordinate.

  • z (float) – Z coordinate.

Returns:

The sampled 3D vector value.

Return type:

Vec3

class pyvcad.Vec4sVolume#

A VDB volume storing 4D vector values with single precision.

__init__(self: pyvcad.pyvcad.Vec4sVolume) None#

Constructor. Creates an empty Vec4sVDBVolume.

bounding_box(self: pyvcad.pyvcad.Vec4sVolume) tuple[pyvcad.pyvcad.Vec3, pyvcad.pyvcad.Vec3]#

Get the world space bounding box of the volume.

Returns:

The minimum and maximum coordinates.

Return type:

tuple[Vec3, Vec3]

clone(self: pyvcad.pyvcad.Vec4sVolume) pyvcad.pyvcad.Vec4sVolume#

Create a thread-safe clone of this volume.

Returns:

A cloned volume instance.

Return type:

Vec4sVolume

grid_type(self: pyvcad.pyvcad.Vec4sVolume) str#

Get the grid type name.

Returns:

The grid type name.

Return type:

str

sample(self: pyvcad.pyvcad.Vec4sVolume, x: SupportsFloat, y: SupportsFloat, z: SupportsFloat) pyvcad.pyvcad.Vec4#

Sample the volume at the given coordinates.

Parameters:
  • x (float) – X coordinate.

  • y (float) – Y coordinate.

  • z (float) – Z coordinate.

Returns:

The sampled 4D vector value.

Return type:

Vec4

Loaders#

class pyvcad.DICOMLoader#

A loader for DICOM image stacks that converts them to VDB volumes.

__init__(self: pyvcad.pyvcad.DICOMLoader, directory: str, center: bool = False, rescale_slope: SupportsFloat = -inf, rescale_intercept: SupportsFloat = -inf, slice_thickness: SupportsFloat = -inf, x_pixel_spacing: SupportsFloat = -inf, y_pixel_spacing: SupportsFloat = -inf) None#

Constructor. Creates a DICOMLoader for loading DICOM image stacks.

Parameters:
  • directory (str) – The directory containing the DICOM stack.

  • center (bool, optional) – Whether to center the volume at the origin. Default is false.

  • rescale_slope (double, optional) – The rescale slope to apply to pixel values.

  • rescale_intercept (double, optional) – The rescale intercept to apply to pixel values.

  • slice_thickness (double, optional) – The slice thickness in mm.

  • x_pixel_spacing (double, optional) – The pixel spacing in x direction in mm.

  • y_pixel_spacing (double, optional) – The pixel spacing in y direction in mm.

as_volume(self: pyvcad.pyvcad.DICOMLoader) pyvcad.pyvcad.FloatVolume#

Convert the loaded DICOM stack to a VDB volume.

Returns:

The resulting VDB volume.

Return type:

FloatVDBVolume

get_bounding_box(self: pyvcad.pyvcad.DICOMLoader) tuple[pyvcad.pyvcad.Vec3, pyvcad.pyvcad.Vec3]#

Get the axis-aligned bounding box of the loaded DICOM volume in mm.

Returns:

A tuple containing two glm.vec3 vectors representing the minimum and maximum corners of the bounding box ((min_x, min_y, min_z), (max_x, max_y, max_z)).

Return type:

tuple

get_dimensions(self: pyvcad.pyvcad.DICOMLoader) pyvcad.pyvcad.Vec3#

Get the physical dimensions of the loaded DICOM volume in mm.

Returns:

A vector containing the dimensions in x, y, and z directions (x_dim, y_dim, z_dim).

Return type:

glm.vec3

get_min_max_hu(self: pyvcad.pyvcad.DICOMLoader) tuple[float, float]#

Get the minimum and maximum Hounsfield Unit (HU) values in the loaded DICOM volume.

Returns:

A tuple containing the minimum and maximum HU values (min_hu, max_hu).

Return type:

tuple

get_rescale_intercept(self: pyvcad.pyvcad.DICOMLoader) float#

Get the rescale intercept used for converting pixel values to Hounsfield Units (HU).

Returns:

The rescale intercept.

Return type:

double

get_rescale_slope(self: pyvcad.pyvcad.DICOMLoader) float#

Get the rescale slope used for converting pixel values to Hounsfield Units (HU).

Returns:

The rescale slope.

Return type:

double

get_voxel_size(self: pyvcad.pyvcad.DICOMLoader) pyvcad.pyvcad.Vec3#

Get the voxel size of the loaded DICOM volume in mm.

Returns:

A vector containing the voxel size in x, y, and z directions (x_size, y_size, z_size).

Return type:

glm.vec3

pyvcad.vdb_loader#

VDB file loading utilities