Skip to content
28 changes: 28 additions & 0 deletions docs/examples/implicit_shapes.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.. _RST ImplicitShapes:

Implicit Shapes (F-rep)
=======================

Primitives and Boolean Operations
----------------------------------

.. include:: ../../examples/ImplicitShapes/primitives_and_booleans.py
:literal:

.. image:: ../_static/examples/implicit_booleans.png

Implicit Lattices
-----------------

.. include:: ../../examples/Lattices/implicit_lattice.py
:literal:

.. image:: ../_static/examples/implicit_lattice.png

Trabecular Bone
---------------

.. include:: ../../examples/ImplicitShapes/trabecular_bone.py
:literal:

.. image:: ../_static/examples/trabecular_bone.png
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Table of contents

examples/basic_shapes
examples/lattices
examples/implicit_shapes
examples/tpms
examples/3d_operations
examples/mesh
Expand Down
5 changes: 5 additions & 0 deletions docs/microgen.shape.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ microgen.shape package
:undoc-members:
:show-inheritance:

.. automodule:: microgen.shape.implicit_shape
:members:
:undoc-members:
:show-inheritance:

.. automodule:: microgen.shape.surface_functions
:members:
:undoc-members:
Expand Down
159 changes: 159 additions & 0 deletions docs/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,165 @@ Create TPMS on a cylindrical coordinate system:
cylindrical_gyroid.sheet.plot(color='white')


Implicit Shapes (F-rep)
-----------------------

Microgen includes an implicit (F-rep) modeling framework where shapes are
defined by scalar fields ``f(x, y, z)`` — the surface is at ``f = 0`` and the
interior is ``f < 0``. This enables smooth blending, exact booleans, and
composability that is hard to achieve with boundary meshes alone.

Converting Basic Shapes to Implicit
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Basic shapes (``Sphere``, ``Box``, ``Capsule``, ``Cylinder``, ``Ellipsoid``)
can be converted to implicit shapes with ``to_implicit()``, making it easy to
combine parametric geometry with F-rep boolean operations:

.. jupyter-execute::

import microgen
from microgen.shape.implicit_shape import implicit_box

sphere = microgen.Sphere(center=(0.3, 0, 0), radius=0.4)
sphere_imp = sphere.to_implicit()
box_imp = implicit_box(center=(-0.2, 0, 0), half_extents=(0.3, 0.3, 0.3))
result = sphere_imp.smooth_union(box_imp, k=0.2)
result.generate_vtk(resolution=60).plot(color='white')


Primitives
^^^^^^^^^^

Create basic implicit primitives and visualize them with marching cubes:

.. jupyter-execute::

from microgen.shape.implicit_shape import implicit_sphere, implicit_box

sphere = implicit_sphere(center=(0, 0, 0), radius=0.4)
sphere.generate_vtk(resolution=60).plot(color='white')

.. jupyter-execute::

box = implicit_box(center=(0, 0, 0), half_extents=(0.3, 0.3, 0.3))
box.generate_vtk(resolution=60).plot(color='white')


Boolean Operations
^^^^^^^^^^^^^^^^^^

Combine implicit shapes with standard boolean operators:

.. jupyter-execute::

from microgen.shape.implicit_shape import implicit_sphere, implicit_box

sphere = implicit_sphere(center=(0, 0, 0), radius=0.4)
box = implicit_box(center=(0, 0, 0), half_extents=(0.3, 0.3, 0.3))

union = sphere | box
union.generate_vtk(resolution=60).plot(color='steelblue')

.. jupyter-execute::

intersection = sphere & box
intersection.generate_vtk(resolution=60).plot(color='coral')

.. jupyter-execute::

difference = sphere - box
difference.generate_vtk(resolution=60).plot(color='mediumseagreen')


Smooth Blending
^^^^^^^^^^^^^^^

Smooth union produces organic-looking junctions controlled by the parameter *k*:

.. jupyter-execute::

smooth = sphere.smooth_union(box, k=0.3)
smooth.generate_vtk(resolution=60).plot(color='orchid')


Batch Smooth Union
^^^^^^^^^^^^^^^^^^

When combining many primitives, use ``batch_smooth_union`` — it evaluates all
fields in a flat loop, avoiding recursion-depth limits:

.. jupyter-execute::

import numpy as np
from microgen.shape.implicit_shape import implicit_sphere, batch_smooth_union

rng = np.random.default_rng(42)
spheres = [
implicit_sphere(center=tuple(rng.uniform(-0.5, 0.5, 3)), radius=0.15)
for _ in range(20)
]
combined = batch_smooth_union(spheres, k=0.1)
combined.generate_vtk(bounds=(-0.8, 0.8) * 3, resolution=80).plot(color='coral')


