Geometry via SDF¶

Google Collab Book

This notebook introduces signed distance fields in ΦFlow.

In [1]:
# %pip install phiflow
from phi.flow import *

SDF From Existing Geometry¶

Signed distance fields can easily be created from existing geometry. The next cell creates a SDF from a pair of spheres.

In [2]:
spheres = Sphere(vec(x=[1, 2], y=1), radius=.8)
bounds = Box(x=3, y=2)
sdf = geom.sdf_from_geometry(spheres, bounds, x=10, y=10)
plot({"SDF": sdf.values, "Surface": [spheres, sdf]}, overlay='list')
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Cell In[2], line 3
      1 spheres = Sphere(vec(x=[1, 2], y=1), radius=.8)
      2 bounds = Box(x=3, y=2)
----> 3 sdf = geom.sdf_from_geometry(spheres, bounds, x=10, y=10)
      4 plot({"SDF": sdf.values, "Surface": [spheres, sdf]}, overlay='list')

AttributeError: module 'phi.geom' has no attribute 'sdf_from_geometry'

Custom SDF Construction¶

Next, let's construct a SDF from a 2D NumPy array.

In [3]:
bounds = Box(x=(-10, 10), y=(-10, 10))
grid_x, grid_y = np.meshgrid(np.linspace(-10, 10, 100), np.linspace(-10, 10, 100))
sdf_np = np.sqrt(grid_x**2 + grid_y**2) - 5
sdf_tensor = tensor(sdf_np, spatial('x,y'))
sdf = geom.SDFGrid(sdf_tensor, bounds)
plot(sdf_tensor, sdf)
/opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/phiml/math/_tensors.py:1155: RuntimeWarning: invalid value encountered in power
  result = op(n1, n2)
/opt/hostedtoolcache/Python/3.12.11/x64/lib/python3.12/site-packages/phi/vis/_matplotlib/_matplotlib_plots.py:167: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
  plt.tight_layout()  # because subplot titles can be added after figure creation
Out[3]:

Sampling¶

SDFs behave like any other geomoetry. They can be resampled to grids and other fields.

In [4]:
to_grid = CenteredGrid(sdf, 0, bounds, x=40, y=40)
soft = resample(sdf, to_grid, soft=True)
plot(to_grid, soft)
Out[4]:
In [5]:
sdf.lies_inside(vec(x=0, y=0))
Out[5]:
True

Querying the Surface¶

SDFs support querying the closest surface point and normal vector.

In [6]:
loc = geom.UniformGrid(sdf.resolution.with_sizes(10), sdf.bounds).center
sgn_dist, delta, normal, *_ = sdf.approximate_closest_surface(loc)
plot(PointCloud(loc, delta))
Out[6]: