Table of Contents

Class PivotTransformationSyntax

Namespace
Hi.NcParsers.LogicSyntaxs
Assembly
HiMech.dll

ISO/Fanuc-family pivot gate: writes the PivotTransformSource entry into ProgramToMcTransform on blocks where the controller is interpreting commanded XYZ in a frame that needs the Pn→MC kinematic rigid transform — namely active RTCP (G43.4) or active tilted plane (G68/G68.2). On plain-mode blocks (no RTCP, no tilted plane), the controller treats commanded XYZ as machine-frame directly, so the indexed rotary angle is a positioning value only and must not fold into the linear axes; this syntax skips those blocks and leaves the chain at identity (or whatever non-kinematic offsets earlier syntaxes contributed). Brand variants with their own modal vocabulary gate the same shared engine (PivotTransformUtil): Siemens TRAORI/CYCLE800 → SiemensPivotTransformationSyntax; Heidenhain M128/PLANE SPATIAL would follow the same pattern.

Mirrors real Fanuc semantics: plain G43 offsets along the active tilted-plane normal (or machine Z when no tilt is active), and plain XYZ moves map directly to machine axis registers regardless of indexed table/head rotary position. Only G43.4 follows the live tool vector and only G68.2 redefines the work-plane orientation — both of which this guard detects via the existing chain markers.

Chain position: must run after all Pn-frame writers (IsoG68p2TiltSyntax, ToolHeightOffsetSyntax, G43p4RtcpSyntax, IsoCoordinateOffsetSyntax, brand-specific coord offset syntaxes) so the guard sees the finalised mode markers and the PivotTransform entry — when emitted — naturally lands as the last chain element. Must run before McXyzSyntax / ProgramXyzSyntax so they see the completed chain.

Silently no-ops when IMachineKinematics is absent (3-axis configurations without rotary kinematics).

public class PivotTransformationSyntax : ISituNcSyntax, INcSyntax, IMakeXmlSource
Inheritance
PivotTransformationSyntax
Implements
Inherited Members
Extension Methods

Examples

Real-kinematics cases below wire TestDeps.CodeKinematics with the default chain code [O][Z][A][w];[O][Y][X][B][S][t] — a table-A / head-B 5-axis machine. A is on the table side (rotates the workpiece around -X); B is on the head side (rotates the spindle around +Y). Both rotary pivot axes pass through the origin (0,0,0) of the chain root frame because CodeXyzabcChain uses zero-offset Branch.Attach between components — a real table-head machine usually has the spindle-B pivot offset from origin, but for the corpus the zero-offset chain keeps the matrices hand-verifiable. Realistic MachineCoordinateState carries A and/or B only; there is no C axis in this chain (5-axis machines have at most two rotary axes).

Verification cue specific to this syntax: with origin pivots, table-A rotation moves the workpiece's coordinate frame around the X axis through origin, so the four-basis probe of MakePivotTransformMat(IMachineKinematics, Vec3d) returns a pure rotation around X — case 3 below pulls out exactly Rx(45°) (no translation column) for table-A=45°. Head-B rotation maps every probe point through the same head-chain rotation, but because everything on the head side downstream of B is at origin before B applies, the rotation reduces to the identity on the probe set: K_0 == K_abc and K_0 · K_abc⁻¹ collapses to identity. That is the symmetry the plain-mode bug fix relies on — head-side rotary was harmlessly writing identity matrices, while table-side rotary was silently rotating linear axes into MC.

Plain-mode skip — kinematics dep is present but the block has no active tilted plane and no RTCP, so ShouldFoldKinematicPivot returns false and the syntax leaves the block untouched. This is the "no work to do" guard that prevents over-application of the kinematic transform on indexed-rotary plain XYZ moves:

