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
@@ -380,6 +380,8 @@ ownership rules that keep them on the project</li>
<li><a class="xref" href="../../platform/control-tree.html">Control Tree</a> — the engine that builds, rebuilds and selects this branch</li>
<li><a class="xref" href="../../legacy-controller.html">Legacy Controller Page</a> — the superseded HardNcEnv route this branch replaces, still shipped
at <code>/controller</code></li>
<li><a class="xref" href="../../legacy-controller-settings.html">Legacy Controller Settings</a> — the model that route edits, what this branch shares with
it, and the three settings it holds alone</li>
</ul>
</article>
@@ -117,13 +117,18 @@ Heidenhain after the rightmost <code>DR+</code>/<code>DR-</code> and <code>RL</c
holds — and the shape of the source note the optimizer embeds, a <code>;</code> comment on Heidenhain and a
parenthesized one on the rest. The radius-compensation syntax all five presets
carry reads it too, raising its negative-radius validation warning only where the marker is
Heidenhain. <strong>The piece classifier does not read it</strong>: none of its re-interpolation guards is
keyed on the brand, and the guard that singles a klartext arc out is keyed on where the arc's
centre came from. So an arc centred on a modal <code>CC</code> line splits like any other, and the one
refused (<code>NcOpt--SplitionStartPointCenterUnsupported</code>) is the arc whose <code>CC</code> chain left an
in-plane coordinate for its own start point to supply. An arc whose centre falls entirely on its
start point never reaches that guard: with no radius it is not an arc at all, so it warns
<code>Arc-CircleCenter--OnStartPoint</code> and is degraded to a chord as the program is read.</p>
Heidenhain. <strong>The piece classifier does not read it</strong>: neither of its re-interpolation guards is keyed
on the brand — one keys on where the arc's centre came from, the other on the piece's own
incremental words. So a klartext arc centred on a
modal <code>CC</code> line splits like any other, provided the chain supplies both in-plane centre coordinates
and the <code>C</code> block states its own words absolutely; an incomplete chain
(<code>NcOpt--SplitionStartPointCenterUnsupported</code>) and an incremental word on the block itself
(<code>NcOpt--SplitionIncrementalUnsupported</code>) are each optimized as whole lines, and
<a class="xref" href="../../../../technique/nc-dialects/controller-heidenhain.html">Heidenhain Support</a> states both. An arc whose centre falls
entirely on its start point never reaches the centre guard: with no radius it is not an arc at all,
so it warns <code>Arc-CircleCenter--OnStartPoint</code> and is degraded to a chord as the program is read. The
incremental guard is not conditioned on the block being an arc, so a degraded chord that still
carries an <code>I</code> word trips it like any other line.</p>
<p>Each of the five properties returns a <strong>new instance per read</strong>, so no two projects can share one
preset and the returned runner is safe to mutate before it is installed. The five brand tokens are
declared once as constants on the brand dependency and are then enumerated again, independently, in
@@ -531,7 +536,8 @@ one free-form string property, with no behaviour of its own; its readers live el
<li><code>HiMech/NcOpt/SoftNcOptProc.cs</code> — where NC optimization reads the marker back out of the session's
effective dependency list, for the writeback grammar.</li>
<li><code>HiMech/NcOpt/NcOptPieceClassifier.cs</code> — the re-interpolation guards, none of them keyed on the
brand; the arc guard keys on the centre's provenance instead.</li>
brand; the two a klartext arc can reach key on the centre's provenance and on the piece's own
incremental words instead.</li>
<li><code>HiMech/NcParsers/Keywords/Generic/ArcCenterSource.cs</code> — the two centre-provenance stamps: the one
the arc guard refuses, and the one that tells the writeback a split arc's fragments share the <code>CC</code>
line unchanged. An arc whose own block states its centre carries neither.</li>
@@ -317,7 +317,8 @@ tool length low.</p>
missing pair and the millimetre value it used instead. A fallback that finds <code>NaN</code> — the sentinel the
generic ledger's tool-house refresh writes for a tool whose tip length does not resolve — raises a
configuration warning of its own and degrades to 0 rather than composing a non-finite translation.
Both carry the code <code>SiemensToolOffset--TcdpRowMissing</code>.</p>
The usable-height arm carries the code <code>SiemensToolOffset--TcdpRowMissing</code>; the <code>NaN</code> arm carries
<code>SiemensToolOffset--TcdpRowMissingGenericHeightNaN</code>.</p>
<p>The fallback crosses the sign boundary. What it reads out of the generic table is that table's own
effective height, ideal minus wear; what it substitutes is a <code>$TC_DP</code> height, geometry plus wear. A
project that keeps wear in both places therefore compensates in one direction while the row exists
@@ -143,7 +143,12 @@ from different things and can disagree — one of the departures catalogued in
<a class="xref" href="../editing-contract.html">Editing Contract</a>.</p>
<h2 id="what-a-row-holds">What a Row Holds</h2>
<p>The table is the Fanuc Memory C layout: the H number and the D number address the same row, so one
row carries both the length and the radius of one offset.</p>
row carries both the length and the radius of one offset. Fanuc's older memory types are narrower —
Memory A keeps a single value per offset number (no geometry/wear split, and H and D read the same
number), Memory B splits geometry from wear but still lets H and D share one value — so a program
written for those controls calls the radius by a different number than the length (<code>G43 H3</code> with
<code>G41 D33</code>, say). A program that pairs <code>H3</code> with <code>D3</code> therefore presupposes Memory C, which is what
this table models; on the older types the same words would compensate the radius by the tool length.</p>
<table>
<thead>
<tr>
@@ -203,8 +208,9 @@ less the radial wear, and those two are exactly what
shortens the compensation and a negative wear lengthens it. Nothing in the panel states this: the
four column headers name the components and no footnote names the operation, which is why the rule
belongs here. An offset number the table holds no row for is not an error either: both getters
answer 0 for it, and neither the ISO height path nor the radius side reports the miss — a mistyped H
is a zero-length compensation that plays to the end of the program without a warning.</p>
answer 0 for it and the program plays on with a zero compensation — each side reports the miss
once, from the block that selects the row (<code>Comp-ToolHeight--RowMissing</code> on the H word,
<code>RadiusComp--RowMissing</code> on the D word), and nothing else marks it.</p>
<div class="WARNING">
<h5>Warning</h5>
<p><strong>The neighbouring Siemens ledger uses the opposite convention.</strong> On
@@ -234,6 +240,18 @@ signed rather than absolute. A negative effective radius — a radial wear large
radius — is accepted, and it offsets the path to the opposite of the programmed side. On the first
block of a compensation move the parser raises a validation warning for that case on Heidenhain
only, mirroring the look-ahead check a TNC control performs; the other brands take it silently.</p>
<p>An effective radius larger than the inner radius of the contour it compensates is a different
case. The compensated path then runs against the programmed direction — an inner arc smaller than
the offset, or an inner step shorter than it — and a control stops there (Fanuc alarm PS0041,
<em>interference in cutter compensation</em>). Both engines report it as the validation warning
<code>RadiusComp--Interference</code> on the offending block and keep playing the swapped-side path, so the
run stays inspectable. The usual cause is this table rather than the program: a CAM post that emits
the <strong>tool-centre path</strong> and leaves <code>G41 D..</code> in place expects the D row to hold the <strong>wear only</strong>,
so the ideal radius of such a row is 0 — and a tool-house refresh left on its cutter-radius basis
writes the cutter's real radius into every row and silently turns that program into an overcut. The
<a href="#the-radius-basis">radius basis</a> below is what tells the refresh which strategy the program follows;
the tell-tale signs of a tool-centre program are lead-in and lead-out arcs smaller than the tool
radius and a finishing contour that lies one tool radius inside the wall.</p>
<h3 id="the-macro-variable-window">The macro-variable window</h3>
<p>On the Fanuc, Mazak and Syntec syntax lists a variable lookup maps <code>#2001</code> through <code>#2200</code> onto the
effective <strong>height</strong> of offsets 1 through 200, so a macro program can read the same subtraction the
@@ -265,6 +283,46 @@ panel's catalogued departures from <a class="xref" href="../editing-contract.htm
<li>Row CRUD disappears: the <strong>Add</strong> button is not rendered and each row's delete button becomes a
grey em dash. A <strong>Refresh from Tool House</strong> button appears next to the toggle in their place.</li>
</ul>
<h3 id="the-radius-basis">The radius basis</h3>
<p>Length and radius do not follow the tool house the same way, because shops post their programs under
two cutter-compensation strategies and only one of them wants the cutter's radius in the table:</p>
<table>
<thead>
<tr>
<th>Basis</th>
<th>The NC path is</th>
<th>The D row holds</th>
<th>A refresh writes to <strong>Ideal Radius</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Cutter radius</strong></td>
<td>the part contour; the control offsets it by the tool radius</td>
<td>geometry (the cutter radius) plus wear</td>
<td>the largest radius on the cutter profile</td>
</tr>
<tr>
<td><strong>Zero-based</strong></td>
<td>the tool-centre path — the CAM system already offset it, <code>G41 D..</code> stays in the program</td>
<td>the wear only; geometry is 0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>The basis is a project-level setting — <a class="xref" href="../../../../api/Hi.MachiningProcs.MachiningActRunnerConfig.html#Hi_MachiningProcs_MachiningActRunnerConfig_RadiusOffsetBasis">RadiusOffsetBasis</a>
(<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.RadiusOffsetBasis.html">RadiusOffsetBasis</a>, serialized beside the tool-house
dependence, default <em>cutter radius</em> so an older project refreshes exactly as before) — chosen from the
<strong>Radius basis</strong> select in the panel's toolbar and written through
<code>PUT api/mech/soft-nc-runner/tool-offsets/radius-basis</code>. Every refresh honours it: the button, the
play-time refresh while the dependence is on, and both refresh endpoints. The height side is untouched by
the choice; the wear columns are never written by any refresh.</p>
<p>Pick the basis from the program, not from habit: a zero-based program shows lead-in and lead-out arcs
whose radius is smaller than the tool radius and a finishing contour one tool radius inside the wall
it produces (a Ø8 end mill following a circle of radius 2.5 is finishing a Ø13 bore, not a Ø5 one);
a cutter-radius program draws the part contour itself. Refreshing a zero-based program on the
cutter-radius basis is the overcut the radius side reports as <code>RadiusComp--Interference</code> — see
<a href="#how-the-radius-reaches-the-path">How the radius reaches the path</a>.</p>
<h3 id="the-table-does-not-otherwise-track-the-tool-library">The table does not otherwise track the tool library</h3>
<p>Offset number and tool id are independent integers, and with the dependence off nothing reconciles
them. A row may name a number the project's tool library has never held, and the library may hold
@@ -275,8 +333,8 @@ as written. The library itself is edited on <a class="xref" href="../../../tool-
<p>One endpoint backs both the button and the toggle, and it runs three steps. For every tool in the
project's library it writes the ideal height from that tool's spindle-buckle-to-tool-tip length —
<code>NaN</code> where the length does not resolve — and, where the cutter is a milling cutter, the ideal
radius from the largest radius on its cutter profile; a row is created for a library tool that had
none. <strong>It then deletes every row whose number is not in the library.</strong> The wear columns are never
radius by the <a href="#the-radius-basis">radius basis</a>: the largest radius on its cutter profile under
<em>cutter radius</em>, 0 under <em>zero-based</em>; a row is created for a library tool that had none. <strong>It then deletes every row whose number is not in the library.</strong> The wear columns are never
touched.</p>
<p>The engine carries the same three steps of its own, as
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetTable.html#Hi_NcParsers_Dependencys_Generic_ToolOffsetTable_UpdateIdealByToolHouse_">UpdateIdealByToolHouse</a><small>(API)</small>,
@@ -354,9 +412,13 @@ again on every runner assignment.</p>
<ul>
<li><strong>Set ideal offset dependent on tool house</strong> Toggle</li>
<li><strong>Refresh from Tool House</strong> Button — flat, refresh icon; only while the dependence is on</li>
<li><strong>Radius basis</strong> Select — dense, outlined; <strong>Cutter radius (D row = cutter radius; NC is
the part contour)</strong> or <strong>Zero-based (D row holds wear only; NC is the tool-centre path)</strong></li>
<li><strong>Add</strong> Button — primary, add icon, right-aligned; only while the dependence is off</li>
</ul>
</li>
<li>Radius-Basis Hint Line — grey caption under the toolbar, one of two sentences chosen by the
selected basis</li>
<li>Offset Table — dense, flat, bordered
<ul>
<li>Header Row — <strong>Tool #</strong>, <strong>Ideal Height (mm)</strong>, <strong>Axial Wear (mm)</strong>, <strong>Ideal Radius (mm)</strong>,
@@ -134,7 +134,7 @@ project directory. Load / Save As / Copy / Paste / XML.</li>
</li>
<li><code>equipment/fixture/geometry</code> — &ldquo;Geometry&rdquo;, a Geometry slot backing
<a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html#Hi_NcMech_Fixtures_Fixture_Geom">Geom</a>. The slot's own panel is the kind picker
(<a class="xref" href="../geom/geom-manage-control.html">Geometry Management Control</a>, selector only); the picked kind's
(<a class="xref" href="../geom/geometry-editor.html">Geometry Management Control</a>, selector only); the picked kind's
editor is the slot's child item. Kinds offered: <code>Box3d</code>, <code>Cylindroid</code>, <code>StlFile</code>,
<code>TransformationGeom</code>, <code>GeomCombination</code>, plus None. The geometry must satisfy <code>IStlSource</code>, so the
runtime-only voxel <code>CubeTreeFile</code> is not among them.</li>
@@ -120,7 +120,8 @@ surface, editing a different model from the branch above.</p>
<li><a class="xref" href="../platform/control-tree.html">Control Tree</a> — the engine behind this page's tree: how a branch is built, rebuilt and selected</li>
<li><a href="controller/index.html">Controller Branch</a> — the branch this page hosts whose node set changes with the controller brand</li>
<li><a href="hidden-controllers.html">Hidden Controller Branches</a> — the two equipment nodes this page withholds until a preference or a link asks for them</li>
<li><a class="xref" href="../legacy-controller.html">Legacy Controller</a> — the superseded controller screen at its own route, and the three settings only it edits</li>
<li><a class="xref" href="../legacy-controller.html">Legacy Controller</a> — the superseded controller screen at its own route: its seven tabs, how an edit commits, and its viewer</li>
<li><a class="xref" href="../legacy-controller-settings.html">Legacy Controller Settings</a> — the model that screen edits, and the three settings the equipment tree has no editor for</li>
</ul>
</article>
@@ -108,16 +108,16 @@ geometry, anchors, mesh and material are all edited through the child items belo
</li>
<li><code>equipment/workpiece/raw-geometry</code> — &ldquo;Raw Geometry&rdquo;, a Geometry slot backing
<a class="xref" href="../../api/Hi.NcMech.Workpieces.Workpiece.html#Hi_NcMech_Workpieces_Workpiece_InitGeom">InitGeom</a>. The slot's own panel is the kind picker
(<a class="xref" href="../geom/geom-manage-control.html">Geometry Management Control</a>, selector only); the picked kind's
(<a class="xref" href="../geom/geometry-editor.html">Geometry Management Control</a>, selector only); the picked kind's
editor is the slot's child item. Kinds offered: <code>Box3d</code>, <code>Cylindroid</code>, <code>StlFile</code>,
<code>TransformationGeom</code>, <code>GeomCombination</code>, <code>CubeTreeFile</code>, plus None. <code>ExtendedCylinder</code> is an
<code>IMakeXmlSource</code> and was offered here until its start section — wired by a host, never serialized
— was found to reload a saved project degenerate; see
<a class="xref" href="../geom/extended-cylinder-panel.html">Extended Cylinder Panel</a> for what an older project holding
<a class="xref" href="../geom/extended-cylinder-editor.html">ExtendedCylinder Editor</a> for what an older project holding
one still shows. The source
choice folds into that one picker — picking the voxel <code>CubeTreeFile</code>, which the picker shows as
<code>MeshedGeomFile</code>, <em>is</em> the meshed source (see
<a class="xref" href="../geom/meshed-geom-panel.html">Meshed Geometry Panel</a>).</li>
<a class="xref" href="../geom/meshed-geom-file-editor.html">MeshedGeomFile Editor</a>).</li>
<li><code>equipment/workpiece/target-geometry</code> — &ldquo;Target Geometry&rdquo;, the same slot shape backing
<a class="xref" href="../../api/Hi.NcMech.Workpieces.Workpiece.html#Hi_NcMech_Workpieces_Workpiece_IdealGeom">IdealGeom</a>. Kinds offered: <code>Box3d</code>, <code>Cylindroid</code>, <code>StlFile</code>,
<code>TransformationGeom</code>, plus None. The target must satisfy <code>IGetStl</code>, so <code>CubeTreeFile</code> is not among