Table of Contents

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. NoTransform is 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 or None, 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 plus None hands 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}-Transformer aliases in step with it. A slot holding nothing answers 409, and so do an ExtendedCylinder and a CubeTreeFile; an unknown kind answers 400.
  • A wrapper whose transformer is null or NoTransform reads as untransformed. That is what older project files hold: the client presents the inner kind with No Transform, and mints no NoTransform on 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-geom hangs on an anchor, what a fresh freeform holder carries, and what a Create…Geometry?geometryType=TransformationGeom call 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's onSetTransform hook, the changed and error events.
  • wwwroot-src/src/components/geom/geometrySlot.ts — TransformChoice, TRANSFORMABLE_GEOM_KINDS, resolveGeometrySlot() (a wrapper presented as its inner kind; a null or NoTransform transformer as None, without calling IndexTransformer) and geometrySlotBadge().
  • 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's ctx.transform, the Transformed {kind} label and the …/type/transformer child; buildSubtree appends that child last.
  • wwwroot-src/src/components/controlTree/PrimarySlavePanel.vue — renders the picker over the kind node's panel, bound to the host's setNodeTransform, 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.vue and wwwroot-src/src/components/geom/GeomCombinationEditor.vue — the hosts that pass an onSetTransform hook; wwwroot-src/src/components/toolhouse/InnerBeamDiv.vue deliberately 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.ts and wwwroot-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) and wwwroot-src/src/i18n/en/tree.ts (node.transformedGeometry).
  • Geom/GeomSlotTransform.cs — CreateTransformer, Apply (wrap / swap / unwrap and the refusals) and Reindex (the slot key and its two aliases).
  • Mech/WorkpieceController.cs, Mech/Topology/EquipmentTopologyController.cs with Mech/Topology/TopologyEditService.cs, Mech/FreeformHolderController.cs, Geom/GeomCombinationController.cs, Geom/TransformationGeomController.cs and Mech/CutterController.cs — the seven Set…Transform routes.
  • Geom/TransformationGeomController.cs — also the type's own REST surface at /api/TransformationGeom/*, which scripts still use: New, Get, IndexGeom, IndexTransformer, CreateGeom, CreateTransformer, UpdateTransformer, GetGeomType and GetTransformerType. IndexTransformer installs a NoTransform on a null field, which is why the client reads a wrapper through Get and 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