Table of Contents

Geometry Editor

The geometry switchboard is one control: a kind picker over the kinds its host allows, and — unless the host asked for the picker alone — the picked kind's editor beneath it. It binds a key into the shared object store, not an object, and every Control-Tree Geometry slot is this same control in selector-only mode.

Layout

Web: a geometry-type dropdown; a separator, drawn only while a kind is active; then that kind's editor. Picking a kind commits immediately — there is no Apply button. In selector-only mode everything below the dropdown is dropped, which is the form each Geometry slot node shows.

What It Binds

The web panel has no target-geometry property. It takes a modelKey naming the object it edits and mutates what sits behind that key; a host that also owns the field holding the geometry passes an onCreate hook, so switching the kind rebinds the host's field rather than just the key.

Each host's field type decides which kinds it may offer; whether the kind survives a save decides which of those it does. A fixture's geometry and a workpiece's target geometry are IGetStl; a workpiece's initial geometry is an IMakeXmlSource, which is why the cube-tree file — which is not an IGetStl — reaches that picker and no other.

Type compatibility alone is not sufficient, and ExtendedCylinder is the case that shows it. It is an IMakeXmlSource, so the workpiece's raw slot could hold one and once did — but its start section is supplied by a host at run time and is not serialized, so a saved project reloaded it with a zero-radius start and the shape degenerated. The kind is now offered by the one host that wires that source, the cutter's upper beam.

Reach

The picker's own default is five of the seven kinds: Box3d, Cylindroid, StlFile, GeomCombination and CubeTreeFile. ExtendedCylinder is in the kind map but out of that default: a host that can wire its start section names it explicitly. TransformationGeom is in the kind map and is never offered, whitelisted or not: a transformed geometry is made with the Transform picker beside the kind, not picked as a kind. Nothing else is hidden by a flag.

The default is a guard rail, not a shipped list. Every host passes its own whitelist — the Control-Tree Geometry slots from the node context, the inline hosts as a constant — so no shipped surface renders the default at all, and the whitelist is what really decides reach.

Host Kinds offered
A mechanism anchor's solid, a freeform holder's geometry, a combination child the four container kinds — Box3d, Cylindroid, StlFile, GeomCombination
Workpiece raw geometry five — the four container kinds plus CubeTreeFile
Workpiece target geometry three — Box3d, Cylindroid, StlFile
Cutter upper beam five — Cylindroid, ExtendedCylinder, StlFile, Box3d, GeomCombination
Cutter inner beam two — Cylindroid, StlFile

A null geometry is a legal state of the model, but the web picker offers its None (unset) entry only when the host asks for it: the workpiece's two slots, the freeform holder's geometry and the cutter's inner beam do, while the mechanism anchor, the cutter upper beam and combination children do not, so those pickers cannot clear the slot. Clearing goes through the host's create hook with the literal kind None, which the container-aware endpoints map to null; a transform on the slot goes with the geometry.

Putting a Transform on a Geometry

A transformed geometry is not a kind this picker offers. Beside the kind picker — beneath it in the embedded form, as the kind node's header in a Control Tree — sits the Transform picker, which wraps the geometry already in the slot into a TransformationGeom in place, swaps its transformer, or with No Transform hands the authored geometry back to the owner; the kind picker shows the inner kind throughout, and a Control-Tree row reads Transformed Cylindroid. The Transform picker appears only under a kind that can sit under a transform and only where the host passes an onSetTransform hook, so the cutter's inner beam, a MeshedGeomFile and an ExtendedCylinder show none. A kind switch on a transformed slot creates the new geometry inside the wrapper, so the transform survives it; the picker's None (unset) clears wrapper and geometry together.

A combination is still not wrapped around an existing geometry: picking GeomCombination creates a new, empty one and discards what was there.

In the Control Tree

Geometry is a slot item type. Its child builder probes the slot's key for the type behind it and, when that type is a known kind, grows exactly one child node of that kind bound to the same key — so the slot node carries the picker and its single child carries the editor. A slot holding a TransformationGeom grows its inner kind's node, labelled Transformed {kind}, with the transformer's node under it. Every kind but GeomCombination resolves to the shared sole-editor panel; GeomCombination maps to a panel of its own, because it grows further slot children rather than hosting one editor. The two file-backed kinds compose the referenced file into their node label.

Source Code Path

See HiNC App Anatomy for git repository links.

HiNC-2025-webservice (Quasar CLI SPA):

  • wwwroot-src/src/components/geom/GeometryEditor.vue — the switchboard: the kind picker over the allowed kinds, the opt-in unset entry, the immediate commit through the create hook, and the active kind's editor; in the embedded form also the Transform picker and the transformer's editor.
  • wwwroot-src/src/components/geom/geometrySlot.ts — how a slot is presented: a wrapper as its inner kind, with the Transform choice beside it.
  • wwwroot-src/src/components/geom/geometryEditors.ts — the single kind → editor map both this picker and the Control Tree's sole-editor panel resolve through.
  • wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue — the slot node's panel: this switchboard in selector-only mode, fed its allowed kinds, its unset flag and its create hook from the node.
  • wwwroot-src/src/components/controlTree/SoleEditorPanel.vue — the kind child's panel.
  • wwwroot-src/src/components/controlTree/itemTypes.ts — registers Geometry as a slot type with its child builder, registers each kind against its panel, and holds both the container-kind list and the file-backed node labels; a wrapped slot's Transformed {kind} node and its transformer child are built here too.
  • wwwroot-src/src/components/controlTree/useControlTreeHost.ts — the three Equipment page Geometry slots and their per-host kind whitelists.
  • wwwroot-src/src/components/mech/EquipmentTopologyPanel.vue and wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue — the two inline, non-tree hosts.
  • wwwroot-src/src/api/index-service.ts — the type probe the picker calls to discover which kind is currently behind the key.
  • wwwroot-src/src/api/geometry.ts — the kind union, the create dispatcher and its per-kind endpoint map, and every per-kind call.
  • wwwroot-src/src/api/fixture.ts, wwwroot-src/src/api/workpiece.ts, wwwroot-src/src/api/toolHouse.ts and wwwroot-src/src/api/equipmentTopology.ts — the container-aware create wrappers each host's hook posts through.
  • wwwroot-src/src/i18n/en/common.ts and wwwroot-src/src/i18n/en/geom.ts — the picker's label and its unset and empty-state strings. Geometry type names are deliberately not translated.
  • The seven per-kind controllers under Geom/ — Geom/Box3dController.cs, Geom/CylindroidController.cs, Geom/ExtendedCylinderController.cs, Geom/StlFileController.cs, Geom/CubeTreeFileController.cs, Geom/TransformationGeomController.cs and Geom/GeomCombinationController.cs — each at /api/{Kind}/*. There is no single geometry controller and no geometry hub.
  • Common/IndexController.cs — the type probe at /api/Index/GetType.
  • Common/IndexService.cs — the keyed object store all of the above read and write. There is no per-panel session object.
  • Mech/FixtureController.cs, Mech/WorkpieceController.cs, Mech/CutterController.cs and Mech/Topology/EquipmentTopologyController.cs — the container-aware create endpoints that set the host's own field, and the ones that accept None and store null.

See Also