Releases: inventhq/PicoPie
Release list
picopie 0.7.0 — compiled active_values() traversal (~30× faster)
Changed — active_values() is now compiled (~30× faster)
ScalarField.active_values() and VectorField.active_values() previously walked the sparse active-voxel set with a per-voxel Python callback — the same overhead class as the implicit-SDF path fixed in 0.6.0. They now use the compiled _fastloop extension: a native TraverseActive that writes straight into NumPy arrays via two nogil passes (count, then fill an exactly-sized buffer).
- ~30× faster — 335k active voxels: ~320 ms → ~10 ms — with bit-identical results (same coords, values, dtype, shape, and ordering). Re-verified against this PyPI wheel: compiled == pure-Python fallback.
- Same public API, transparent. No new method; falls back to the pure-Python callback when the extension isn't built, exactly like
get_many/set_many— one API, fast path + fallback. - Concurrent calls from multiple threads are serialised with a lock (the native callback ABI carries no user-data pointer, so the collector uses module state); the pure-Python fallback needs no lock.
Implemented in #4.
Install
pip install -U picopie # core
pip install -U "picopie[web]" # + the web viewer
The CycloneDX SBOM (sbom.cdx.json) is attached.
picopie 0.6.0 — compiled/native implicit callbacks
Added — compiled callbacks for render_implicit_ / intersect_implicit_
render_implicit_(sdf, bbox) and intersect_implicit_(sdf) now accept a compiled SDF in addition to a plain Python callable. Pass a numba.cfunc or any ctypes function pointer with the ABI float(const PKVector3*) (a pointer to three contiguous float32) and it is handed straight to the native loop — no per-voxel Python round-trip.
import numba
from numba import types
sig = types.float32(types.CPointer(types.float32)) # matches PKPFnfSdf
@numba.cfunc(sig, nopython=True)
def my_sdf(p):
return (p[0]**2 + p[1]**2 + p[2]**2) ** 0.5 - 8.0
part.render_implicit_(my_sdf, bbox) # detected and run nativelyMeasured ~30× faster than the Python-callback path (compiled C sphere SDF at 0.2 mm voxels: 724 ms → 23 ms), with bit-identical geometry — verified again against this PyPI wheel (native 2145.6 == python 2145.6 mm³).
- Plain
sdf(x, y, z)callables are unchanged and keep the never-abort finite guard. Detection is duck-typed, so numba stays an optional, undeclared dependency — works equally with numba, a hand-written C shared library, or cffi. - Caveat: the compiled path deliberately bypasses the finite/exception guard (which is what makes the Python path both safe and slow). A compiled callback owns its own correctness — returning NaN/inf injects a zero-distance surface, matching upstream C# PicoGK. See "Compiled callbacks" in
docs/tutorials/advanced/01-performance.md. - Requested in #1; implemented in #2.
Install
pip install -U picopie # core
pip install -U "picopie[web]" # + the web viewer
The CycloneDX SBOM (sbom.cdx.json) is attached.
v0.5.0 — rename import namespace picogk → picopie (LEAP 71 request)
Breaking change: the import namespace is now picopie (was picogk)
At the request of LEAP 71 (PicoGK's maintainers — who commended the project as
"a high-quality and substantial project" but asked for clear separation from the
official library), PicoPie now consistently uses the PicoPie name in package,
namespace, and type names. This is an independent, community-maintained binding
— not an official LEAP 71 project, and not affiliated with or endorsed by them.
Migrating
- import picogk
- from picogk import Voxels
- from picogk.shapes import Sphere
- from picogk.web import show
+ import picopie
+ from picopie import Voxels
+ from picopie.shapes import Sphere
+ from picopie.web import show- The exception type
PicoGKErroris renamed toPicoPieError. - The PyPI package name is unchanged —
pip install -U picopie. - The bundled native PicoGK runtime is unchanged (it is the actual PicoGK
runtime, so it stayspicogk.sointernally); geometry, performance, and the
whole API surface are otherwise identical to 0.4.2.
README and NOTICE now state clearly that PicoPie is unofficial and not affiliated
with LEAP 71. 436 CI tests pass on the renamed package.
Install
pip install -U picopie # core
pip install -U "picopie[web]" # + the web viewer
The CycloneDX SBOM (sbom.cdx.json) is attached.
v0.4.2 — post-construction step-bump fix + coverage
A small fix-and-coverage release closing the last items from the gap audit.
Fixed
- Shape tessellation now follows post-construction modulation. Setting a
modulated dimension after a shape is built —box.width = fn,
cylinder.radius = fn,pipe.inner_radius/outer_radius = fn(andCone) —
now raises the tessellation step count to match the constructor path. It
previously stayed silently coarse. Step counts are computed lazily from the
current modulation state; an explicit*_stepsargument still overrides, and
constructor-path results (and C# parity) are unchanged.
Testing
- Added direct coverage for previously-untested public wrappers
(Voxels.voxel_size_mm/bounding_box,Lattice/VdbFile.is_valid, field
memory_bytes,Metadata.to_dict, theVdbFile.savefailure path, and the
picogk.__all__re-exports) and shape branches (spherical frame alignment, the
cylindrical control-spline tangential step, closed control surfaces,
LatticeManifold(extend_both_sides=...), the down-facing painter split, and
mesh STL export). 436 CI tests.
Install
pip install -U picopie # core
pip install -U "picopie[web]" # + the web viewer
The CycloneDX SBOM (sbom.cdx.json) is attached.
v0.4.1 — web viewer polish (geometry/style split, matrix parity, camera) + validation guards
A polish release on the 0.4.0 web viewer, from a final gap audit. The core was
verified — empirically, in isolated subprocesses — to have no crash/hang gaps;
the real findings were concentrated in the (newest) web viewer.
Fixed — web viewer
- Matrix convention now matches the desktop
Viewer(row-major,
System.Numerics). A non-symmetricset_group_matrix/set_object_matrix
previously rendered transposed in the browser. - The camera no longer re-fits on every update — recolouring, toggling
visibility, or transforming a group preserves the current orbit (it auto-frames
only on first load and onreset_view). export_htmlnow carries per-object transforms; the identity matrix is no
longer a shared-mutable default.
Changed — web viewer
- geometry/style split — heavy vertex/index buffers are separated from light
per-object style (color, material, visibility, transform), so a style tweak does
a cheap in-place update instead of re-transmitting and rebuilding all geometry.
Hardening (core)
Voxels.mesh_shell,ScalarField/VectorFieldset_many/get_many,
ScalarField.slice, andMesh.add_trianglenow reject non-finite /
out-of-range input with a clear error, consistent with the rest of the API
(previously: silent garbage — none of these crashed).
Testing
- Assert the
require_finite/to_vec3/ bounds guards actually raise; add
library-lifecycle tests; bring the web serialization and viewer camera-state
math into per-wheel CI. 420 CI tests.
Install
pip install -U picopie # core
pip install -U "picopie[web]" # + the web viewer
The CycloneDX SBOM (sbom.cdx.json) is attached.
v0.4.0 — browser web viewer (three.js + anywidget)
The last big capability: a browser-based 3D viewer, so PicoPie now renders
where the desktop GLFW viewer can't — JupyterLab, VS Code notebooks, Google
Colab, and remote/SSH sessions.
Added — picogk.web
A three.js viewer inside an anywidget. Geometry is
computed in Python and streamed to the browser as binary buffers
(compute-in-Python, render-in-browser — not a WASM port of the kernel). Install
the optional extra:
pip install "picopie[web]"
import picogk
from picogk.web import show
picogk.init(0.2)
show(picogk.Voxels.sphere(radius=12)) # renders inline in a notebook cellWebViewerat full parity with the desktopViewer—add
(Voxels/Mesh/PolyLine),remove,set_group_material,set_group_visible,
set_background,set_group_matrix/set_object_matrix,reset_view,
screenshot— plus ashow(*objects)one-liner.- three.js renderer: PBR materials + lighting, orbit/pan/zoom, an auto-framed
camera, a wireframe toggle, and keyboard shortcuts (F fit · W wireframe
· S save PNG). export_html(objects, path)— writes a self-contained, double-click-to-open
HTML (the renderer is inlined and the geometry embedded); no Jupyter or server
needed. Trypython examples/web/demo.py.
Needs a browser with internet (three.js loads from a CDN the first time, then is
cached). The core library and the desktop viewer are unchanged.
Install
pip install picopie==0.4.0 # core
pip install "picopie[web]==0.4.0" # + the web viewer
The CycloneDX SBOM (sbom.cdx.json) is attached.
v0.3.2 — project_z_slice_ fine-voxel fix + voxel-size test coverage
A follow-up to 0.3.1: found and fixed another instance of the same bug class
(a millimetre value used as an integer voxel count) by auditing the runtime,
and closed the test-coverage gap that let the class ship twice.
Fixed
project_z_slice_at fine voxel sizes. PicoGK'sProjectZSliceDn/
ProjectZSliceUpsealed the end cap by iterating(int)(0.5 + background_mm)
slices — but the background is in mm (narrowBand × voxel_size), not a
voxel count. Below ~0.167 mm it truncated to 0, so the bottom cap was never
sealed and the projected solid came out non-watertight — silently, with no
error (re-voxelising it collapsed the volume, e.g. 818 → 22 mm³ at 0.1 mm).
Above ~1.5 mm it over-iterated. The bundled runtime now uses the narrow band
directly, so the result is consistent across voxel sizes.Voxels.triple_offset_andproject_z_slice_now reject non-finite (NaN/inf)
arguments with aValueError, matchingoffset_/double_offset_.
Testing
- New voxel-size sweep tripwire (
tests/test_voxel_size_sweep.py, runs per
wheel) exercises the resolution-sensitive native ops across 0.1–1.0 mm and
asserts the results stay valid and consistent with the 0.5 mm baseline. The
whole suite previously ran only at 0.5 mm — the one resolution where these
narrow-band truncations can't fire — which is why the class shipped twice. scripts/fuzz_abort.pynow sweeps voxel size across workers (0.05–2.0 mm) and
fuzzes the previously-uncoveredtriple_offset_,project_z_slice_, and
mesh_shellops.scripts/voxel_size_sweep.pyis the diagnostic that found it.
Install
pip install picopie==0.3.2
The CycloneDX SBOM (sbom.cdx.json) is attached.
v0.3.1 — implicit intersect fix at fine voxel sizes + smoother gallery
A bugfix + polish release on top of the 0.3.0 ShapeKernel port.
Fixed
- Implicit intersect at fine voxel sizes.
Voxels.intersect_implicit_(and
theImplicitGyroid/ImplicitSphere/ … intersect helpers) aborted with
"expected grid A outside value > 0, got 0" whenever the voxel size was below
~0.33 mm. Upstream PicoGK'sIntersectImplicitbuilt its temporary grid from
the background in millimetres (a float =narrowBand × voxel_size) passed
into anint nNarrowBandargument, which truncated to0at fine resolutions
→ a grid with background0→ OpenVDB'scsgIntersectionrejected it. The
bundled runtime is now patched at build time to pass the source's narrow band
instead, so implicit intersects work at any voxel size.
Changed
- The example gallery (
examples/shapekernel/gallery.py) now renders at a
0.2 mm voxel size by default (was 0.5 mm) with a new--voxel-sizeflag,
and the small implicit shapes are scaled up — the docs gallery images are
noticeably smoother (no faceted silhouettes / "orange-peel"). Surface
smoothness is set by the voxel size, not the parametric tessellation.
Install
pip install picopie==0.3.1
The CycloneDX SBOM (sbom.cdx.json) is attached.
PicoPie 0.3.0 — ShapeKernel port
picogk.shapes — a full, Pythonic port of LEAP 71's ShapeKernel (pinned ShapeKernel-v2.1.0), built on the PicoPie core and parity-tested vs the reference C# (geometry to float precision).
Added
- Support layer:
LocalFrame/Frames,LineModulation/SurfaceModulation, vector/spline/list/grid/formula utilities, splines (ControlPointSpline/Surface,Tangential/CylindricalControlSpline). - All 10 base shapes:
Sphere,Box,Cylinder,Cone,Ring,Lens,Pipe,PipeSegment,Revolve,LogoBox— frames + modulations + spines,to_voxels()/to_mesh(). - Lattices (
LatticePipe/LatticeManifold) + builders; implicit SDFs (ImplicitGyroid/Sphere/Genus/SuperEllipsoid) withrender/intersect. - Measurement (volume/area/centre-of-gravity/inertia), mesh utilities, CSV/STL/VDB export, colour palette/scales +
MeshPainter. - Runnable example gallery + a "Shapes" tutorial track + docs gallery.
Fixed / hardened
Mesh.from_arraysandLattice.add_*reject non-finite input with a clearValueError(both fast + fallback paths) — every shape validates its dimensions up front.- B-splines with too few control points raise a clear error instead of
ZeroDivisionError.
Install: pip install picopie==0.3.0 (or uv add picopie). Self-contained wheels for CPython 3.10–3.13 on Linux/macOS/Windows. See the CHANGELOG.
picopie 0.2.1 — first public release
First public release of PicoPie — a Pythonic binding for PicoGK
(LEAP 71's OpenVDB voxel/level-set kernel). No .NET, no compiler, no system libraries.
pip install picopie # or: uv add picopie
pip install "picopie[viz]" # + headless slice/mesh PNG helpersSelf-contained wheels for CPython 3.10–3.13 on Linux (manylinux x86-64), macOS (Apple Silicon),
and Windows (x64) — the native runtime (OpenVDB 13, PicoGK 26.2) and all its C++ deps are bundled.
Highlights
Voxels(primitives, booleans+ - &, offsets,shell_, implicit SDF, queries),Mesh
(STL/OBJ in/out, NumPy arrays),Lattice,ScalarField/VectorField,Metadata, VDB I/O.- Interactive viewer (
picogk.show,render_png) + headless slice/mesh PNG helpers. - Compiled fast path (~13–28× bulk transfer) with pure-Python fallback.
Reliability
- Parity-validated against C# PicoGK on the same runtime (volumes, dims, mesh counts, queries).
- Never aborts — native/OpenVDB errors surface as catchable
PicoGKError; non-finite inputs
rejected up front (fuzz-verified). Green CI on all three OSes; ~190 tests; mypy + ruff clean. - Reproducible & auditable: every dep version-pinned; ships an SBOM + hash-pinned build deps.
Docs
Leveled tutorials (Novice / Intermediate / Advanced) + a one-file QuickLearn — see
docs/.
PyPI: https://pypi.org/project/picopie/0.2.1/ · Apache-2.0.