This repository has been archived on 2026-10-11. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
HiNC-2025-win-desktop-Deploy/App/wwwroot/HiAPI-docsite/anatomy/general-setup/controller/program-data/tool-offsets.html
T
2026-09-11 03:46:11 +08:00

561 lines
36 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tool Offsets | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Tool Offsets | HiAPI-C# 2025 ">
<link rel="icon" href="../../../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../../../public/docfx.min.css">
<link rel="stylesheet" href="../../../../public/main.css">
<meta name="docfx:navrel" content="../../../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../../../index.html">
<img id="logo" class="svg" src="../../../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Anatomy-ControllerToolOffsets">
<h1 id="tool-offsets">Tool Offsets</h1>
<p>Tool Offsets is the Controller branch's brand-neutral offset ledger — one row per integer offset
number, each carrying a height and a radius split into an ideal (geometry) component and a wear
component. It lives on the General Setup page at <code>/general-setup</code> under the Control-Tree id
<code>equipment/controller/program-data/tool-offsets</code>, and that one id is the whole of what this page
owns. The leaf is ungated: every brand preset proxies the table behind it, so the node is grown
wherever a runner resolves — <a class="xref" href="../brand-matrix.html">Brand Matrix</a>.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p>Anatomy makes no claim that any id named here is stable across versions. The migration hop that
keeps an older <code>?tree=</code> value resolving is described in
<a class="xref" href="../../../platform/tree-ids-and-routes.html">Tree Ids and Routes</a>.</p>
</div>
<p>The panel follows the branch's shared rules — one read on mount, per-control commit, the
capture-assign-await-restore write, the two empty layers, and a dense markup table with no sort and
no pagination. Those rules, and the places this panel departs from them, are
<a class="xref" href="../editing-contract.html">Editing Contract</a>. What is this leaf's own is everything
below.</p>
<h2 id="one-node-two-labels">One Node, Two Labels</h2>
<p>The node id never changes, and the tree label does. The branch builder pushes this leaf
unconditionally, then chooses its label from the snapshot's Siemens tool-offset flag:</p>
<table>
<thead>
<tr>
<th>Condition</th>
<th>Label the tree row reads</th>
</tr>
</thead>
<tbody>
<tr>
<td>No <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolOffsetTable.html">SiemensToolOffsetTable</a> resolves</td>
<td><strong>Tool Offsets</strong></td>
</tr>
<tr>
<td>One does</td>
<td><strong>Tool Offsets (ISO G43 H)</strong></td>
</tr>
</tbody>
</table>
<p>Among the shipped presets only Siemens carries that table, so only Siemens sees the second label —
and it sees it beside a second offset leaf, <strong>Tool Offsets ($TC_DP)</strong>, grown from the same flag. The
qualifier exists so that the two ledgers do not read as one row of the tree; the id under it is
<code>equipment/controller/program-data/tool-offsets</code> either way, so an existing deep link is unaffected
by which label is showing. Which flag grows which leaf, and what that flag probes, is
<a class="xref" href="../brand-matrix.html">Brand Matrix</a>.</p>
<p>A second, independent Siemens signal appears <strong>inside</strong> the panel. While the runner's brand marker
reads <code>Siemens</code>, an orange caption sits above the toolbar:</p>
<blockquote>
<p><em>&quot;On Siemens this table serves the ISO <code>G43 H</code> path only — it is not the Sinumerik tool-offset
ledger. <code>D</code> tool calls read the Tool Offsets ($TC_DP) table; when a (T, D) row is missing there,
playback falls back to this table's height for the tool number and reports a warning.&quot;</em></p>
</blockquote>
<p>The label is chosen from the table flag and the caption from the brand string. Those are computed
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. 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>
<th>Column</th>
<th>Stores</th>
<th>Read by</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Tool #</strong></td>
<td>the offset number, the row's key</td>
<td>the H word, the D word, or the Heidenhain tool number</td>
</tr>
<tr>
<td><strong>Ideal Height (mm)</strong></td>
<td>the tool's length before wear</td>
<td>the height side</td>
</tr>
<tr>
<td><strong>Axial Wear (mm)</strong></td>
<td>accumulated length wear</td>
<td>the height side</td>
</tr>
<tr>
<td><strong>Ideal Radius (mm)</strong></td>
<td>the cutter's radius before wear</td>
<td>the radius side</td>
</tr>
<tr>
<td><strong>Radial Wear (mm)</strong></td>
<td>accumulated radius wear</td>
<td>the radius side</td>
</tr>
</tbody>
</table>
<p>There is no unit column and no unit conversion:
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetRow.html">ToolOffsetRow</a> stores four plain millimetre doubles, and the
panel writes and reads them unchanged. No cell is bounded except the key, which takes a minimum of</p>
<ol>
<li>The panel renders no description caption above its table: the Siemens caveat is the only line it
shows there, and the only other prose it carries is the closing caption the tool-house dependence
turns on below the table.</li>
</ol>
<p>The key column is the branch's one renameable key, and the rename is guarded on both sides of the
wire: the panel refuses a value already present in its own rows with the toast <em>&quot;Tool id {id}
already exists.&quot;</em> and re-reads the table, and the endpoint refuses the same case with a message
naming the existing id. Below 1 never reaches either — the numeric widget rejects the bound itself,
marks the box and emits nothing. A non-integer that the widget does emit is dropped by the handler
with no request and no message at all.</p>
<h2 id="the-sign-convention">The Sign Convention</h2>
<p><strong>On this table an effective value is the ideal minus the wear.</strong>
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetRow.html#Hi_NcParsers_Dependencys_Generic_ToolOffsetRow_FullHeight_mm">FullHeight_mm</a> is the ideal height less the
axial wear and <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetRow.html#Hi_NcParsers_Dependencys_Generic_ToolOffsetRow_FullRadius_mm">FullRadius_mm</a> the ideal radius
less the radial wear, and those two are exactly what
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.IToolOffsetConfig.html">IToolOffsetConfig</a> hands every consumer. A positive wear therefore
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 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
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolOffsetTable.html">SiemensToolOffsetTable</a> an effective value is the geometry
<strong>plus</strong> the wear, and that panel prints the addition in a footnote under its own table. On a
Siemens project both leaves are present at once, so one wear number entered in the two ledgers
moves the tool in opposite directions. See
<a class="xref" href="siemens-tool-offsets.html">Siemens Tool Offsets</a>.</p>
</div>
<h3 id="how-the-height-reaches-the-machine">How the height reaches the machine</h3>
<p>The height side is consumed as a translation, not as a property of the tool. On a G43 block the ISO
tool-height syntax reads the effective height for the H number and composes it into the
program-to-machine transform chain as a translation of that many millimetres along the current tool
orientation; G44 negates the same number and G49 writes zero. The G43.4 RTCP path reads the same
number for the same H word and re-aims it through the machine kinematics. On Heidenhain there is no
cancel word: a TOOL CALL block reads the effective height for the <strong>tool number</strong> and adds the
block's <code>DL</code> delta to it, and the result composes into the same chain entry.</p>
<p>Nothing on that path reads the tool the project actually carries. The modelled tool assembly's own
spindle-buckle-to-tool-tip length is what decides where its tip sits once the machine has moved by
the compensation, so the stored ideal height and the modelled tool's length are two independent
numbers that have to agree for the programmed contour to land on the workpiece. Making them agree is
the entire purpose of the tool-house dependence below, which writes
<a class="xref" href="../../../../api/Hi.Machining.IMachiningTool.html#Hi_Machining_IMachiningTool_SpindleBuckleToToolTipLength">SpindleBuckleToToolTipLength</a> straight into the ideal column.</p>
<h3 id="how-the-radius-reaches-the-path">How the radius reaches the path</h3>
<p>The radius side is read by the G41/G42 radius-compensation syntax against the D number, and it is
signed rather than absolute. A negative effective radius — a radial wear larger than the ideal
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
G43 path applies. It is a read: the lookup exposes no writer, and neither the Siemens nor the
Heidenhain syntax list registers it.</p>
<h3 id="where-a-blank-cell-comes-from">Where a blank cell comes from</h3>
<p>A cleared numeric cell is not a stored value — the panel drops a null or a non-finite edit before
sending anything, so clearing a cell leaves the number on the server and the box repopulates on the
next remount. A blank cell that arrives <strong>from</strong> the server is a different thing: it is <code>NaN</code>, which
the numeric widget renders as empty text. The tool-house refresh is what writes one, for a tool
whose tip length does not resolve. Only the Siemens <code>$TC_DP</code> fallback tests for it — a NaN height
there is reported as a configuration warning and degrades to zero — while the ISO G43 path composes
whatever the table returned.</p>
<h2 id="tool-house-dependence">Tool-House Dependence</h2>
<p>Above the table sits the toggle <strong>Set ideal offset dependent on tool house</strong>. It is the one setting
this leaf edits that is not a dependency at all: it writes
<a class="xref" href="../../../../api/Hi.MachiningProcs.MachiningActRunnerConfig.html#Hi_MachiningProcs_MachiningActRunnerConfig_IsIdealOffsetDependentOnToolHouse">IsIdealOffsetDependentOnToolHouse</a>, a project-level
element serialized beside the runner suit, so it is untouched by a runner install and by the sweep
that follows a brand switch. Its stored default is on; the reader answers <em>off</em> when no project is
loaded, which is a fallback rather than the model's own default.</p>
<p>With the dependence on, the panel hands three things over:</p>
<ul>
<li>The two <strong>ideal</strong> columns become read-only, and a closing caption says so: <em>&quot;Ideal columns mirror
the Tool House; only the wear columns are editable.&quot;</em> Read-only is a screen guarantee only — the
write is row-scoped, so the ideal values ride along on every wear edit, and the endpoint writes
all four components unconditionally. That the two ideal cells still commit on Enter is one of the
panel's catalogued departures from <a class="xref" href="../editing-contract.html">Editing Contract</a>.</li>
<li>The <strong>Tool #</strong> cell is replaced by bold plain text, so the key cannot be renamed.</li>
<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
tools with no row; neither state is reported anywhere on this panel, and both are stored and played
as written. The library itself is edited on <a class="xref" href="../../../tool-house/index.html">Tool House Page</a>.</p>
<p>The refresh is what imposes a one-to-one mapping, and it does so in both directions.</p>
<h3 id="the-refresh-is-destructive-and-it-is-not-only-a-button">The refresh is destructive, and it is not only a button</h3>
<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 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>,
and that copy is what playback calls. The two agree step for step and part company only on a missing
library: the engine method returns without doing anything, while the endpoint answers unsuccessfully
with <em>&ldquo;No tool house available&rdquo;</em>.</p>
<p>Three consequences deserve stating plainly.</p>
<ul>
<li><strong>There is no confirmation.</strong> The dialog that guards a single delete button does not guard this,
and there is no undo.</li>
<li><strong>Turning the toggle on runs it immediately.</strong> Enabling the dependence is two server calls in one
attempt: the flag write, then the refresh. A project with no tool library fails the second with
<em>&ldquo;No tool house available&rdquo;</em> after the first has already committed, and the panel's local toggle
springs back while the server-side flag stays on — the two-call rollback recorded in
<a class="xref" href="../editing-contract.html">Editing Contract</a>. Turning the toggle off writes the flag
and stops there — no refresh, and no re-read.</li>
<li><strong>Playback runs it too.</strong> While the flag is on, starting an NC program refreshes the table from
the library before the first block, so a hand-typed ideal value is replaced whether or not the
panel was ever opened, and an empty library at that moment empties the table. No panel is told:
what is on screen is whatever the last read returned until the selection moves away and back.</li>
</ul>
<h2 id="row-life-cycle">Row Life Cycle</h2>
<p>The add and the delete are the two flows the branch spells one way here and another way elsewhere.</p>
<p><strong>Add</strong> is a fieldless toolbar button, because the server mints the key: the endpoint takes the
highest existing number plus one — or 1 on an empty table — inserts an all-zero row and returns the
number, and the panel appends that row locally rather than re-reading. All four zeros are the
server's actual new-row values, not a screen placeholder.</p>
<p><strong>Delete</strong> opens a confirmation dialog first, titled <strong>Remove tool offset</strong> over <em>&quot;Remove the offset
row for tool #{id}?&quot;</em>, and filters the row out locally once the request resolves. Deleting a number
the table no longer holds answers unsuccessfully with a message naming it.</p>
<p><strong>Rename</strong> is optimistic and re-sorts the rows ascending once the write returns; a failure restores
the previous number. Every other cell is a per-cell handler that sends the whole row.</p>
<h2 id="when-the-table-is-absent">When the Table Is Absent</h2>
<p>The leaf carries both of the branch's empty layers. The shared one renders <em>&quot;No NC runner — load a
project first.&quot;</em> while the snapshot reports no runner. The panel's own read then gates on whether a
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetTable.html">ToolOffsetTable</a> resolved, and renders <em>&quot;No tool-offset table
on the active runner.&quot;</em> when it did not — which hides the dependence toggle along with the table,
since the whole body sits behind that guard. A failed write answers inside a success envelope. The
row write, the delete, the rename and the refresh all go through the branch's shared dependency
helper and carry <code>No ToolOffsetTable on the active runner</code>, which the panel shows as its own context
followed by that sentence. <strong>Add</strong> does not use that helper: it tests the table itself and answers
<code>No tool-offset table on the active runner</code> — the panel's own absent-table line, less its full stop.
The dependence write reaches neither string, because what it writes is a project-level element
rather than the table; it is the one route on this leaf that answers a coded payload instead, and it
reports no project loaded.</p>
<p>That second layer is hard to reach. <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetTableProxy.html">ToolOffsetTableProxy</a> is
a seedless get-or-create placeholder: on wiring it installs a bare table into the project's per-case
list whenever the project holds none, and the suit wires its proxies when it is deserialized and
again on every runner assignment.</p>
<h2 id="layout">Layout</h2>
<ul>
<li><strong>General Setup</strong> Control Tree — the left dock of <code>/general-setup</code>
<ul>
<li><strong>Controller</strong> Node Row
<ul>
<li><strong>Program Data</strong> Group Row
<ul>
<li><strong>Tool Offsets</strong> Node Row — <code>equipment/controller/program-data/tool-offsets</code>; reads
<strong>Tool Offsets (ISO G43 H)</strong> while a Siemens <code>$TC_DP</code> table resolves</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Editor Row — the panel of whichever node is selected
<ul>
<li><strong>Tool Offsets</strong> Panel
<ul>
<li>No-Runner Body — <em>&quot;No NC runner — load a project first.&quot;</em>; shown instead of everything below</li>
<li>Absent-Table Body — <em>&quot;No tool-offset table on the active runner.&quot;</em>; shown instead of the body</li>
<li>Siemens Caveat Line — orange caption, shown while the brand marker reads <code>Siemens</code>, with
<code>G43 H</code> and <code>D</code> set in code style</li>
<li>Toolbar
<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>,
<strong>Radial Wear (mm)</strong>, then an unlabelled action column</li>
<li>Offset Row, one per offset number, ascending
<ul>
<li>Tool Number Cell — a numeric field with a minimum of 1, or bold plain text while the
dependence is on</li>
<li>Ideal Height, Axial Wear, Ideal Radius and Radial Wear Numeric Fields — the two ideal ones
read-only while the dependence is on</li>
<li>Delete Button — or a grey em dash while the dependence is on</li>
</ul>
</li>
</ul>
</li>
<li>Dependent Footnote — <em>&quot;Ideal columns mirror the Tool House; only the wear columns are
editable.&quot;</em>; only while the dependence is on</li>
</ul>
</li>
<li>Remove-Row Confirmation Dialog — <strong>Remove tool offset</strong>, <em>&quot;Remove the offset row for tool
#{id}?&quot;</em>, with a cancel button</li>
</ul>
</li>
</ul>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../../../index.html">HiNC App Anatomy</a> for git repository links.</p>
<h3 id="web-application">Web Application</h3>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/SoftNcToolOffsetsPanel.vue</code> — the panel: the dependence
toggle and its two-call enable, the refresh button, the read-only ideal columns, the renameable
key with its duplicate guard, the confirmed delete, the locally appended add, and the Siemens
caption gated on the brand string.</li>
<li><code>wwwroot-src/src/components/controlTree/softNcItemTypes.ts</code> — the branch builder: this leaf's id,
its two labels and label keys, and the snapshot flag that switches between them.</li>
<li><code>wwwroot-src/src/api/softNcRunner.ts</code> — the typed wrappers: the row shape with its presence and
dependence flags, the whole-row write, the add that returns a minted number, the rename, the
delete, and the refresh call.</li>
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the numeric cell: commit on blur or Enter,
the minimum rejected inside the widget, the empty-text-to-null parse the panel drops, and the
<code>NaN</code> that renders as an empty box.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue</code> — the shared no-runner line the
panel opens with.</li>
<li><code>wwwroot-src/src/composables/useSoftNcRunner.ts</code> — the shared snapshot behind that first guard and
behind the tree's choice of label.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcSiemensToolOffsetsPanel.vue</code> — the neighbouring
ledger on Siemens, and the footnote in which it states the opposite sign rule.</li>
<li><code>wwwroot-src/src/i18n/en/softNc.ts</code> — the two node labels, the Siemens caveat, the four column
headers, the dependent footnote, the duplicate-key toast, the absent-table line and the panel's
error contexts.</li>
<li><code>wwwroot-src/src/i18n/en/common.ts</code> — the shared <strong>Tool #</strong>, <strong>Add</strong>, toggle and refresh labels.</li>
<li><code>wwwroot-src/src/i18n/en/dialog.ts</code> — the remove-row dialog's title and message.</li>
<li><code>Mech/SoftNcRunnerController.cs</code> — the REST surface: the reader with its presence and dependence
flags, the whole-row write, the add that mints the next number, the delete and the rename with
their refusals, the project-level dependence write, and the refresh with its drop of rows the
library no longer holds.</li>
<li><code>Common/ApiError.cs</code> — the coded no-project payload the dependence write answers with, the one
answer on this leaf that can be re-rendered in the application locale.</li>
</ul>
<h3 id="hiapi-engine">HiAPI Engine</h3>
<ul>
<li><code>HiMech/NcParsers/Dependencys/Generic/ToolOffsetTable.cs</code> — the ledger itself: the four stored
components, the subtraction that makes an effective value ideal minus wear, the integer-keyed row
dictionary, and the tool-house update with its row creation and its row removal.</li>
<li><code>HiMech/NcParsers/Dependencys/Generic/ToolOffsetTableProxy.cs</code> — the seedless get-or-create
placeholder every brand preset carries in place of the table, and the bare instance it installs
into a project holding none.</li>
<li><code>HiMech/NcParsers/Dependencys/IToolOffsetConfig.cs</code> — the single-integer offset contract the
consumers read through, and the pointer to the Siemens tool-and-edge contract beside it.</li>
<li><code>HiMech/NcParsers/Dependencys/Siemens/SiemensToolOffsetTable.cs</code> — the neighbouring ledger, and
the addition that makes its effective values geometry plus wear.</li>
<li><code>HiMech/NcParsers/SoftNcRunner.cs</code> — the five brand presets, each of which carries the tool-offset
proxy, and the proxy resolution every read of the table goes through.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/ToolHeightOffsetSyntax.cs</code> — the ISO height path: the H word, the
G43 / G44 / G49 arms, and the translation along the tool orientation both brand siblings compose
through.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/G43p4RtcpSyntax.cs</code> — the RTCP path that reads the same height for
the same H word and re-aims it through the kinematics.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/Heidenhain/HeidenhainToolOffsetSyntax.cs</code> — the TOOL CALL path: the
tool number as the offset id, the <code>DL</code> delta added to the table height, and the absence of a
cancel word.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/Siemens/SiemensToolOffsetSyntax.cs</code> — the <code>D</code> path's fallback onto
this table when the <code>$TC_DP</code> map has no row, its warning, and the <code>NaN</code> case it degrades to zero.</li>
<li><code>HiMech/NcParsers/PostLogicSyntaxs/RadiusCompensationSyntax.cs</code> — the radius side: the D word, the
signed offset that flips the compensated side when it goes negative, and the Heidenhain-only
warning for that case.</li>
<li><code>HiMech/NcParsers/Dependencys/Fanuc/FanucToolOffsetVariableLookup.cs</code> — the read-only macro window
onto the effective heights, and the address range it answers for.</li>
<li><code>HiMech/NcParsers/Syntaxs/FanucSyntaxUtil.cs</code>,
<code>HiMech/NcParsers/Syntaxs/MazakSyntaxUtil.cs</code> and
<code>HiMech/NcParsers/Syntaxs/SyntecSyntaxUtil.cs</code> — the three syntax lists that register that window.</li>
<li><code>HiMech/MachiningProcs/MachiningActRunnerConfig.cs</code> — the tool-house dependence flag, its stored
default and the element the project serializes it as.</li>
<li><code>HiMech/MachiningProcs/MachiningSession.cs</code> — the play loop's refresh of the table from the
library before the first block, run whenever the flag is on.</li>
<li><code>HiMech/Machining/MachiningToolHouse.cs</code> — the tool-id-keyed library the refresh walks.</li>
<li><code>HiMech/Machining/IMachiningTool.cs</code> — the tool contract the library's entries answer to, and
where the spindle-buckle-to-tool-tip length the refresh reads is declared.</li>
<li><code>HiMech/Milling/MillingTools/MillingTool.cs</code> — the assembly walk behind that length, and the <code>NaN</code>
it answers when the walk does not resolve.</li>
<li><code>HiNc/MachiningProcs/LocalProjectService.cs</code> — the facade that owns the library and the runner
suit, and the entry point the play-time refresh reaches this table through.</li>
<li><code>HiNc/MachiningProcs/MachiningProject.cs</code> — where the library, the runner configuration and the
suit hang off the project, and the load path that leaves the library unset when the project file
names none.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="index.html">Program Data Plane</a> — the plane this leaf sits on, where its table is stored, and
what a brand switch does to the tables beside it</li>
<li><a class="xref" href="siemens-tool-offsets.html">Siemens Tool Offsets</a> — the <code>$TC_DP</code> ledger that appears next to this one on
Siemens, and whose wear convention is the opposite of the one stated above</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>