experiment · featuretree

Recognising CAD features by cutting the stock into cells

2026-10-06 · punkfab/featuretree (MIT) · cell_recognize.py

featuretree takes a STEP file, which holds a part's shape but not how it was built, and recovers a list of features that rebuilds it. Until this week it had one way of doing that. We've now tried a second, and this post is what happened: where it's better, and where it's clearly worse.

Why we went looking

Our recogniser works by slicing. It guesses a build direction, cuts the part into cross-sections along it, and traces the outlines it finds. That works well when the outlines are tidy.

We ran it on someone else's example part, a flange coupling exported by BlenderMesh2STEP, a Blender add-on that turns meshes into exact STEP solids. It's a simple part: a plate, a hub, a bore, a key slot, four counterbored holes. We recovered 78% of it.

The cause was three bugs in how we handle circles, plus one awkward detail in the part. The key slot starts exactly at the bore's edge, so the two outlines meet at a single point. Our tracer followed them as one loop that touches itself, and the rebuild failed. With those fixed, the slicer recovers the flange exactly. But it's the third part we've seen fail on touching outlines, so we wanted a method that doesn't trace outlines at all.

The idea

Cell decomposition is an old idea from the feature-recognition literature of the 1990s. It works on volumes instead of outlines:

  1. Start with the stock. Take the part's bounding box.
  2. Cut it into cells. Extend every flat face and every cylinder of the part across the whole box. Those surfaces chop the box into cells. Each cell is either entirely material or entirely empty.
  3. Label each cell. Test a few points inside it against the part.
  4. Merge empty cells into cuts. Empty cells that sit side by side, and stay empty over the same range of heights, become one cut: a profile and a depth.
  5. Pick the fewest cuts. Repeatedly take the cut that removes the most empty space not yet removed.

Four horizontal slabs of a flange coupling seen from above, each split into 54 cells. Material cells are filled teal and empty cells are pale. From left to right the slabs run from the base of the plate up to the hub: the bore and four small bolt holes are empty at the bottom, the bolt holes widen into counterbores, a ring groove appears around the hub, and in the top slab everything except the hub is empty.

The flange, split into 324 cells, seen from above at four heights. The grey lines are the part's own surfaces extended across the box. Reading left to right you can see the features appear: bolt holes, then their counterbores, then the groove under the hub and the key slot, then the hub standing alone.

The result is a "stock minus cuts" tree. It describes the part the way a machinist would, not necessarily the way its designer built it. A boss is whatever is left after cutting around it.

Two things that went wrong on the way

Results

On the flange it recovers the part exactly, as a stock block and 16 cuts, in about 12 seconds. The 16 are the ones you'd list by hand: the bore, the key slot, the groove, four holes, four counterbores, four rounded corners, and the cut around the hub.

Then the eleven parts of NIST's CAD test suite, next to the slicer. A part passes at 99.5% overlap and volume within 0.5%.

PartSlicer overlapSlicer featuresCells overlapCells featuresCells time
CTC-0199.73% ✓5499.73% ✓30128 s
CTC-0292.28%14422.06%162725 s
CTC-0394.38%6497.73%34145 s
CTC-0499.03%108rebuild failed93147 s
CTC-0598.05%5798.06%56120 s
FTC-0697.72%31rebuild failed4470 s
FTC-0796.42%2920.01%5333 s
FTC-0898.75%3799.28%50212 s
FTC-0999.85% ✓8099.98% ✓42104 s
FTC-1096.60%3899.17%8092 s
FTC-11100.00% ✓274.12%74 s

One caution on reading the table. The slicer's overlap is a lower bound, because its result has to be rotated back onto the input and we only try 24 orientations. The cell method never leaves the input's frame, so its number is direct.

What the table says

So it isn't a replacement. The slicer passes three parts and the cell method passes two of those three. The useful reading is that they fail on different parts for different reasons: the slicer on awkward outlines, the cells on surfaces that aren't flat or round.

What's next

Who did what

We chose the direction and pushed on whether the comparison was fair. Claude wrote the prototype, found and fixed the bugs, and ran the measurements.

The code is cell_recognize.py in punkfab/featuretree; paper/figures/cells_corpus.py reruns the table. It's a prototype and not yet wired into the main recogniser. Got a part that should come back as an editable tree? Start a project →