Transforms
^^^^^^^^^^

Translate, rotate, and scale implicit shapes:

.. jupyter-execute::

from microgen.shape.implicit_shape import implicit_box

box = implicit_box(center=(0, 0, 0), half_extents=(0.3, 0.2, 0.1))
rotated = box.rotate(angles=(0, 0, 45))
rotated.generate_vtk(resolution=60).plot(color='white')


Utilities: Shell and Repeat
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

``shell`` hollows a shape; ``repeat`` tiles it periodically:

.. jupyter-execute::

from microgen.shape.implicit_shape import implicit_sphere, shell

sphere = implicit_sphere(center=(0, 0, 0), radius=0.4)
hollow = shell(sphere, thickness=0.05)
hollow.generate_vtk(resolution=80).plot(color='white')

.. jupyter-execute::

from microgen.shape.implicit_shape import implicit_sphere, repeat

sphere = implicit_sphere(center=(0, 0, 0), radius=0.15)
tiled = repeat(sphere, spacing=(0.5, 0.5, 0.5))
tiled.generate_vtk(bounds=(-0.8, 0.8) * 3, resolution=80).plot(color='white')


TPMS + F-rep Composition
^^^^^^^^^^^^^^^^^^^^^^^^^

Combine TPMS implicit fields with F-rep shapes — for example, intersect a
gyroid with an implicit sphere:

.. jupyter-execute::

from microgen.shape.implicit_shape import implicit_sphere, from_field
from microgen.shape.surface_functions import gyroid
import numpy as np

gyroid_field = from_field(
lambda x, y, z: gyroid(x * 2 * np.pi, y * 2 * np.pi, z * 2 * np.pi),
bounds=(-0.6, 0.6) * 3,
)
sphere = implicit_sphere(center=(0, 0, 0), radius=0.5)
result = gyroid_field & sphere
result.generate_vtk(bounds=(-0.6, 0.6) * 3, resolution=80).plot(color='white')


3D Operations
-------------

Expand Down
75 changes: 75 additions & 0 deletions examples/ImplicitShapes/primitives_and_booleans.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Implicit shapes: primitives, boolean operations, and smooth blending.

Demonstrates the F-rep (Function Representation) framework in microgen
for creating implicit shapes and combining them with hard and smooth
boolean operations.
"""

import pyvista as pv

from microgen.shape.implicit_shape import (
batch_smooth_union,
implicit_box,
implicit_sphere,
)

# ---------------------------------------------------------------------------
# Create primitives
# ---------------------------------------------------------------------------

sphere = implicit_sphere(center=(0, 0, 0), radius=0.45)
box = implicit_box(center=(0, 0, 0), half_extents=(0.3, 0.3, 0.3))

BOUNDS = (-0.8, 0.8) * 3
RES = 80

# ---------------------------------------------------------------------------
# Boolean operations
# ---------------------------------------------------------------------------

union = sphere | box
intersection = sphere & box
difference = sphere - box
smooth = sphere.smooth_union(box, k=0.3)

# ---------------------------------------------------------------------------
# Visualize in a 2x2 grid
# ---------------------------------------------------------------------------

plotter = pv.Plotter(shape=(2, 2), window_size=(1200, 1200))

ops = [
(0, 0, "Union (A | B)", union, "steelblue"),
(0, 1, "Intersection (A & B)", intersection, "coral"),
(1, 0, "Difference (A - B)", difference, "mediumseagreen"),
(1, 1, "Smooth Union (k=0.3)", smooth, "orchid"),
]

for row, col, title, shape, color in ops:
mesh = shape.generate_vtk(bounds=BOUNDS, resolution=RES)
plotter.subplot(row, col)
plotter.add_text(title, font_size=12)
plotter.add_mesh(mesh, color=color, show_edges=False)

plotter.link_views()
plotter.show()

# ---------------------------------------------------------------------------
# Batch smooth union — combining many primitives efficiently
# ---------------------------------------------------------------------------

import numpy as np

rng = np.random.default_rng(42)
spheres = [
implicit_sphere(center=tuple(rng.uniform(-0.5, 0.5, 3)), radius=0.15)
for _ in range(20)
]

combined = batch_smooth_union(spheres, k=0.1)
mesh = combined.generate_vtk(bounds=(-0.8, 0.8) * 3, resolution=100)

plotter2 = pv.Plotter()
plotter2.add_text("Batch smooth union (20 spheres, k=0.1)", font_size=12)
plotter2.add_mesh(mesh, color="coral", show_edges=False)
plotter2.show()
Loading
Loading