Isosurface: marching cubes & metaballs

Pure-Python port of the 3-D core of BOSL2’s isosurface.scad: isosurface() meshes the level set of a scalar field over a voxel grid (marching cubes) into a VNF; the mb_* functions are metaball field primitives; and metaballs() sums transformed primitives and meshes the result into a blobby surface:

isosurface(field_fn, isovalue=1, bounding_box=60, voxel_size=2)
metaballs([(pos1, mb_sphere(12)), (pos2, mb_sphere(12))], bounding_box=box, voxel_size=2)

A field primitive returns a value that grows toward infinity at its center and falls off with distance; the surface is drawn where the summed field reaches isovalue (default 1). Because the fields add, overlapping metaballs bulge together into a smooth blob. The mb_* formulas are pinned point-for-point to real BOSL2 in tests/test_bosl2_reorient.py; the meshes are watertight and verified geometrically.

The mesher uses the standard Paul Bourke marching-cubes triangle table, so its triangulation isn’t vertex-identical to BOSL2’s, but the surface it encloses is the same; face winding is fixed to outward via the VNF’s signed volume.

Coverage of BOSL2 isosurface.scad

BOSL2 function

Status

Notes

isosurface

ported

isosurface() – marching cubes over a field callable or a precomputed 3-D array; voxel_size/voxel_count, closed, reverse, range isovalues [lo, hi] (collapsed to a one-sided threshold).

metaballs

ported

metaballs() – a list of (transform, metaball) pairs (or the BOSL2 flat form).

mb_sphere / mb_cuboid / mb_torus / mb_capsule / mb_disk / mb_octahedron / mb_connector

ported

the 3-D metaball field primitives, with cutoff / influence / negative.

mb_cyl

not ported

the revolved-profile (cone/rounded) field – a follow-up.

contour / metaballs2d / mb_circle / mb_rect / mb_trapezoid / mb_stadium / mb_ring / mb_connector2d

not ported

the 2-D analogues (marching squares) – a follow-up.

debug views, anchor/spin/orient

not ported

preview/attachment machinery.

Examples

Two spheres merging into a peanut:

spec = [([-14, 0, 0], mb_sphere(12)), ([14, 0, 0], mb_sphere(12))]
metaballs(spec, bounding_box=[[-40, -20, -20], [40, 20, 20]], voxel_size=2).polyhedron().show()

⬇ Download STL mesh

A ring metaball plus a connecting bar:

spec = [([0, 0, 0], mb_torus(14, 4)), ([-14, 0, 0], mb_connector([-14, 0, 0], [14, 0, 0], 4))]
metaballs(spec, bounding_box=[[-22, -22, -10], [22, 22, 10]], voxel_size=2).polyhedron().show()

⬇ Download STL mesh

The level set of a custom field function:

def field(p):
    import numpy as np
    diameter=np.sqrt(p[:, 0]**2 + p[:, 1]**2 + p[:, 2]**2)
    return 18 / d + 3 * np.sin(p[:, 0] / 3) * np.cos(p[:, 1] / 3)
isosurface(field, 1, bounding_box=70, voxel_size=2.5).polyhedron().show()
_images/8766ff2c30e07ba7.png

API reference

bosl2.isosurface.isosurface(f, isovalue, bounding_box=None, voxel_size=None, voxel_count=None, closed=True, reverse=False, exact_bounds=False)[source]

Mesh the level set of a scalar field f at isovalue into a VNF (BOSL2 isosurface()).

The solid is the region where f >= isovalue (a single number) or, for a range [lo, hi], where lo <= f <= hi collapses to f >= lo (hi unbounded) or f <= hi (lo unbounded, i.e. reversed). f is a callable (vectorised (N,3)->(N,) or scalar point->value) or a precomputed 3-D array. Give voxel_size or voxel_count to control resolution; the bounding box grows to whole voxels unless exact_bounds.

Returns:

A VNF.

Parameters:
  • closed (bool)

  • reverse (bool)

Examples

The level set of a wobbly sphere field:

