Freeform Holder Panel
The key model is FreeformHolder: a holder whose shape comes from a referenced geometry, typically an STL, positioned by two anchor transformers — one to the spindle, one to the cutter.
The holder occupies four child sections of the Holder node under the selected tool — Geometry, Geom To Spindle, Geom To Cutter and Resolution, the nodes whose role paths end in .../holder/geometry, .../holder/geom-to-spindle, .../holder/geom-to-cutter and .../holder/resolution, reached at /tool-house/:toolId/holder/:subtab. Its Name, readonly Abstract Note and Note are edited one level up, on the Holder Panel itself, under the Metadata-on-container convention.
The three shape sections are not holder-specific editors. They are the same generic Geometry and Transformer slots the Fixture branch of the General Setup page is built from: a kind picker on the section node, and the chosen kind's own editor on the child node below it. So an STL holder is picked as StlFile and its source file set through the shared StlFile editor, a TransformationGeom holder grows Inner Geometry and Inner Transformer nodes, a GeomCombination holder grows one node per item, and each placement grows the chosen transformer kind's editor — Static Translation for the usual (0, 0, h) offset.
Layout
Web Layout
- Geometry Section
- Geometry Type Selector — None / Box3d / Cylindroid / StlFile / TransformationGeom / GeomCombination
- The chosen kind's editor, on the child node the kind grows
- Geom To Spindle Section — where the holder sits relative to the spindle
- Transformer Type Selector — Static Translation / Static Rotation / Static Freeform / Dynamic Translation / Dynamic Rotation / General Transform / No Transform
- The chosen kind's editor, on the child node the kind grows
- Geom To Cutter Section — where the cutter sits relative to the holder
- Transformer Type Selector and the chosen kind's editor, as above
- Resolution Section
- Resolution Hint Caption — names the STL tessellation resolution used for display and collision meshing
- Linear Resolution (mm) Input Field
- Angle Resolution (deg) Input Field
Feature
The generic editors reach the holder's own members, and that is what makes the split work. When the Holder node's children are built, the page calls FreeformHolderController's Get with its session key; the server publishes the holder's Geom, GeomToSpindleTransformer and GeomToCutterTransformer in the index service under three per-session keys (-HolderGeom, -HolderGeomToSpindle, -HolderGeomToCutter) and hands the keys back. The keys name the very objects the holder holds, so an edit through a kind editor lands on the holder directly. The keys are returned even when a member is empty — nothing is published then, the section's picker reads an empty slot, and picking a kind fills that same key — which is how a freshly switched-to Freeform holder, whose geometry starts empty, gets its first shape.
Picking a kind is a container-aware create, not a bare New. The Geometry picker calls CreateGeometry, which builds the geometry, sets it as the holder's Geom and publishes it under the section's key (None clears the geometry). A placement picker first creates the transformer through the kind's own New endpoint and then attaches it with UpdateGeomToSpindleTransformer or UpdateGeomToCutterTransformer. Without the attach, only the index-service entry would change and the holder would keep pointing at its old transformer.
Because the generic editors hold no reference back to the holder, every edit at or below a section ends in the holder resync the page wires onto the section: a geometry edit calls UpdateGeometryContent, a placement edit re-attaches the transformer under its key. Both run UpdateByGeom() to regenerate the solid, ClearCache(), and AlignAnchorByExposedCutterHeight() to re-place the cutter under the holder — clearing the cache alone would leave the cutter where it was. The page then refreshes the tool list and the canvas.
The Resolution section writes the polar resolution straight onto the holder: SetPolarResolution assigns a fresh PolarResolution2d and the holder swaps its solid for one born with the new value, keeping the geometry. Get also returns the current pair, which is how the two fields are seeded.
Guards sit on both sides. Every action on the controller answers Not Found for an unknown tool id and Bad Request when the tool's holder is not a FreeformHolder; SetPolarResolution rejects a linear or angle value that is not greater than zero, and the Resolution section refuses to send one. Fields commit on blur or Enter.
Switching a tool to Freeform is a committing choice. SetHolderType assigns a new FreeformHolder only when the tool does not already carry one, so a holder authored elsewhere — through HiNcRcl, say — survives a round trip through this page with its geometry, anchors and resolution intact.
Source Code Path
See HiNC App Anatomy for git repository links.
HiNC-2025-webservice (Quasar CLI SPA):
wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts— grows the four child sections for aFreeformHolder: readsGetto publish the three members, binds the Geometry section to the genericGeometryitem type and the two placements to the genericTransformeritem type (with the create hooks and the resync chain), and routes Resolution to theHolderSectionitem type.wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue/TransformerSlotPanel.vue— the kind pickers on the three shape sections; the chosen kind's editor lives on the child node (wwwroot-src/src/components/geom/geometryEditors.ts,wwwroot-src/src/components/topo/transformerEditors.ts).wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue— the Resolution section, dispatching on the holder type toFreeformHolderControllerfor a Freeform holder.wwwroot-src/src/components/controlTree/toolhouse/ToolHolderPanel.vue— the parent Holder node's panel, which hosts this holder's Name, readonly Abstract Note and Note and commits them throughsetFreeformHolderName/setFreeformHolderNote.wwwroot-src/src/api/freeformHolder.ts— the typed wrapper over/api/FreeformHolder:getFreeformHolder,createFreeformHolderGeometry,updateFreeformHolderGeometry,resyncFreeformHolder,updateFreeformHolderGeomToSpindle,updateFreeformHolderGeomToCutter,setFreeformHolderName,setFreeformHolderNote,setFreeformHolderResolution.wwwroot-src/src/i18n/en/toolhouse.ts— the two placement section labels (toolhouse.node.geomToSpindle/geomToCutter) and the Freeform sections hint; the zh-Hans and zh-Hant files carry the same keys.Mech/FreeformHolderController.cs—GET Get(name / note / abstract note, the polar resolution, and — with a session key — the three member keys) plusPOST CreateGeometry | UpdateGeometry | IndexCurrentGeometry | UpdateGeometryContent | UpdateGeomToSpindleTransformer | UpdateGeomToCutterTransformer | SetName | SetNote | SetPolarResolution.
See Also
- Polar Resolution 2D Panel — the resolution editor this panel embeds
- Fixture Page — the other user of the generic Geometry and Transformer slots this holder's shape sections are made of