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:
{}
#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
srcXElementSource XML element.
Properties
Name
Syntax kind name (typically the concrete type name).
public string Name { get; }
Property Value
XName
XML element name used to register this syntax with XFactory.
public static string XName { get; }
Property Value
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
syntaxPieceNodeLazyLinkedListNode<SyntaxPiece>ncDependencyListList<INcDependency>ncDiagnosticProgressNcDiagnosticProgress
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
baseDirectorystringThe base directory for resolving relative paths
relFilestringThe relative file path for the XML source
exhibitionOnlyboolif 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
factoryXFactory