def field(p):
    import numpy as np
    x, y, z = p[:, 0], p[:, 1], p[:, 2]
    return 20 / np.sqrt(x*x + y*y + z*z) + 3 * np.sin(x / 3)
isosurface(field, 1, bounding_box=60, voxel_size=2).polyhedron().show()

⬇ Download STL mesh

bosl2.isosurface.metaballs(spec, bounding_box, voxel_size=None, voxel_count=None, isovalue=1, closed=True, exact_bounds=False)[source]

Mesh a set of transformed metaball field primitives into a blobby surface (BOSL2 metaballs()).

spec is a list of (transform, metaball) pairs (or the BOSL2 flat [transform, metaball, ...] form), where transform is a 4x4 matrix or a 3-vector position and metaball comes from mb_sphere / mb_cuboid / mb_torus / mb_capsule / mb_disk / mb_octahedron / mb_connector. The fields sum, and the surface is drawn where the total reaches isovalue.

Returns:

A VNF.

Parameters:

closed (bool)

Examples

Two spheres merging into a peanut:

spec = [([-14, 0, 0], mb_sphere(12)), ([14, 0, 0], mb_sphere(12))]
metaballs(spec, bounding_box=[[-40, -20, -20], [40, 20, 20]], voxel_size=2).polyhedron().show()

⬇ Download STL mesh

bosl2.isosurface.mb_sphere(radius=None, cutoff=inf, influence=1, negative=False, diameter=None)[source]

A spherical metaball field of radius radius (BOSL2 mb_sphere()).

Parameters:
  • radius (float | None)

  • cutoff (float)

  • influence (float)

  • negative (bool)

  • diameter (float | None)

bosl2.isosurface.mb_cuboid(size, squareness=0.5, cutoff=inf, influence=1, negative=False)[source]

A rounded-cuboid metaball field (BOSL2 mb_cuboid()). squareness 0..1: 0 round, 1 square.

Parameters:
  • cutoff (float)

  • influence (float)

  • negative (bool)

bosl2.isosurface.mb_torus(major_radius=None, minor_radius=None, cutoff=inf, influence=1, negative=False, major_diameter=None, minor_diameter=None)[source]

A torus metaball field, major radius major_radius, tube radius minor_radius (BOSL2 mb_torus()).

Parameters:
  • cutoff (float)

  • influence (float)

  • negative (bool)

bosl2.isosurface.mb_capsule(height=None, radius=None, cutoff=inf, influence=1, negative=False, diameter=None)[source]

A capsule (round-ended cylinder) metaball field, total length height, radius radius (BOSL2 mb_capsule()).

Parameters:
  • height (float | None)

  • radius (float | None)

  • cutoff (float)

  • influence (float)

  • negative (bool)

  • diameter (float | None)

bosl2.isosurface.mb_disk(height=None, radius=None, cutoff=inf, influence=1, negative=False, diameter=None)[source]

A rounded-edge disk metaball field, thickness height, outer radius radius (BOSL2 mb_disk()).

Parameters:
  • height (float | None)

  • radius (float | None)

  • cutoff (float)

  • influence (float)

  • negative (bool)

  • diameter (float | None)

bosl2.isosurface.mb_octahedron(size, squareness=0.5, cutoff=inf, influence=1, negative=False)[source]

A rounded-octahedron metaball field (BOSL2 mb_octahedron()).

Parameters:
  • cutoff (float)

  • influence (float)

  • negative (bool)

bosl2.isosurface.mb_connector(p1, p2, radius=None, cutoff=inf, influence=1, negative=False, diameter=None)[source]

A capsule metaball field spanning from p1 to p2 with radius radius (BOSL2 mb_connector()).

Parameters:
  • radius (float | None)

  • cutoff (float)

  • influence (float)

  • negative (bool)

  • diameter (float | None)

class bosl2.isosurface.Metaball(field, neg=1)[source]

Bases: object

A metaball field primitive: a vectorised scalar field field(pts) over (N, 3) points, plus its sign (neg). Combine several with metaballs().