DeepSDFStruct.SDF#

Signed Distance Function (SDF) Base Classes and Operations#

This module provides the foundational classes and utilities for working with Signed Distance Functions (SDFs) in DeepSDFStruct. SDFs are implicit geometric representations that encode the distance from any point in space to the nearest surface, with the sign indicating whether the point is inside (negative) or outside (positive) the geometry.

Key Features#

SDFBase Abstract Class

Base class for all SDF representations with support for: - Spline-based geometric deformations - Spatially-varying parametrization - Boundary conditions and capping - Boolean operations (union, intersection) - Differentiable operations for optimization

SDFfromMesh

Convert triangular surface meshes to SDF representations using fast winding number algorithms for robust inside/outside testing.

SDFfromDeepSDF

Neural network-based SDF using trained DeepSDF models for complex, learned geometric representations.

Union and Intersection

Combine multiple SDFs using smooth boolean operations with configurable smoothing for differentiable geometry.

Utility Functions
  • Grid sampling for SDF evaluation

  • Gradient computation for normal vectors

  • Boundary condition application

The module enables flexible construction and manipulation of complex 3D geometries in a differentiable framework suitable for optimization, simulation, and machine learning applications.

Examples

Create and evaluate an SDF from a mesh:

import trimesh
from DeepSDFStruct.SDF import SDFfromMesh

mesh = trimesh.load('model.stl')
sdf = SDFfromMesh(mesh)

# Query SDF values
points = torch.rand(1000, 3)
distances = sdf(points)

Combine SDFs with boolean operations:

from DeepSDFStruct.sdf_primitives import SphereSDF
from DeepSDFStruct.SDF import Union

sphere1 = SphereSDF([0, 0, 0], radius=1.0)
sphere2 = SphereSDF([1, 0, 0], radius=1.0)
combined = Union([sphere1, sphere2], smoothing=0.1)

Functions

generate_plane_points(origin, normal, res, ...)

Generate evenly spaced points on a plane in 3D space.

get_equidistant_grid_sample(bounds, grid_spacing)

Generates an equidistant 3D grid of points within the given bounding box.

normalize_mesh_to_unit_cube(mesh[, ...])

Transform mesh coordinates uniformly to [-1, 1] in all axes.

point_segment_distance(P1, P2, query_points)

Calculates the minimum distance from one or more query points to one or more line segments defined by endpoints P1 and P2.

project_bounds(origin, normal[, bounds])

Project 3D AABB bounds onto a slice plane and return 2D limits.

union_numpy(D[, k])

D: np.array of shape (num_points, num_geometries) k: smoothness parameter

union_torch(D[, k])

D: np.array of shape (num_points, num_geometries) k: smoothness parameter

Classes

BoxSDF([box_size, center])

CapBorderDict

A dictionary type describing boundary conditions ("caps") for each axis direction (x, y, z).

CapType

CappedBorderSDF(sdf[, cap_border_dict, scale])

Applies planar boundary caps to another SDF.

DifferenceSDF(base_obj, *subtract_objs)

Subtracts multiple objects from a base object.

ExtrudeSDF(sdf_2d, height)

Extrudes a 2D SDF into a 3D shape.

NegatedCallable(obj)

SDF2D(obj, axes[, offset])

Convert a 3D SDF to 2D by slicing through specified axes.

SDFBase([parametrization, geometric_dim])

Abstract base class for Signed Distance Functions with optional deformation and parametrization.

SDFfromDeepSDF(model[, max_batch])

Signed distance function from a trained DeepSDF neural network model.

SDFfromLineMesh(line_mesh, thickness[, ...])

Signed distance function from a line mesh (collection of line segments).

SDFfromMesh(mesh[, dtype, flip_sign, scale, ...])

Create an SDF from a triangle mesh using closest-point queries.

SmoothDifferenceSDF(base_sdf, *subtract_sdfs)

Smooth subtraction of SDFs.

SmoothIntersectionSDF(*sdfs[, k])

Smooth intersection of multiple SDFs with smoothing parameter k.

SmoothUnionSDF(*sdfs[, k])

Smooth blending of multiple SDFs with smoothing parameter k.

SummedSDF(obj1, obj2)

TransformedSDF(sdf[, rotationMatrix, ...])