#BeforeBuild:
{}
#AfterBuild:
{}
Plain-mode skip with indexed rotary — same guard, but the block already carries a MachineCoordinateState.A = 45 indexed table angle (as a prior McAbcSyntax would have written). In a real Fanuc controller, commanded XYZ on this block goes straight to the machine axis registers regardless of A; the kinematic rotation must not be folded into the chain. Real XyzabcSolver dep is wired in so the guard is what stops the write (not the dep-guard at the top of Build): #BeforeBuild:
{ "MachineCoordinateState": { "A": 45 } }
#AfterBuild:
{ "MachineCoordinateState": { "A": 45 } }
Active RTCP signalled by a pre-existing Dynamic chain entry (as G43p4RtcpSyntax would have written when RTCP is active and ABC changes across the block). HasDynamicEntry(JsonObject) returns true, so the guard passes and the PivotTransform entry is written and tagged KindDynamic. The TestDeps.Kinematics stub makes MakePivotTransformMat(IMachineKinematics, Vec3d) collapse to identity: #BeforeBuild:
{
  "ProgramToMcTransform": [
    {
      "Source": "ToolHeightCompensation",
      "Kind": "Dynamic",
      "Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
    }
  ]
}
#AfterBuild:
{
  "ProgramToMcTransform": [
    {
      "Source": "ToolHeightCompensation",
      "Kind": "Dynamic",
      "Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
    },
    {
      "Source": "PivotTransform",
      "Kind": "Dynamic",
      "Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
    }
  ]
}
Active G68.2 tilted plane — the current block carries the modal TiltTransform snapshot plus an existing Static TiltTransform chain entry (as IsoG68p2TiltSyntax would have written) and MachineCoordinateState.A = 45. The guard reads TiltTransform.Term = "G68.2" and passes; with real XyzabcSolver kinematics (table-A / head-B 5-axis), MakePivotTransformMat at abc = (π/4, 0, 0) produces the table-A Rx(45°) rigid matrix. No Dynamic entries in the chain so the new entry stays Static: #BeforeBuild:
{
  "TiltTransform": { "Term": "G68.2", "X": 0, "Y": 0, "Z": 0, "I": 0, "J": 30, "K": 0 },
  "ProgramToMcTransform": [
    {
      "Source": "TiltTransform",
      "Kind": "Static",
      "Mat4d": [
        1, 0, 0, 0,
        0, 0.8660254037844387, 0.49999999999999994, 0,
        0, -0.49999999999999994, 0.8660254037844387, 0,
        0, 0, 0, 1
      ]
    }
  ],
  "MachineCoordinateState": { "A": 45 }
}
#AfterBuild:
{
  "TiltTransform": { "Term": "G68.2", "X": 0, "Y": 0, "Z": 0, "I": 0, "J": 30, "K": 0 },
  "ProgramToMcTransform": [
    {
      "Source": "TiltTransform",
      "Kind": "Static",
      "Mat4d": [
        1, 0, 0, 0,
        0, 0.8660254037844387, 0.49999999999999994, 0,
        0, -0.49999999999999994, 0.8660254037844387, 0,
        0, 0, 0, 1
      ]
    },
    {
      "Source": "PivotTransform",
      "Kind": "Static",
      "Mat4d": [
        1, 0, 0, 0,
        0, 0.7071067811865475, -0.7071067811865475, 0,
        0, 0.7071067811865475, 0.7071067811865475, 0,
        0, 0, 0, 1
      ]
    }
  ],
  "MachineCoordinateState": { "A": 45 }
}

Constructors

PivotTransformationSyntax()

Initializes a new instance with default settings.

public PivotTransformationSyntax()

PivotTransformationSyntax(XElement)

Initializes a new instance by deserializing from the given XML element.

public PivotTransformationSyntax(XElement src)

Parameters

src XElement

Source XML element.

Properties

Name

Syntax kind name (typically the concrete type name).

public string Name { get; }

Property Value

string

XName

XML element name used to register this syntax with XFactory.

public static string XName { get; }

Property Value

string

Methods

Build(LazyLinkedListNode<SyntaxPiece>, List<INcDependency>, NcDiagnosticProgress)

Build syntax arrangement into the syntaxPieceNode in-place.

public void Build(LazyLinkedListNode<SyntaxPiece> syntaxPieceNode, List<INcDependency> ncDependencyList, NcDiagnosticProgress ncDiagnosticProgress)

Parameters

syntaxPieceNode LazyLinkedListNode<SyntaxPiece>
ncDependencyList List<INcDependency>
ncDiagnosticProgress NcDiagnosticProgress

MakeXmlSource(string, string, bool)

Creates an XML representation of the object. This method may also generate additional resources such as related files.

public XElement MakeXmlSource(string baseDirectory, string relFile, bool exhibitionOnly)

Parameters

baseDirectory string

The base directory for resolving relative paths

relFile string

The relative file path for the XML source

exhibitionOnly bool

if true, the extended file creation is suppressed.

Returns

XElement

An XML element representing the object's state

Remarks

For the demand of easy moving source folder (especially project folder) without configuration file path corruption, the relative file path is applied. The baseDirectory is typically the folder at the nearest configuration file folder. Since the folder can be moving with the configuration file.

Reg(XFactory)

Registers this type's deserializer with the given XFactory (or Default when factory is null). Idempotent.

public static void Reg(XFactory factory = null)

Parameters

factory XFactory