This commit is contained in:
2026-09-11 03:46:11 +08:00
parent 45b9f9ed5d
commit b7f55aa631
114 changed files with 3646 additions and 576 deletions
@@ -95,6 +95,10 @@
<li>T2 Drill bit, diameter unrestricted</li>
</ul>
<p>Click to download <a href="smart-holder-training-img/train.nc">NC code</a>.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p><strong>What this set determines, and what it does not.</strong> Both <a href="#shape-ii">Shape II</a> passes run T1, so the milling passes span two feeds per tooth — 0.1 and 0.05 — at a single helix angle. That is a spread in the right variable, and a narrow one: it works on the slopeintercept collinearity between the shear and the ploughing coefficients. Nothing in the set works on the other degeneracy, the bending-moment plane null: one combination of the edge and normal shear coefficients stays unobservable, and a set of symmetric four-flute passes carries no cutter phase of its own. Which way the run then fails depends on the channels measured — with the axial torque channel present (<code>IsMzEnabled</code>, see <a class="xref" href="../../workflows/force-training.html">Force Training</a>) the fit converges and reports a high correlation over shear values orders of magnitude too large; without it the fit collapses rather than degrading. Repeating <a href="#shape-ii">Shape II</a> with an end mill of a clearly different helix angle removes the plane null, but does not on its own make the set determined — a wider chip-load range across the passes is the other half. See <a href="training-cut-set-design.html">Designing a Training Cut Set</a>.</p>
</div>
<div class="NOTE">
<h5>Note</h5>
<p><strong>Adjusting Machining Method</strong></p>
@@ -136,9 +136,23 @@ not by the magnitude of any one coefficient.</p>
</div>
<h2 id="flute-count-is-not-a-lever">Flute Count Is Not a Lever</h2>
<p>Adding more passes with the same symmetric multi-flute cutter buys nothing, at any feed. That
sample subspace is degenerate, and more of it stays degenerate: a set made only of symmetric
four-flute passes cannot derive its own cutter phase, and the fit collapses rather than degrading.
What buys identifiability is spread — in helix angle, and in feed per tooth.</p>
sample subspace is degenerate, and more of it stays degenerate. Evenly spaced flutes also cancel
the rotation-averaged transverse moment a run derives its own cutter phase from, so a set made only
of symmetric passes carries no phase reference of its own. Which way it then fails depends on the
channels measured: with the axial torque channel present the fit still converges and reports a high
correlation over shear coefficients orders of magnitude too large; without it the fit collapses
rather than degrading. Neither outcome is usable, and adding passes repairs neither. What buys
identifiability is spread — in helix angle, and in feed per tooth.</p>
<p>Supplying the phase from outside removes that half of the problem and nothing else.
<a class="xref" href="../../api/Hi.MillingForces.Training.MillingTraining.html#Hi_MillingForces_Training_MillingTraining_EnableCwePhasePairing">EnableCwePhasePairing</a> <small>(API)</small> reads
each step's phase from the engagement blocks instead of bootstrapping it from the samples, for
one-flute and symmetric two-flute cutters in light radial side cuts; outside those preconditions the
training falls back to the bootstrapped path with a warning, so a four-flute set is not rescued by
it. The null a single helix angle leaves is untouched either way.</p>
<p>The shipped smart-holder cut set has exactly this shape: its milling passes are one symmetric
four-flute end mill at two feeds, so the set is spread in feed per tooth alone and does not
determine its own edge and normal shear values — see
<a href="smart-holder-training.html">Smart Holder Training</a>.</p>
<p>Symmetric off-the-shelf cutters are nonetheless sufficient. Custom single-flute grinding is not
required for either fix; a pair of stock two-flute cutters ground at different helix angles carries
the same identifiability, and is what a shop can actually obtain.</p>
@@ -174,7 +174,7 @@ Trans.x \cdot Step &amp; Trans.y \cdot Step &amp; Trans.z \cdot Step &amp; 1
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="topology.html">Kinematic Topology</a> — the anchors and branches these matrices move</li>
<li><a href="../../anatomy/geom/transformation-geom-control.html">TransformationGeomControl</a> — the app panel that wraps a geometry in one of these transforms</li>
<li><a href="../../anatomy/geom/transformation-geom-editor.html">TransformationGeomControl</a> — the app panel that wraps a geometry in one of these transforms</li>
</ul>
</article>
@@ -157,7 +157,7 @@ tip), so it includes the flute span</strong> — it is <em>not</em> the remainin
the flute top to the exposed end. It must therefore be <strong>larger than the flute
height</strong>: e.g. flute height 20 mm and 10 mm of shank above it → <code>FullLength = 30</code>, not 10. A value at or below the flute height inverts the beam solid;
thermal physics then cannot build its shank shell layers and reports a
<code>Cutter-UpperBeam--BelowFluteHeight</code> configuration error at tool change (the
<code>Cutter-UpperBeam--ExtendedCylinderFullLengthTooShort</code> configuration error at tool change (the
web editor rejects such a value outright).</p>
</li>
</ul>
@@ -125,11 +125,11 @@ statement it is.</p>
<tbody>
<tr>
<td><code>L</code></td>
<td>Straight-line motion with its axis words.</td>
<td>Straight-line motion with its axis words, absolute or <code>I</code>-prefixed incremental. See <a href="#incremental-axis-words-i-prefix">Incremental axis words</a>.</td>
</tr>
<tr>
<td><code>LN</code></td>
<td>Surface-normal block — a straight line carrying the endpoint plus up to two normalized vectors, in the fixed element order <code>X,Y,Z</code><code>NX,NY,NZ</code><code>TX,TY,TZ</code>. See <a href="#vector-blocks-ln">Vector blocks</a>.</td>
<td>Surface-normal block — a straight line carrying the endpoint plus up to two normalized vectors, in the fixed element order <code>X,Y,Z</code><code>NX,NY,NZ</code><code>TX,TY,TZ</code>. The endpoint words take the <code>I</code> prefix; the vector words have no incremental form. See <a href="#vector-blocks-ln">Vector blocks</a>.</td>
</tr>
<tr>
<td><code>FMAX</code></td>
@@ -137,7 +137,7 @@ statement it is.</p>
</tr>
<tr>
<td><code>CC</code> / <code>C</code></td>
<td>Circular motion — <code>CC</code> sets the pole, <code>C</code> states the end point. <code>DR-</code> is clockwise and <code>DR+</code> counter-clockwise, the centre always comes from the modal <code>CC</code> rather than from the <code>C</code> block, and an arc that closes on its start point is a full circle. See <a href="#arc-centres-cc">Arc centres</a>.</td>
<td>Circular motion — <code>CC</code> sets the pole, <code>C</code> states the end point. <code>DR-</code> is clockwise and <code>DR+</code> counter-clockwise, the centre always comes from the modal <code>CC</code> rather than from the <code>C</code> block, and an arc that closes on its start point is a full circle. Both heads accept <code>I</code>-prefixed words — an incremental pole on <code>CC</code>, an incremental end point on <code>C</code>. See <a href="#arc-centres-cc">Arc centres</a>.</td>
</tr>
<tr>
<td><code>RL</code> / <code>RR</code> / <code>R0</code></td>
@@ -149,7 +149,7 @@ statement it is.</p>
</tr>
<tr>
<td><code>M126</code> / <code>M127</code></td>
<td>Shortest-path rotary traverse on / off. With neither stated, shortest path is the default.</td>
<td>Shortest-path rotary traverse on / off. With neither stated, shortest path is the default. An <code>I</code>-prefixed rotary word is exempt either way — see <a href="#incremental-axis-words-i-prefix">Incremental axis words</a>.</td>
</tr>
<tr>
<td><code>M140 MB+n</code> / <code>M140 MB MAX</code></td>
@@ -169,6 +169,35 @@ statement it is.</p>
</tr>
</tbody>
</table>
<h3 id="incremental-axis-words-i-prefix">Incremental axis words (<code>I</code> prefix)</h3>
<p>An axis word may carry the <code>I</code> prefix — <code>IX+20</code>, <code>IY-15</code>, rotary <code>IC+90</code> — and is then a relative
value rather than a coordinate. Five statement heads read the prefix: <code>L</code>, <code>C</code>, <code>CC</code>, <code>LN</code> and
<code>CYCL CALL POS</code>. On the first four it is a distance from the last programmed position; <code>CYCL CALL POS</code> spells it the same way but measures from the coordinates of the previous <code>CYCL CALL POS</code>, and
is described under <a href="#cycles-and-calls">Cycles and calls</a>. <code>L</code>, <code>C</code> and <code>LN</code> take the full axis set,
rotary letters included; <code>CC</code> and <code>CYCL CALL POS</code> take <code>X</code> / <code>Y</code> / <code>Z</code> only, because neither
positions a rotary axis.</p>
<p>The prefix is per word, not a mode — klartext has no modal <code>G90</code> / <code>G91</code> counterpart, and only the
<code>I</code>-marked words of a block are read as distances. Absolute and incremental words therefore mix
freely inside one block.</p>
<blockquote>
<p>Parsed:</p>
<ul>
<li><code>L IX+20 IY-15</code> — both axes relative</li>
<li><code>L X+60 IY-10</code> — to X 60, and by 10 in Y</li>
<li><code>LIX+20IY-15</code> — glued, exactly as the separator-free absolute form parses</li>
<li><code>L IX5</code> — the sign is optional</li>
<li><code>L IZ+Q2</code> and <code>L IY-Q2</code> — the value grammar behind the prefix is the shared one, so a <code>Q</code>
parameter or a bracket expression reaches it like any other value</li>
</ul>
</blockquote>
<p>A rotary <code>I</code> word is a chain dimension — a signed traverse — and keeps the value it accumulates
instead of being folded into the ±180° shortest-path window: <code>IC+270</code> from 75° ends at 345°, not at
15°. That exemption is per word and per block. It does not turn shortest path off for the rest of
the block: an absolute rotary word on the very same block is still taken the short way round, and
<code>M127</code> remains the modal switch.</p>
<p>One further <code>I</code> spelling on this control is <strong>not</strong> this mechanism at all: the <code>CYCL DEF 7</code>
datum-shift words shift the active datum rather than positioning an axis, and are described under
<a href="#datums">Datums</a>.</p>
<h3 id="arc-centres-cc">Arc centres (<code>CC</code>)</h3>
<p>A <code>C</code> block never states its own centre. Each in-plane component is resolved from the modal <code>CC</code>
section: the <code>CC</code> block's own axis word first, then the same axis of the previous <code>CC</code>, and last the
@@ -176,6 +205,13 @@ arc's own start point. A <code>CC</code> stating no coordinates is the one spell
once — it takes the last programmed position, read at the <code>CC</code> block rather than at the arc, and
replaces the modal centre instead of inheriting it. That is what makes the manual's own shape work:
<code>CC</code> on the centre, a move out to the arc start, then the <code>C</code> block.</p>
<p>An incremental centre is not that spelling. <code>CC IX+0 IY+11</code> <strong>states</strong> a centre — a distance from
the last programmed <strong>tool</strong> position, never from the previous centre — and it is absolute by the
time the arc consumes it. Nor is a <code>CC</code> whose coordinates cannot be read: it leaves residue and
reports <code>UnparsedText--Remaining</code>, and because it states no centre every axis falls through the
modal chain — to the same axis of the previous <code>CC</code> where there is one, and only otherwise to the
arc's own start point as below. Either way the position of the unreadable <code>CC</code> block is never
read as the centre.</p>
<p>A centre that lands on the arc's own start point leaves the block with no radius and so no arc
geometry: it reports <code>Arc-CircleCenter--OnStartPoint</code> and is degraded to a straight move to the
endpoint. One in-plane coordinate is enough to escape that — an arc whose modal chain still leaves
@@ -237,6 +273,8 @@ number or a quoted tool name is accepted.</p>
<li><code>DL</code> is a length delta — the effective tool height is the tool-table height <strong>plus</strong> <code>DL</code>.</li>
<li><code>DR</code> is read and recorded but <strong>not applied</strong>: radius compensation uses the tool-table radius as-is,
and the block reports <code>ToolChange--DeltaUnsupported</code>.</li>
<li>A <code>DL</code>/<code>DR</code> that is not a literal value — an unevaluated variable, for example — is ignored and
reports <code>ToolChange--DeltaNotLiteral</code>.</li>
<li>A tool axis other than <code>Z</code> reports <code>ToolChange--AxisUnsupported</code>.</li>
<li>A <code>TOOL CALL</code> whose tool number could not be captured — an unevaluated variable, for example —
reports <code>ToolChange--MissingToolId</code>.</li>
@@ -255,6 +293,12 @@ CYCL DEF 7.2 Y22.223
CYCL DEF 7.3 Z32.97
</code></pre>
</blockquote>
<p>A <code>CYCL DEF 7</code> axis word may itself carry the <code>I</code> prefix — <code>CYCL DEF 7.2 IY+5</code> shifts the datum by a
further 5 in Y on top of the shift last valid. Unlike the <code>L</code> / <code>C</code> / <code>CC</code> / <code>LN</code> words, this one is not a
distance from the tool position at all: it stays inside the cycle's own record and never becomes per-word
incremental positioning, so it can never reach the optimizer's incremental guard. Only <code>X</code> / <code>Y</code> /
<code>Z</code> are applied; a non-zero rotary word there, <code>IC+90</code> as much as <code>C+90</code>, is consumed and reported as
<code>Datum-Shift--Rotary</code>.</p>
<h2 id="q-parameters-and-fn">Q parameters and FN</h2>
<p><code>Q</code>, <code>QR</code>, <code>QL</code> and <code>QS</code> parameters are read wherever a value is expected, so <code>FQ1</code> reaches the
feedrate, <code>L X+Q2</code> reaches the program position and <code>TOOL CALL SQ3</code> reaches the spindle speed. <code>Q0</code><code>Q99</code>
@@ -344,6 +388,13 @@ and a <code>Q211</code> bottom dwell to dwell drilling.</li>
<code>HeidenhainCycl--Unsupported</code>.</li>
<li><strong><code>CYCL CALL</code></strong> and <strong><code>CYCL CALL POS</code></strong> fire the cycle once; <code>M99</code> fires once and <code>M89</code> arms modal
firing.</li>
<li>A <strong><code>CYCL CALL POS</code></strong> position word takes the <code>I</code> prefix, and its reference is the control's own:
the coordinates last programmed by a <strong>previous <code>CYCL CALL POS</code></strong>, not the current tool position.
With no earlier call for that axis the increment has no reference and the control refuses the block
(its error <code>1A0-0108</code>); the simulation reports <code>HeidenhainCyclCall--IncrementalNoReference</code> and
resolves against the last programmed position instead. When the tool moved between the two calls
the two candidate references differ — the control's stated one is used, and the divergence is
reported as <code>HeidenhainCyclCall--IncrementalAfterMove</code>.</li>
<li><strong><code>CALL LBL n</code></strong> inlines the label body up to <code>LBL 0</code>; <strong><code>CALL LBL n REP m</code></strong> repeats that section
<code>m</code> times.</li>
<li><strong><code>CALL PGM</code></strong> resolves the called program by file name.</li>
@@ -384,12 +435,22 @@ never a parenthesized one, because a TNC reads parentheses as code:</p>
<pre><code>120 L X+35 Y-11.7 R0 F500 ;src(LineNo: 140, StepIndex: 256)
</code></pre>
<p>Re-interpolation itself is not refused for being klartext. A <code>C … DR±</code> arc splits like any other
when the modal <code>CC</code> chain supplies both in-plane centre coordinates: no centre words are rebuilt,
and each fragment carries the block's own words with its own endpoint and feed, around the one <code>CC</code>
line they all share unchanged. The arc that is optimized whole instead is the one whose modal chain
left an in-plane coordinate unstated — no <code>CC</code> ever gave it, so the arc's own start point supplies
it, and every fragment would re-derive that centre from its own start. Such pieces are optimized as
whole lines under <code>NcOpt--SplitionStartPointCenterUnsupported</code>, raised once per run.</p>
when the modal <code>CC</code> chain supplies both in-plane centre coordinates <strong>and</strong> the <code>C</code> block states its
own words absolutely: no centre words are rebuilt, and each fragment carries the block's own words
with its own endpoint and feed, around the one <code>CC</code> line they all share unchanged. An incremental
<code>CC</code> does not disqualify the arc it feeds — the per-word mark sits on the <code>CC</code> block alone and never
carries forward, and the centre reaches the arc already resolved.</p>
<p>Two shapes are optimized as whole lines instead. Each reports its own id, once per run.</p>
<ul>
<li>The arc whose modal chain left an in-plane coordinate unstated — no <code>CC</code> ever gave it, so the arc's
own start point supplies it, and every fragment would re-derive that centre from its own start:
<code>NcOpt--SplitionStartPointCenterUnsupported</code>.</li>
<li>The piece that carries an incremental word of its own — a klartext <code>I</code>-prefixed word, as in the
legal and fully simulated <code>C IX+20 IY+0 DR-</code>, or a <code>G91</code> block in the DIN/ISO dialect. The fragment
rewrite emits absolute coordinates, so every fragment would re-apply the distance from its own
start: <code>NcOpt--SplitionIncrementalUnsupported</code>. The test reads the piece's own block only — the
state of the modal <code>CC</code> chain neither triggers this one nor exempts a piece from it.</li>
</ul>
<h2 id="not-supported">Not supported</h2>
<p><code>TOOL DEF</code>, <code>FK</code> free-contour programming, <code>SL</code> cycles, <code>PATTERN DEF</code>, and <code>TCH PROBE</code>. These are left
unconsumed, and the block that carried them reports <code>Parsing--Unconsumed</code> naming the words.</p>
@@ -262,6 +262,13 @@ carries motion is the last corner's partner instead, and the compensated path me
line at their intersection (Fanuc type B); the legacy interpreter
(<a class="xref" href="../../api/Hi.MachiningProcs.SessionShell.html#Hi_MachiningProcs_SessionShell_EnableSoftNcRunner">EnableSoftNcRunner</a> set <code>false</code>) ends that case
perpendicular.</li>
<li><strong>The D row must match the program's strategy.</strong> A zero-based program (the CAM path is the
tool-centre path, <code>G41 D..</code> kept for wear only) needs a D row whose geometry radius is 0; a
cutter-radius program (the NC is the part contour) needs the tool radius there. An offset larger
than an inner arc or groove of the contour makes the compensated path run against the programmed
direction — a control stops with an interference alarm (Fanuc PS0041), HiNC reports
<code>RadiusComp--Interference</code> and keeps playing the swapped-side path. The radius basis of the
tool-house refresh is chosen on <a class="xref" href="../../anatomy/general-setup/controller/program-data/tool-offsets.html">Tool Offsets</a>.</li>
</ul>
<h3 id="rotation-tilted-planes-and-five-axis">Rotation, tilted planes and five-axis</h3>
<table>
@@ -396,13 +403,17 @@ the Fanuc, Syntec and Mazak presets:</p>
<td>High-speed cycle machining. The real machine executes cycle data pre-registered in its variable area, which is <strong>actual axis motion HiNC cannot see</strong>, so the simulated result misses that machining. Reports <code>Hpcc--HighSpeedCycleIgnored</code> as a warning.</td>
</tr>
<tr>
<td>anything else, or no <code>P</code> at all</td>
<td>anything else</td>
<td>Not supported offline and ignored, reported as <code>Hpcc--UnsupportedFunction</code>. Small <code>P</code> values select the high-speed remote buffer modes.</td>
</tr>
<tr>
<td>no <code>P</code> at all</td>
<td>Not supported offline and ignored, reported as <code>Hpcc--MissingFunctionWord</code>.</td>
</tr>
</tbody>
</table>
<p>An unevaluated macro variable or expression in <code>P</code> is tolerated — it reports
<code>Hpcc--UnsupportedFunction</code> rather than failing the block.</p>
<code>Hpcc--UnevaluatedFunction</code> rather than failing the block.</p>
<h3 id="m-codes">M codes</h3>
<table>
<thead>
@@ -375,7 +375,7 @@ misread as something else — a <code>PLANE AXIAL B+45</code> will not be mistak
<tr>
<td><strong>Fanuc</strong></td>
<td>ISO core, canned cycles G73G89, G41/G42, G43.4 RTCP, G53/G53.1, G68/G68.2/G69, G12.1/G13.1 polar with compensation, Custom Macro B (<code>#</code> variables, <code>IF</code>/<code>GOTO</code>, <code>WHILE</code>/<code>DO</code>), <code>M98</code>/<code>M99</code> subprograms, <code>G65</code>/<code>G66</code>/<code>G67</code> macro calls</td>
<td>bare <code>G05 P</code> HPCC selections (<code>Hpcc--NoOp</code>, <code>Hpcc--HighSpeedCycleIgnored</code>, <code>Hpcc--UnsupportedFunction</code>)</td>
<td>bare <code>G05 P</code> HPCC selections (<code>Hpcc--NoOp</code>, <code>Hpcc--HighSpeedCycleIgnored</code>, <code>Hpcc--UnsupportedFunction</code>, <code>Hpcc--UnevaluatedFunction</code>, <code>Hpcc--MissingFunctionWord</code>)</td>
<td><code>G10</code> programmable data setting, <code>G50</code> spindle limit, <code>G31</code> skip</td>
</tr>
<tr>
@@ -386,7 +386,7 @@ misread as something else — a <code>PLANE AXIAL B+45</code> will not be mistak
</tr>
<tr>
<td><strong>Heidenhain</strong></td>
<td>klartext motion and <code>FMAX</code>, <code>LN</code> surface-normal blocks resolved into the rotary axes, <code>M91</code>, <code>TOOL CALL</code> with <code>DL</code>/<code>DR</code>, <code>CYCL DEF 247</code> presets and <code>CYCL DEF 7</code> additive shifts, <code>CC</code>/<code>C</code> arcs, <code>RL</code>/<code>RR</code>/<code>R0</code>, <code>M126</code>/<code>M127</code>, <code>M140</code>, <code>CYCL DEF 32</code>, Q/QR parameters with the FN grammar and FN 912 jumps, <code>PLANE SPATIAL</code>, <code>FUNCTION TCPM</code>, <code>M128</code>/<code>M129</code>, machining cycles 200/232/251/252/253, <code>CYCL CALL</code>/<code>CYCL CALL POS</code>, <code>CALL LBL</code> with <code>REP</code>, <code>CALL PGM</code>, tilde continuation, <code>BLK FORM</code>, <code>STOP</code>, mirror image (<code>G28</code> and <code>CYCL DEF 8</code>), and the DIN/ISO dialect with absolute <code>I</code>/<code>J</code>/<code>K</code> centres, the ISO label family, <code>G247</code>, <code>G54</code> datum words and <code>G70</code>/<code>G71</code></td>
<td>klartext motion and <code>FMAX</code>, <code>LN</code> surface-normal blocks resolved into the rotary axes, <code>M91</code>, <code>TOOL CALL</code> with <code>DL</code>/<code>DR</code>, <code>CYCL DEF 247</code> presets and <code>CYCL DEF 7</code> additive shifts, <code>CC</code>/<code>C</code> arcs, <code>I</code>-prefixed incremental axis words on <code>L</code>/<code>LN</code>/<code>C</code> (rotary included) and on <code>CC</code>/<code>CYCL CALL POS</code> (<code>X</code>/<code>Y</code>/<code>Z</code> only), <code>RL</code>/<code>RR</code>/<code>R0</code>, <code>M126</code>/<code>M127</code> with an incremental rotary word exempt from the shortest-path fold, <code>M140</code>, <code>CYCL DEF 32</code>, Q/QR parameters with the FN grammar and FN 912 jumps, <code>PLANE SPATIAL</code>, <code>FUNCTION TCPM</code>, <code>M128</code>/<code>M129</code>, machining cycles 200/232/251/252/253, <code>CYCL CALL</code>/<code>CYCL CALL POS</code>, <code>CALL LBL</code> with <code>REP</code>, <code>CALL PGM</code>, tilde continuation, <code>BLK FORM</code>, <code>STOP</code>, mirror image (<code>G28</code> and <code>CYCL DEF 8</code>), and the DIN/ISO dialect with absolute <code>I</code>/<code>J</code>/<code>K</code> centres, the ISO label family, <code>G247</code>, <code>G54</code> datum words and <code>G70</code>/<code>G71</code></td>
<td><code>PLANE VECTOR</code> (captured), <code>PLANE EULER</code> / <code>POINTS</code> / <code>RELATIV</code> / <code>AXIAL</code> / <code>PROJECTED</code> (<code>HeidenhainPlane--Unsupported</code>), unimplemented <code>FN</code> opcodes such as <code>FN 18 SYSREAD</code>, unrecognized <code>CYCL DEF</code> bodies (<code>HeidenhainCycl--Unsupported</code>), center-referenced <code>FUNCTION TCPM REFPNT</code> (<code>Orientation-RefPoint--CntNotSimulated</code>), and 3D-ToolComp along the <code>LN</code> surface normal (<code>SurfaceNormal--CompNotSimulated</code>)</td>
<td><code>TOOL DEF</code>, <code>FK</code> free contour, <code>SL</code> cycles, <code>PATTERN DEF</code>, <code>TCH PROBE</code></td>
</tr>
@@ -410,6 +410,21 @@ misread as something else — a <code>PLANE AXIAL B+45</code> will not be mistak
and <code>ReferenceReturnSyntax</code> is not in that preset's Logic list. <code>HardNcRunner</code> keeps the Fanuc
reading, so the two engines are deliberately divergent on Heidenhain <code>G28</code> files.</p>
</div>
<div class="NOTE">
<h5>Note</h5>
<p><strong>Per-word incremental positioning is one mechanism, shared across brands.</strong> The Siemens <code>IC()</code>
wrapper and the klartext <code>I</code> prefix both write the value under the plain axis key and stamp a
per-axis entry — <code>&quot;PositioningOverride&quot;: {&quot;Y&quot;:&quot;Incremental&quot;}</code> — on the block root, so absolute and
incremental words mix inside one block and only the marked axis is relative: on <code>IC()</code> and on the
klartext <code>L</code> / <code>LN</code> / <code>C</code> / <code>CC</code> heads, a distance from the last programmed position; on
<code>CYCL CALL POS</code>, from the coordinates of the previous <code>CYCL CALL POS</code>. The Siemens coded family
(<code>CAC()</code>, <code>CIC()</code> and the rest) stamps the same section with <code>CodedAbsolute</code> / <code>CodedIncremental</code>
instead of the plain pair, and the optimizer's incremental guard reads <code>CodedIncremental</code> too. That section is non-modal: it appears in no <code>ModalCarry</code> key
set and never reaches the next block. Klartext states no modal <code>G90</code>/<code>G91</code> at all — its
<code>Positioning</code> section stays at the <code>G90</code> default, and only the DIN/ISO dialect on that brand
carries the modal pair. The <code>CYCL DEF 7</code> datum-shift <code>I</code> words are a separate thing and write no
override entry: they shift the active datum rather than measure from the tool position.</p>
</div>
<h2 id="scope-and-testing">Scope and testing</h2>
<p>Two limits sit outside the per-brand table and apply to everything in it.</p>
<ul>