Generic SDF wrapper that applies a transformation to the input queries.

UnionSDF(*objects)

Union of multiple SDFs using the minimum operator.

class DeepSDFStruct.SDF.BoxSDF(box_size=1, center=tensor([0, 0, 0]))#

Bases: DeepSDFStruct.SDF.SDFBase

Parameters:
  • box_size (float)

  • center (torch._VariableFunctionsClass.tensor)

class DeepSDFStruct.SDF.CapBorderDict#

Bases: TypedDict

A dictionary type describing boundary conditions (“caps”) for each axis direction (x, y, z).

Each key (x0, x1, y0, y1, z0, z1) corresponds to one boundary face of a 3D domain, and maps to a dictionary with two fields:

  • cap (int): Type of cap applied (e.g., -1 = none, 1 = active).

  • measure (float): Numerical measure associated with the cap (e.g., thickness, scaling factor, tolerance).

Example

>>> caps: CapBorderDict = {
...     "x0": {"cap": 1, "measure": 0.02},
...     "x1": {"cap": 1, "measure": 0.02},
...     "y0": {"cap": 1, "measure": 0.02},
...     "y1": {"cap": 1, "measure": 0.02},
...     "z0": {"cap": 1, "measure": 0.02},
...     "z1": {"cap": 1, "measure": 0.02},
... }
x0: DeepSDFStruct.SDF.CapType = {'cap': -1, 'measure': 0}#
x1: DeepSDFStruct.SDF.CapType = {'cap': -1, 'measure': 0}#
y0: DeepSDFStruct.SDF.CapType = {'cap': -1, 'measure': 0}#
y1: DeepSDFStruct.SDF.CapType = {'cap': -1, 'measure': 0}#
z0: DeepSDFStruct.SDF.CapType = {'cap': -1, 'measure': 0}#
z1: DeepSDFStruct.SDF.CapType = {'cap': -1, 'measure': 0}#
class DeepSDFStruct.SDF.CapType#

Bases: TypedDict

cap: int#
measure: float#
class DeepSDFStruct.SDF.CappedBorderSDF(sdf, cap_border_dict=None, scale=(1, 1, 1))#

Bases: DeepSDFStruct.SDF.SDFBase

Applies planar boundary caps to another SDF.

Parameters:
cap_border_dict: DeepSDFStruct.SDF.CapBorderDict#
class DeepSDFStruct.SDF.DifferenceSDF(base_obj, *subtract_objs)#

Bases: DeepSDFStruct.SDF.SDFBase

Subtracts multiple objects from a base object.

Computes:

obj0 - (obj1 ∪ obj2 ∪ …)

i.e.

max(d0, -min(d1, d2, …))

Parameters:
class DeepSDFStruct.SDF.ExtrudeSDF(sdf_2d, height)#

Bases: DeepSDFStruct.SDF.SDFBase

Extrudes a 2D SDF into a 3D shape.

Parameters:
class DeepSDFStruct.SDF.NegatedCallable(obj)#

Bases: DeepSDFStruct.SDF.SDFBase

Parameters:

obj (DeepSDFStruct.SDF.SDFBase)

class DeepSDFStruct.SDF.SDF2D(obj, axes, offset=0.0)#

Bases: DeepSDFStruct.SDF.SDFBase

Convert a 3D SDF to 2D by slicing through specified axes.

Creates a 2D SDF by taking a cross-section of a 3D SDF along specified axes at a given offset. This is useful for visualizing 3D SDFs or working with 2D profiles.

