Transform Picker
A geometry with a transform on it is not a kind of its own on the web client. The Transform
picker beside a geometry puts a transform on that geometry, swaps it for another kind, or takes it
off again with No Transform, and the geometry keeps its authored data throughout. What the picker
manipulates on the server is a TransformationGeom — an inner geometry plus the
transformer that places it — but the client never names that type: a slot holding one is presented
as its inner kind, its Control-Tree row reads Transformed Cylindroid, and the transformer's own
row hangs under it. TransformationGeom remains the XML element and the REST kind name. The
composite editor this page used to document — two cards, Inner Geometry and Inner Transformer, and a
tree panel growing a slot for each — is gone from every slot the client edits.
Layout
One dense, outlined q-select labelled Transform, listing:
- No Transform — the geometry is used as authored.
- Static Translation, Static Rotation, Static Freeform, General Transform,
Dynamic Translation, Dynamic Rotation — the six transformer kinds a geometry can sit
under.
NoTransformis not an entry: an identity is what No Transform means, and the server keeps no wrapper around one.
Picking commits immediately; there is no Apply button. A transformer kind the client has no editor for (older data) is listed as the current value, so the picker is never blank.
In the Control Tree
A Geometry slot grows one kind node, …/type, and the picker is that node's header: with
Cylindroid selected under Raw Geometry, the panel shows the Transform picker over the
Cylindroid Z-R editor. With a transform on, the row is relabelled Transformed Cylindroid — a
file-backed kind keeps its file, Transformed StlFile [Geom/part.stl] — and grows one child,
…/type/transformer, labelled with the transformer's kind (General Transform), whose panel is
that kind's editor. The transformer's row comes last, after any children the kind grows itself (a
combination's items). Picking No Transform drops the row and the label returns to the bare kind.
The kind node's id does not change with the choice, so the selection and the expansion survive it.
The …/type/inner-geom and …/type/inner-transformer slots the composite kind used to grow no
longer exist.
Embedded
The Geometry Editor in its embedded form — the Topology column's anchor card, the cutter's Upper Beam section, a combination child's card — renders the kind picker, then the Transform picker, then the kind's editor, and beneath a separator the transformer's editor under a caption naming its kind.
Where It Is Offered
The picker appears only where two things hold: the slot's owner exposes a Set…Transform route (the
owner has to re-point its own field, not just the store entry), and the kind beneath it can sit under
a transform — Box3d, Cylindroid, StlFile, GeomCombination.
| Slot | Route the picker calls |
|---|---|
| Workpiece Raw Geometry | POST /api/Workpiece/SetRawGeometryTransform?geometryKey=&transformerType= |
| Workpiece Target Geometry | POST /api/Workpiece/SetIdealGeometryTransform?geometryKey=&transformerType= |
| An anchor's solid, on the Topology column's anchor card | POST /api/mech/equipment-topology/{owner}/anchor/{id}/set-geom-transform?transformerType= |
| Freeform holder Geometry | POST /api/FreeformHolder/SetGeometryTransform?toolId=&geometryKey=&transformerType= |
| A combination's child | POST /api/GeomCombination/SetItemTransformAt?geomCombinationKey=&index=&transformerType= |
| A wrapper nested inside a wrapper (older data) | POST /api/TransformationGeom/SetGeomTransform?transformationGeomKey=&transformerType= |
| Cutter Upper Beam | POST /api/Cutter/{id}/upper-beam/set-transform?key=&transformerType= |
It is absent on the cutter's Inner Beam — a custom spinning profile reads a geometry's Z-R list only
under an identity, so that slot offers no picker — and under MeshedGeomFile (a CubeTreeFile is
no IGetStl) and ExtendedCylinder (its start section is wired by its host at assignment, which a
wrapper would hide from that host).
Behavior
- Wrap, swap, unwrap — in place. Each route takes
transformerType, a transformer kind orNone, and applies it to what the slot holds: a bare geometry plus a kind becomes a wrapper around that very object; a wrapper plus a kind gets a fresh transformer of that kind; a wrapper plusNonehands its inner geometry back to the owner. The authored geometry is never rebuilt. The route answers the slot key — empty when the slot ended up empty — and keeps the{key}-Geom/{key}-Transformeraliases in step with it. A slot holding nothing answers409, and so do anExtendedCylinderand aCubeTreeFile; an unknown kind answers400. - A wrapper whose transformer is null or
NoTransformreads as untransformed. That is what older project files hold: the client presents the inner kind with No Transform, and mints noNoTransformon its behalf. Picking a transform fills that wrapper in place; picking another kind replaces the whole slot, so the owner ends up holding the bare geometry. - A wrapper with no geometry reads as an empty slot. That is what
enable-geomhangs on an anchor, what a fresh freeform holder carries, and what aCreate…Geometry?geometryType=TransformationGeomcall produces: the kind picker reads None (unset) where the host offers it, and no kind node appears. Picking a kind creates it inside the wrapper when the wrapper carries a transform (which is kept — a shape only reachable over REST); an empty wrapper carrying none is replaced by the bare geometry. - A kind switch keeps the transform. On a transformed slot, picking another wrappable kind
creates the new geometry inside the wrapper; picking
MeshedGeomFile, which cannot be wrapped, replaces the whole slot; None (unset) clears the slot, wrapper and all. - Badges follow the presentation. The Workpiece root's Raw / Target badges and the anchor card's
type badge read the kind, or Transformed {kind} — never
TransformationGeom. - A refused choice rolls back. The error toasts as Set transform: … and the picker returns to the value in force.
Source Code Path
See HiNC App Anatomy for git repository links.
HiNC-2025-webservice (Quasar CLI SPA):
wwwroot-src/src/components/geom/GeometryTransformSelect.vue— the picker: the choice list, the immediate commit through the owner'sonSetTransformhook, thechangedanderrorevents.wwwroot-src/src/components/geom/geometrySlot.ts—TransformChoice,TRANSFORMABLE_GEOM_KINDS,resolveGeometrySlot()(a wrapper presented as its inner kind; a null orNoTransformtransformer asNone, without callingIndexTransformer) andgeometrySlotBadge().wwwroot-src/src/components/geom/GeometryEditor.vue— the embedded form: kind picker, Transform picker, kind editor, transformer editor; the kind switch that creates inside a wrapper.wwwroot-src/src/components/controlTree/itemTypes.ts—buildGeometryChildren: the kind node'sctx.transform, the Transformed {kind} label and the…/type/transformerchild;buildSubtreeappends that child last.wwwroot-src/src/components/controlTree/PrimarySlavePanel.vue— renders the picker over the kind node's panel, bound to the host'ssetNodeTransform, which calls the owner's hook, runs the slot's commit chain, rebuilds the slot branch and re-expands the kind node — addressed by the node the picker was rendered for, so a selection change mid-request cannot drop the follow-up.wwwroot-src/src/components/controlTree/useControlTreeHost.ts,wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts,wwwroot-src/src/components/mech/EquipmentTopologyPanel.vue,wwwroot-src/src/components/toolhouse/UpperBeamDiv.vueandwwwroot-src/src/components/geom/GeomCombinationEditor.vue— the hosts that pass anonSetTransformhook;wwwroot-src/src/components/toolhouse/InnerBeamDiv.vuedeliberately passes none.wwwroot-src/src/components/geom/TransformationGeomEditor.vue— the legacy composite editor, reached only for a wrapper nested inside a wrapper; its inner geometry carries the same picker.wwwroot-src/src/api/workpiece.ts,wwwroot-src/src/api/equipmentTopology.ts,wwwroot-src/src/api/freeformHolder.ts,wwwroot-src/src/api/geometry.tsandwwwroot-src/src/api/toolHouse.ts— the typed wrappers over the seven routes.wwwroot-src/src/i18n/en/common.ts(labels.transform),wwwroot-src/src/i18n/en/geom.ts(editor.noTransform,editor.setTransformFailed) andwwwroot-src/src/i18n/en/tree.ts(node.transformedGeometry).Geom/GeomSlotTransform.cs—CreateTransformer,Apply(wrap / swap / unwrap and the refusals) andReindex(the slot key and its two aliases).Mech/WorkpieceController.cs,Mech/Topology/EquipmentTopologyController.cswithMech/Topology/TopologyEditService.cs,Mech/FreeformHolderController.cs,Geom/GeomCombinationController.cs,Geom/TransformationGeomController.csandMech/CutterController.cs— the sevenSet…Transformroutes.Geom/TransformationGeomController.cs— also the type's own REST surface at/api/TransformationGeom/*, which scripts still use:New,Get,IndexGeom,IndexTransformer,CreateGeom,CreateTransformer,UpdateTransformer,GetGeomTypeandGetTransformerType.IndexTransformerinstalls aNoTransformon a null field, which is why the client reads a wrapper throughGetand never indexes an absent transformer.
See Also
- Transformers — what each transformer kind does to a frame
- Geometry Editor — the kind picker this picker sits beside, and the hosts that offer both
- Transformer Select Panel — the seven transformer editors the transformer row and card resolve through
- Control Tree — the slot and kind node pattern the transformer row extends