Parameters:
  • obj (SDFBase) – The 3D SDF object to convert to 2D.

  • axes (list of int) – List of two axis indices [axis0, axis1] to keep for the 2D slice. For example, [0, 1] keeps x and y axes (XY plane).

  • offset (float, default 0.0) – Offset value for the third (unused) axis.

  • Examples

  • SphereSDF(center=[0 (>>> sphere_3d =)

  • 0

  • 0]

  • radius=1.0)

  • >>>

  • z=0) (>>> # Convert to 2D (XY plane at)

  • sphere_3d.to2D(axes=[0 (>>> sphere_2d =)

  • 1]

  • offset=0.0)

  • torch.tensor([[0.0 (>>> points =)

  • 0.0]

  • [0.5

  • 0.5]])

  • sphere_2d(points) (>>> distances =)

Notes

The 2D SDF queries points in the plane defined by the two axes, with the third axis fixed at the offset value.

obj: DeepSDFStruct.SDF.SDFBase#
class DeepSDFStruct.SDF.SDFBase(parametrization=None, geometric_dim=3)#

Bases: torch.nn.modules.module.Module, abc.ABC

Abstract base class for Signed Distance Functions with optional deformation and parametrization.

This class provides the foundation for all SDF representations in DeepSDFStruct. SDFs represent geometry as an implicit function that returns the signed distance from any query point to the nearest surface. Negative values indicate points inside the geometry, positive values indicate points outside, and zero indicates points on the surface.

The class supports: - Optional spline-based deformations for smooth transformations - Parametrization functions for spatially-varying properties - Composition operations (union, intersection) via overloading

Parameters:
  • parametrization (torch.nn.Module, optional) – A function that provides spatially-varying parameters for the SDF (e.g., varying thickness in a lattice).

  • geometric_dim (int, default 3) – Geometric dimension of the SDF (2 or 3).

Notes

Subclasses must implement: - _compute(queries): Calculate SDF values for query points - _get_domain_bounds(): Return the bounding box of geometry

Examples

>>> from DeepSDFStruct.sdf_primitives import SphereSDF
>>> import torch
>>>
>>> # Create a sphere SDF
>>> sphere = SphereSDF(center=[0, 0, 0], radius=1.0)
>>>
>>> # Query SDF values
>>> points = torch.tensor([[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]])
>>> distances = sphere(points)
>>> print(distances)  # [-1.0, 1.0] (inside, outside)
forward(queries)#

Evaluate the SDF at given query points.

This method validates input, computes SDF values using the subclass implementation, and applies optional boundary conditions and capping.

Parameters:

queries (torch.Tensor) – Query points of shape (N, 2) for 2D or (N, 3) for 3D, where N is the number of points to evaluate.

Returns:

Signed distance values of shape (N, 1). Negative values indicate points inside the geometry, positive values outside.

Return type:

torch.Tensor

Raises:
  • ValueError – If queries have invalid shape.

  • RuntimeError – If SDF computation returns invalid output.

geometric_dim: int#
get_device()#

Return the device of the first parameter or buffer in this module.

If the module has no parameters and no buffers, returns cpu.

get_dtype()#

Return the dtype of the first parameter or buffer in this module.

If the module has no parameters and no buffers, returns float32.

plot_slice(origin=(0, 0, 0), normal=(0, 0, 1), res=(100, 100), ax=None, clim=(-1, 1), cmap='seismic', show_zero_level=True, deformation_function=None)#

Plot a 2D slice through an SDF as a contour plot.

This function evaluates an SDF on a planar grid and visualizes the signed distance values using a color map. The zero level set (the actual surface) can be highlighted with a contour line.

Parameters:
  • fun (callable) – The SDF function to visualize. Should accept a torch.Tensor of shape (N, 3) and return distances of shape (N, 1).

  • origin (tuple of float, default (0, 0, 0)) – A point on the slice plane.

  • normal (tuple of float, default (0, 0, 1)) – Normal vector of the slice plane. Currently supports only axis-aligned planes: (1,0,0), (0,1,0), or (0,0,1).

  • res (tuple of int, default (100, 100)) – Resolution of the slice grid (num_points_u, num_points_v).

  • ax (matplotlib.axes.Axes, optional) – Axes to plot on. If None, creates a new figure.

  • xlim (tuple of float, default (-1, 1)) – Range along the first plane axis.

  • ylim (tuple of float, default (-1, 1)) – Range along the second plane axis.

  • clim (tuple of float, default (-1, 1)) – Color map limits for distance values.

  • cmap (str, default 'seismic') – Matplotlib colormap name.

  • show_zero_level (bool, default True) – If True, draws a black contour line at distance=0 (the surface).

  • deformation_function (callable, optional) – Deformation mapping from parametric to physical space. If given, sample points are deformed before SDF evaluation and plotting.

Returns:

fig, ax – Only returned if ax was None (i.e., a new figure was created).

Return type:

matplotlib.figure.Figure, matplotlib.axes.Axes

Examples

>>> from DeepSDFStruct.sdf_primitives import SphereSDF
>>> from DeepSDFStruct.plotting import plot_slice
>>> import matplotlib.pyplot as plt
>>>
>>> # Create a sphere
>>> sphere = SphereSDF(center=[0, 0, 0], radius=0.5)
>>>
>>> # Plot XY slice at z=0
>>> fig, ax = plot_slice(
...     sphere,
...     origin=(0, 0, 0),
...     normal=(0, 0, 1),
...     res=(200, 200)
... )
>>> plt.title("XY Slice of Sphere")
>>> plt.show()

Notes

The ‘seismic’ colormap is well-suited for SDFs as it uses blue for negative (inside) and red for positive (outside), with white near zero.

to2D(axes, offset=0.0)#

Converts SDF to 2D

Parameters:
  • axis – list of axes that will be used for the 2D

  • axes (list[int])

class DeepSDFStruct.SDF.SDFfromDeepSDF(model, max_batch=32768)#

Bases: DeepSDFStruct.SDF.SDFBase

Signed distance function from a trained DeepSDF neural network model.

Wraps a trained DeepSDF model to provide SDF queries. The model uses latent vectors to condition the SDF on specific shapes from a learned distribution.

Parameters:
  • model (DeepSDFModel) – Trained DeepSDF model with decoder network.

  • max_batch (int, default 8192 (32**3)) – Maximum number of query points to process in a single batch. Useful for managing GPU memory when querying many points.

model#

The underlying DeepSDF model.

Type:

DeepSDFModel

latvec#

Latent vector(s) for conditioning. Can be set via set_latent_vec().

Type:

torch.Tensor or None

geometric_dim#

Geometric dimension (2 or 3) from the model’s decoder.

Type:

int

Examples

>>> from DeepSDFStruct.SDF import SDFfromDeepSDF
>>> from DeepSDFStruct.deep_sdf.models import DeepSDFModel
>>> import torch
>>>
>>> # Load a trained model
>>> model = DeepSDFModel.load_from_checkpoint("path/to/checkpoint")
>>> sdf = SDFfromDeepSDF(model)
>>>
>>> # Query the SDF
>>> points = torch.rand(1000, 3)
>>> distances = sdf(points)

Notes

The latent vector can be updated to query different shapes from the learned distribution using set_latent_vec().

set_latent_vec(latent_vec)#

Set conditioning parameters for the model (e.g., latent code).

Parameters:

latent_vec (torch.Tensor)

class DeepSDFStruct.SDF.SDFfromLineMesh(line_mesh, thickness, smoothness=0)#

Bases: DeepSDFStruct.SDF.SDFBase

Signed distance function from a line mesh (collection of line segments).

Creates an SDF by computing the minimum distance from query points to line segments in the mesh. Each line segment is treated as a cylinder with the specified thickness.

Parameters:
  • line_mesh (gustaf.Edges) – Line mesh containing vertices and edge connectivity.

  • thickness (float) – Thickness (diameter) of the lines. Points within half this distance are considered inside.

  • smoothness (float, default 0) – Smoothing parameter for the union operation. Higher values create smoother transitions between line segments. Use 0 for sharp union.

Examples

>>> import gustaf
>>> import numpy as np
>>> from DeepSDFStruct.SDF import SDFfromLineMesh
>>>
>>> # Create a simple line segment
>>> vertices = np.array([[0, 0], [1, 1]])
>>> edges = np.array([[0, 1]])
>>> line_mesh = gustaf.Edges(vertices, edges)
>>>
>>> sdf = SDFfromLineMesh(line_mesh, thickness=0.1)
>>> import torch
>>> points = torch.tensor([[0.0, 0.0], [0.5, 0.5]])
>>> distances = sdf(points)

Notes

Currently supports only 2D line meshes.

line_mesh: gustaf.edges.Edges#
class DeepSDFStruct.SDF.SDFfromMesh(mesh, dtype=<class 'numpy.float32'>, flip_sign=False, scale=True, threshold=1e-05, backend='igl')#

Bases: DeepSDFStruct.SDF.SDFBase

Create an SDF from a triangle mesh using closest-point queries.

This class wraps a triangle mesh and computes signed distances by finding the closest point on the mesh surface to each query point. The sign is determined using winding number or ray casting to determine inside/outside.

The mesh can be optionally normalized to fit within a unit cube centered at the origin, which is useful for consistent scaling across different geometries.

Parameters:
  • mesh (trimesh.Trimesh or gustaf.faces.Faces) – The input triangle mesh. If a gustaf Faces object is provided, it will be converted to a trimesh object.

  • dtype (numpy dtype, default np.float32) – Data type for distance calculations.

  • flip_sign (bool, default False) – If True, flips the sign of the computed distances (inside becomes outside and vice versa).

  • scale (bool, default True) – If True, normalizes the mesh to fit within a unit cube [-1, 1]^3 centered at the origin.

  • threshold (float, default 1e-5) – Small threshold value for numerical stability in distance computations.

mesh#

The (possibly normalized) triangle mesh.

Type:

trimesh.Trimesh

dtype#

Data type used for calculations.

Type:

numpy dtype

flip_sign#

Whether distances are sign-flipped.

Type:

bool

threshold#

Numerical threshold for stability.

Type:

float

Notes

This class uses libigl for efficient closest-point queries and embree for ray intersection tests to determine inside/outside status.

Examples

>>> import trimesh
>>> from DeepSDFStruct.SDF import SDFfromMesh
>>> import torch
>>>
>>> # Load or create a mesh
>>> mesh = trimesh.creation.box(extents=[1, 1, 1])
>>>
>>> # Create SDF from mesh
>>> sdf = SDFfromMesh(mesh, scale=True)
>>>
>>> # Query distances
>>> points = torch.tensor([[0.0, 0.0, 0.0], [2.0, 0.0, 0.0]])
>>> distances = sdf(points)
class DeepSDFStruct.SDF.SmoothDifferenceSDF(base_sdf, *subtract_sdfs, k=0)#

Bases: DeepSDFStruct.SDF.SDFBase

Smooth subtraction of SDFs.

Parameters:
class DeepSDFStruct.SDF.SmoothIntersectionSDF(*sdfs, k=0)#

Bases: DeepSDFStruct.SDF.SDFBase

Smooth intersection of multiple SDFs with smoothing parameter k.

Parameters:

sdfs (DeepSDFStruct.SDF.SDFBase)

class DeepSDFStruct.SDF.SmoothUnionSDF(*sdfs, k=0)#

Bases: DeepSDFStruct.SDF.SDFBase

Smooth blending of multiple SDFs with smoothing parameter k.

Parameters:

sdfs (DeepSDFStruct.SDF.SDFBase)

class DeepSDFStruct.SDF.SummedSDF(obj1, obj2)#

Bases: DeepSDFStruct.SDF.SDFBase

Parameters:
class DeepSDFStruct.SDF.TransformedSDF(sdf, rotationMatrix=None, translation=None, scaleFactor=None)#

Bases: DeepSDFStruct.SDF.SDFBase

Generic SDF wrapper that applies a transformation to the input queries. Transformation can be rotation, translation, or scaling.

Parameters:

sdf (DeepSDFStruct.SDF.SDFBase)

class DeepSDFStruct.SDF.UnionSDF(*objects)#

Bases: DeepSDFStruct.SDF.SDFBase

Union of multiple SDFs using the minimum operator.

Combines multiple SDFs by computing the minimum distance at each query point. This creates the union (boolean OR) of all input geometries.

Parameters:

*objects (SDFBase) – Two or more SDF objects to combine. All objects must have the same geometric dimension (2D or 3D).

Raises:

ValueError – If fewer than two objects are provided, or if objects have mismatched geometric dimensions.

Examples

>>> sphere1 = SphereSDF([0, 0, 0], radius=1.0)
>>> sphere2 = SphereSDF([1.5, 0, 0], radius=1.0)
>>> union = UnionSDF(sphere1, sphere2)
DeepSDFStruct.SDF.generate_plane_points(origin, normal, res, xlim, ylim)#

Generate evenly spaced points on a plane in 3D space.

Creates a regular grid of points on a plane defined by a point and normal vector. The grid is axis-aligned in the plane’s local coordinate system.

Parameters:
  • origin (array-like of shape (3,)) – A point on the plane (3D vector).

  • normal (array-like of shape (3,)) – Normal vector of the plane (3D vector). Currently supports only axis-aligned normals: [1,0,0], [0,1,0], or [0,0,1].

  • res (tuple of int) – Grid resolution (num_points_u, num_points_v).

  • xlim (tuple of float) – Range along the first plane axis (umin, umax).

  • ylim (tuple of float) – Range along the second plane axis (vmin, vmax).

Returns:

  • points (np.ndarray of shape (num_points_u * num_points_v, 3)) – 3D coordinates of grid points.

  • u (np.ndarray of shape (num_points_u * num_points_v,)) – First plane coordinate for each point.

  • v (np.ndarray of shape (num_points_u * num_points_v,)) – Second plane coordinate for each point.

Raises:

NotImplementedError – If normal is not axis-aligned.

Examples

>>> from DeepSDFStruct.plotting import generate_plane_points
>>> import numpy as np
>>>
>>> # Generate points on XY plane at z=0.5
>>> points, u, v = generate_plane_points(
...     origin=[0, 0, 0.5],
...     normal=[0, 0, 1],
...     res=(10, 10),
...     xlim=(-1, 1),
...     ylim=(-1, 1)
... )
>>> print(points.shape)  # (100, 3)
>>> print(np.allclose(points[:, 2], 0.5))  # True (all on z=0.5 plane)

Notes

The function determines two orthogonal axes (u and v) in the plane based on the normal vector. For axis-aligned planes: - Normal [0,0,1] (XY plane): u=[1,0,0], v=[0,1,0] - Normal [0,1,0] (XZ plane): u=[1,0,0], v=[0,0,1] - Normal [1,0,0] (YZ plane): u=[0,1,0], v=[0,0,1]

DeepSDFStruct.SDF.get_equidistant_grid_sample(bounds, grid_spacing, dtype=torch.float32, device='cpu')#

Generates an equidistant 3D grid of points within the given bounding box.

Parameters:
  • bounds (torch.Tensor) – Tensor of shape (2,3), [[xmin, ymin, zmin], [xmax, ymax, zmax]]

  • grid_spacing (float) – Approximate spacing between points along each axis.

Returns:

points – Tensor of shape (N,3) containing all grid points.

Return type:

torch.Tensor

DeepSDFStruct.SDF.normalize_mesh_to_unit_cube(mesh, shrink_factor=1.0)#

Transform mesh coordinates uniformly to [-1, 1] in all axes. Keeps aspect ratio of original mesh.

shrink_factorfloat

Uniform scaling factor applied after normalization. 1.0 -> exactly fills [-1, 1] 0.95 -> 5% smaller

Returns:

The fitted mesh, the inverse scaling factor applied (can directly be used as input for the TorchScaling), and the translation vector used.

Parameters:
  • mesh (trimesh.base.Trimesh)

  • shrink_factor (float)

DeepSDFStruct.SDF.point_segment_distance(P1, P2, query_points)#

Calculates the minimum distance from one or more query points to one or more line segments defined by endpoints P1 and P2.

Parameters:
  • P1 (np.ndarray) – Array of shape (M, 2) or (2,) representing first endpoints of segments.

  • P2 (np.ndarray) – Array of shape (M, 2) or (2,) representing second endpoints of segments.

  • query_points (np.ndarray) – Array of shape (N, 2) or (2,) representing query point(s).

Returns:

Array of shape (N,) with the minimum distance from

each query point to the closest segment.

Return type:

np.ndarray

DeepSDFStruct.SDF.project_bounds(origin, normal, bounds=None)#

Project 3D AABB bounds onto a slice plane and return 2D limits.

Parameters:
  • origin ((3,)) – Point on plane

  • normal ((3,)) – Plane normal

  • bounds ((2, 3)) – AABB bounds [[xmin,ymin,zmin],[xmax,ymax,zmax]] If None, defaults to unit cube [0,1]^3

Returns:

xlim, ylim – Limits in plane coordinates

Return type:

tuple

DeepSDFStruct.SDF.union_numpy(D, k=0)#

D: np.array of shape (num_points, num_geometries) k: smoothness parameter

DeepSDFStruct.SDF.union_torch(D, k=0)#

D: np.array of shape (num_points, num_geometries) k: smoothness parameter