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/siemens-tool-offsets.html
T
2026-09-11 03:46:11 +08:00

598 lines
38 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Siemens Tool Offsets | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Siemens 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-ControllerSiemensToolOffsets">
<h1 id="siemens-tool-offsets">Siemens Tool Offsets</h1>
<p>Siemens Tool Offsets is the Sinumerik <code>$TC_DP</code> ledger — one offset row per cutting edge of a tool,
addressed by the tool number and the edge number together — plus the tool-name map that resolves a
string tool call to a tool number. It occupies two leaves of the Controller branch on the General
Setup page at <code>/general-setup</code>, under the Control-Tree ids
<code>equipment/controller/program-data/siemens-tool-offsets</code> and
<code>equipment/controller/program-data/tool-names</code>, and those two ids are the whole of what this page
owns. Both are grown by one snapshot flag over one backing object, which is why one page carries
them.</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>Both panels follow 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 these two panels depart from them, are
<a class="xref" href="../editing-contract.html">Editing Contract</a>. What is these leaves' own is everything
below.</p>
<h2 id="two-nodes-over-one-table">Two Nodes Over One Table</h2>
<p>The tree labels differ, the panels differ, and the object behind them does not.</p>
<table>
<thead>
<tr>
<th>Node id</th>
<th>Tree label</th>
<th>Which half of the object</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>equipment/controller/program-data/siemens-tool-offsets</code></td>
<td><strong>Tool Offsets ($TC_DP)</strong></td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolOffsetTable.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolOffsetTable_Edges">Edges</a> — the offset rows</td>
</tr>
<tr>
<td><code>equipment/controller/program-data/tool-names</code></td>
<td><strong>Tool Names</strong></td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolOffsetTable.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolOffsetTable_ToolNames">ToolNames</a> — the name map</td>
</tr>
</tbody>
</table>
<p>The branch builder pushes both inside a single test of the snapshot's Siemens tool-offset flag, so
they appear and disappear together and there is no separate tool-name flag anywhere in the snapshot.
The flag itself is a type probe for <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolOffsetTable.html">SiemensToolOffsetTable</a>
over the proxy-resolved dependency list, and the Siemens preset is the only shipped brand list that
carries the proxy for it — <a class="xref" href="../brand-matrix.html">Brand Matrix</a>.</p>
<p>The same flag does one more thing: it relabels the ungated generic offset leaf one row above from
<strong>Tool Offsets</strong> to <strong>Tool Offsets (ISO G43 H)</strong>, without touching that leaf's id. The two ledgers
are present together on a Siemens project and an unqualified label would blur them into one — see
<a class="xref" href="tool-offsets.html">Tool Offsets</a>.</p>
<p>Each panel reads only its own half. The <code>$TC_DP</code> panel reads and writes rows; the Tool Names panel
reads and writes name mappings; neither reports the other's edits, and neither re-reads when the
other writes. The presence flag both receive is the same one — whether the table object resolved —
so the Tool Names panel's absent-table line, <em>&quot;No Siemens tool-name table on the active runner.&quot;</em>,
names a table that is not a type of its own.</p>
<h2 id="the-key-has-two-parts">The Key Has Two Parts</h2>
<p><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.ISiemensToolOffsetConfig.html">ISiemensToolOffsetConfig</a> addresses an offset by a <strong>tool
number</strong> and a <strong>cutting edge number</strong> together, where
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.IToolOffsetConfig.html">IToolOffsetConfig</a> — the contract behind the generic ledger — takes a
single integer. That is the structural difference between the two ledgers, and it is why one tool can
carry several rows: a tool with more than one usable edge stores an offset per edge, and the program
selects among them with the <code>D</code> word after the tool is mounted.</p>
<p>The pair is the dictionary key, and both halves are rendered as bold plain text with a hard-coded
letter prefix — <code>T</code> on the tool cell and <code>D</code> on the edge cell. Neither is editable and no rename
route exists on either half of the object, so a key cannot be corrected in place. Neither can a
chosen one be asked for: the <code>$TC_DP</code> add accepts no target pair — it mints the next tool, or the
next edge of the tool it is given — so arriving at a particular pair means growing the table up to it
and deleting what was stepped through. Only the tool-name half takes a typed key. That same
server-side minting is why nothing on this leaf can create a duplicate.</p>
<p>An unconfigured pair is not an error. The interface contract returns 0 for a pair the table has no
row for, and the try-form is the only reliable miss signal, because 0 is itself a legal stored
offset — a distinction that decides the fallback below.</p>
<h2 id="the-columns">The Columns</h2>
<p>Ten labelled columns: the two key columns, then eight value columns in millimetres over the four
geometry components and their four wear counterparts.</p>
<table>
<thead>
<tr>
<th>Column header</th>
<th><code>$TC_DP</code> index</th>
<th>Stored as</th>
<th>Read by the pipeline</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Tool T</strong></td>
<td>—</td>
<td>the key's tool number</td>
<td>the tool the offsets belong to</td>
</tr>
<tr>
<td><strong>Edge D</strong></td>
<td>—</td>
<td>the key's edge number</td>
<td>the <code>D</code> word</td>
</tr>
<tr>
<td><strong>Length 1 (Z)</strong></td>
<td>3</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_Length1_mm">Length1_mm</a></td>
<td>the height path</td>
</tr>
<tr>
<td><strong>Length 2 (X)</strong></td>
<td>4</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_Length2_mm">Length2_mm</a></td>
<td>nothing</td>
</tr>
<tr>
<td><strong>Length 3 (Y)</strong></td>
<td>5</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_Length3_mm">Length3_mm</a></td>
<td>nothing</td>
</tr>
<tr>
<td><strong>Radius</strong></td>
<td>6</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_Radius_mm">Radius_mm</a></td>
<td>nothing</td>
</tr>
<tr>
<td><strong>Length 1 Wear</strong></td>
<td>12</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_WearLength1_mm">WearLength1_mm</a></td>
<td>the height path</td>
</tr>
<tr>
<td><strong>Length 2 Wear</strong></td>
<td>13</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_WearLength2_mm">WearLength2_mm</a></td>
<td>nothing</td>
</tr>
<tr>
<td><strong>Length 3 Wear</strong></td>
<td>14</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_WearLength3_mm">WearLength3_mm</a></td>
<td>nothing</td>
</tr>
<tr>
<td><strong>Radius Wear</strong></td>
<td>15</td>
<td><a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_WearRadius_mm">WearRadius_mm</a></td>
<td>nothing</td>
</tr>
</tbody>
</table>
<p>The table declares accessors for all three length components and for the radius, and the shipped
pipeline calls exactly one of them: the try-form that returns length 1 plus its wear. The radius
accessor and the direction-indexed length accessor are called by nothing in it. Radius compensation
reads the <strong>generic</strong> ledger's radius by a single offset number, so a radius entered here changes
nothing that plays. Length 2 and Length 3 are stored, serialized and handed back unchanged, and no
consumer reads them.</p>
<p>The axis letters in the three length headers are part of the header string and not a binding. Length
1 is the component the height path consumes whatever axis the machine calls it; the other two are
indexed positionally by an accessor nothing calls.</p>
<p>There is no unit column and no conversion — every field is a plain millimetre double, written and
read back as typed. None of the eight numeric cells passes a bound, so a negative value is accepted
and stored, which the sign convention below makes load-bearing rather than incidental.</p>
<h3 id="the-fields-the-row-carries-but-does-not-interpret">The fields the row carries but does not interpret</h3>
<p>A row also holds <a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Siemens.SiemensToolEdgeOffset.html#Hi_NcParsers_Dependencys_Siemens_SiemensToolEdgeOffset_VerbatimDpFields">VerbatimDpFields</a>, a
bag keyed by <code>$TC_DP</code> index for every index outside the eight above. Nothing interprets those values
and no cell edits them; they exist so that a full controller dump survives a load and a save
unchanged. The panel shows only their count, as a small grey <strong>+N</strong> beside the row's action buttons
with a tooltip explaining that the fields are stored and saved with the project and not used by the
simulation. The row write sends the whole row object including that count, and the endpoint assigns
only the eight doubles, so the bag survives every edit made here.</p>
<p>The two halves stay separate on both sides of serialization. Writing an index into the row routes a
consumed index onto its typed property and every other index into the bag, and the serializer filters
the consumed indices back out of the bag before writing, so an index cannot end up stored twice and
shadow its own typed value on the next load. The element the table writes carries one <code>Edge</code> entry
per key with the eight components as named attributes and the bag as <code>DP</code>-indexed ones, and one
<code>ToolName</code> entry per mapping; the reader accepts both spellings of a component, so a <code>DP</code>-indexed
geometry value lands on the typed property rather than in the bag.</p>
<h2 id="the-sign-convention">The Sign Convention</h2>
<p><strong>On this table an effective value is the geometry plus the wear.</strong> The height the pipeline reads is
length 1 added to length-1 wear, and the radius and per-direction accessors add their wear the same
way. A positive wear therefore lengthens the compensation, and a tool that has worn shorter is
recorded as a <strong>negative</strong> wear value. The panel states the addition twice: the description above the
table ends <em>&quot;Wear adds onto geometry (enter a shortened tool as negative wear).&quot;</em>, and the footnote
below it reads <em>&quot;All values in mm. Effective length 1 = Length 1 (Z) + Length 1 Wear; same for the
other columns.&quot;</em></p>
<div class="WARNING">
<h5>Warning</h5>
<p><strong>The generic ledger one node above uses the opposite convention.</strong> On
<a class="xref" href="../../../../api/Hi.NcParsers.Dependencys.Generic.ToolOffsetTable.html">ToolOffsetTable</a> an effective value is the ideal <strong>minus</strong>
the wear — <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 that panel states no sign rule at all. On a Siemens project
both leaves are present at once, so the same wear number typed into the two ledgers moves the tool
in opposite directions. See <a class="xref" href="tool-offsets.html">Tool Offsets</a>, which carries this
warning from the other side.</p>
</div>
<p>The two conventions are not a defect to reconcile: each matches the control whose vocabulary its
table borrows. What makes the pair sharp is that they meet — the fallback below reads a height out of
the subtracting table and uses it where an adding table's height was expected.</p>
<h2 id="how-a-d-word-resolves">How a D Word Resolves</h2>
<p>The Siemens height path consumes a standalone <code>D</code> word from the block and writes the same downstream
state as the ISO <code>G43</code> path: a tool-height compensation section marked with the term <code>D</code>, and a
translation of the effective height composed into the program-to-machine transform chain. Both
brands' paths compose that entry under one source key and replace it in place, so the two are
mutually exclusive on a file that mixes the dialects.</p>
<p>Resolution runs in this order.</p>
<ol>
<li><strong><code>D0</code> cancels.</strong> The section is written with an offset of 0 and an identity transform, with no
table lookup and no diagnostic.</li>
<li><strong>The active tool number comes from the block's tool-change section</strong>, or from the previous
block's when this one carries none. A numeric tool id is taken as it stands.</li>
<li><strong>A string tool id is resolved through the tool-name map</strong> on this same table. An unmapped name
raises an unsupported warning and leaves the tool number at 0.</li>
<li><strong>The <code>(T, D)</code> pair is looked up here.</strong> A configured row answers with length 1 plus its wear.</li>
<li><strong>A pair with no row falls back to the generic ledger</strong>, described next.</li>
</ol>
<p>A block that carries no <code>D</code> word re-resolves the previous block's edge modally, and only while that
previous section is still owned by the <code>D</code> term; a section already claimed by an ISO term on the same
block, or carried modally from one, is left to the ISO path. The modal re-resolve deliberately raises
no diagnostic — the warnings below are attached to blocks that spell a <code>D</code> word out, so a single
missing row reports once instead of on every block that inherits it.</p>
<h3 id="what-a-missing-row-falls-back-to">What a missing row falls back to</h3>
<p>For a <code>(T, D)</code> pair this table has no row for — and equally when no Siemens offset table resolves at
all — the height is taken from the <strong>generic</strong> tool-offset table's height for the tool number,
through the single-integer contract the ISO <code>G43 H</code> path already reads. Every Siemens runner carries
that table, so the fallback always has a source. It exists so that an unfilled per-case <code>$TC_DP</code>
table follows the tool-house-fed ledger instead of resolving 0 and machining the whole program one
tool length low.</p>
<p>Both arms report. A fallback that finds a usable height raises a configuration warning naming the
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.
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
here and in the other once it does not.</p>
<p>An unresolved tool name reaches the same fallback with the tool number left at 0, and the generic
table's own panel cannot create a row 0 — its tool-number cell takes a minimum of 1 and refuses
anything below it, and its add route mints from 1 upward — so the height resolves to 0.</p>
<h2 id="what-the-tool-name-map-is-for">What the Tool-Name Map Is For</h2>
<p>Siemens programs may name a tool as a string rather than a number, as in the <code>T=&quot;D16R3Z6&quot;</code> form the
panel's own hint quotes. The act chain the simulation builds is keyed by integer tool id, so the
string has to become a number before anything can use it, and this map is the only surface in the
engine that performs that translation. Lookup is case-insensitive: the map is constructed with an
ordinal case-insensitive comparer.</p>
<p>Two consumers read it, and they fail differently.</p>
<ul>
<li><strong>The tool change itself.</strong> The tool-change semantic resolves a string tool id through this map
before it emits a tooling step. An unmapped name raises a <code>ToolChange--NameUnresolved</code> warning and
emits <strong>no step at all</strong>, so the tool change is not simulated rather than simulated with the wrong
tool.</li>
<li><strong>The <code>D</code> word.</strong> The height path resolves the same name for its own <code>(T, D)</code> lookup and, on a
miss, raises <code>SiemensToolOffset--ToolUnresolved</code> and carries on with tool number 0.</li>
</ul>
<p>Both consumers reach the map through the concrete Siemens table rather than through an interface, so
a runner that resolves no such table resolves no tool name either, whatever its brand marker says.</p>
<p>The map's own panel is a two-column table over a name and a tool number. The name is the key and is
rendered as bold plain text; the tool number is a numeric cell with a minimum of 1. Row order is the
server's — the read sorts the keys case-insensitively. The panel never sorts, and its add path
re-reads the whole table rather than appending a row locally.</p>
<p>Its footer is an <strong>Add / Set</strong> pair of fields, and the verb is both: the write is an upsert keyed on
the name. Entering a name that already exists overwrites that mapping's number instead of adding a
second row. Because the underlying dictionary keeps the key it already holds when a value is
assigned, a name entered in different casing updates the existing row and the re-read redisplays the
casing that was stored first.</p>
<h2 id="row-life-cycle">Row Life Cycle</h2>
<p>The two leaves spell adding and deleting differently, and the difference is which side mints the key.</p>
<p><strong>The <code>$TC_DP</code> table's adds are fieldless toolbar and row buttons, because the server mints both
halves of the key.</strong> <strong>Add Tool</strong> in the toolbar sends no tool number and the endpoint takes the
highest tool present plus one — or 1 on an empty table — with edge 1. The per-row button, tooltipped
<em>&quot;Add a cutting edge for T{tool}&quot;</em>, sends that row's tool number and the endpoint takes that tool's
highest edge plus one. Neither half of the key fills a gap: a deleted middle tool or edge is stepped
over rather than reused. Either way the panel appends a locally zeroed row for the returned pair and
re-sorts by tool then edge; those zeros mirror the fresh row the server actually inserted rather than
standing in as a placeholder.</p>
<p><strong>The Tool Names table's add is the footer pair described above</strong>, since its key is typed rather than
minted. A blank name is refused before any request with <em>&quot;Tool name must not be empty.&quot;</em>, and a
number that is not a positive integer with <em>&quot;Tool # must be a positive integer.&quot;</em>; a successful write
clears both fields and re-reads the table. The endpoint refuses a blank name a second time.</p>
<p>Deletion is guarded on one leaf and not the other. A <code>$TC_DP</code> row opens a confirmation dialog first —
<strong>Remove tool offset row</strong> over <em>&quot;Remove the offset row for (T{tool}, D{edge})?&quot;</em> — and the row is
filtered out locally once the request resolves; deleting a pair the table no longer holds answers
unsuccessfully with a message naming it. A tool name deletes on the click with no dialog and no undo,
and a name the map does not hold answers unsuccessfully with a message naming it.</p>
<p>Cell edits differ from both. Every numeric cell on the <code>$TC_DP</code> table sends the <strong>whole row</strong> — all
eight components — and rolls back only the one cell it captured on failure. The Tool Names number
cell sends the mapping it belongs to. Neither panel commits a cleared cell: an emptied field parses
to null and the handler returns before the request, so the box is left blank on screen while the
stored number stands and returns on the next remount. The tool-number cell additionally drops a
non-integer silently, while a value below 1 is refused inside the numeric widget itself, which marks
the box and emits nothing.</p>
<h2 id="what-materializes-the-table">What Materializes the Table</h2>
<p>Three of the writes re-wire the runner suit's dependency proxies before resolving the table: the
<code>$TC_DP</code> row write, the <code>$TC_DP</code> add, and the tool-name write. The proxy is a get-or-create
placeholder, so that wiring installs a bare table into the project's per-case list when it holds none,
and the write then lands on a real table instead of answering that one is missing. The reads and the
two deletes do not re-wire.</p>
<p>Neither panel reports a structural change and neither refreshes the shared snapshot, so a table
created by one of those writes does not re-evaluate the flag or regrow the branch. In practice the
guard never fires from these leaves: the suit wires its proxies when it is deserialized and on every
runner assignment, and the nodes are built only after the flag already read true.</p>
<h2 id="when-the-tables-are-absent">When the Tables Are Absent</h2>
<p>Both leaves carry the branch's two empty layers. The shared one renders <em>&quot;No NC runner — load a
project first.&quot;</em> while the snapshot reports no runner. Each panel's own read then gates on whether the
Siemens table resolved, and renders <em>&quot;No Siemens tool-offset table on the active runner.&quot;</em> or <em>&quot;No
Siemens tool-name table on the active runner.&quot;</em> when it did not.</p>
<p>That second layer is not reachable by navigating, because the flag that grows either node is the same
probe the reads answer with. It is a live guard for a table that goes away under a mounted panel. A
failed write answers inside a success envelope, and the sentence it carries depends on the route. The
four that resolve the table through the shared dependency helper — the row upsert, the row delete and
the two tool-name routes — answer with the type name, <code>No SiemensToolOffsetTable on the active runner</code>; the <code>$TC_DP</code> add builds its own envelope instead and answers word for word with the
<code>$TC_DP</code> panel's own absent-table line. Either way the panel shows its localized context followed by
the sentence the server sent.</p>
<p>The table is stored on the project rather than in the runner file. It reaches the pipeline as a
seedless proxy in the Siemens preset's dependency list and resolves to the concrete table on the
project's per-case list, so a controller file saved from the branch root carries none of these rows.
A brand switch away from Siemens removes it along with the two nodes, and a switch back creates an
empty one rather than restoring what was there —
<a class="xref" href="index.html">Program Data Plane</a>.</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 ($TC_DP)</strong> Node Row — <code>equipment/controller/program-data/siemens-tool-offsets</code></li>
<li><strong>Tool Names</strong> Node Row — <code>equipment/controller/program-data/tool-names</code></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Editor Row — the panel of whichever node is selected
<ul>
<li><strong>Tool Offsets ($TC_DP)</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 Siemens tool-offset table on the active runner.&quot;</em>; shown instead of
the body</li>
<li>Description Caption — <em>&quot;Sinumerik $TC_DP tool offsets, one row per (tool T, cutting edge D). A
<code>D1</code> word in the program reads this table; when a row is missing, playback falls back to the
generic Tool Offsets table and reports a warning. Wear adds onto geometry (enter a shortened
tool as negative wear).&quot;</em>, with <code>D1</code> set in code style</li>
<li>Toolbar — right-aligned
<ul>
<li><strong>Add Tool</strong> Button — primary, add icon</li>
</ul>
</li>
<li>Offset Table — dense, flat, bordered
<ul>
<li>Header Row — <strong>Tool T</strong>, <strong>Edge D</strong>, <strong>Length 1 (Z)</strong>, <strong>Length 2 (X)</strong>, <strong>Length 3 (Y)</strong>,
<strong>Radius</strong>, <strong>Length 1 Wear</strong>, <strong>Length 2 Wear</strong>, <strong>Length 3 Wear</strong>, <strong>Radius Wear</strong>, then an
unlabelled action column</li>
<li>Offset Row, one per <code>(tool, edge)</code> pair, ascending by tool then edge
<ul>
<li>Tool Cell — bold plain text, prefixed <code>T</code></li>
<li>Edge Cell — bold plain text, prefixed <code>D</code></li>
<li>Eight Numeric Fields — the four geometry components, then their four wear components; no
bounds and no unit suffix</li>
<li>Add-Cutting-Edge Button — flat, <code>playlist_add</code> icon, tooltipped <em>&quot;Add a cutting edge for
T{tool}&quot;</em></li>
<li>Delete Button — flat, delete icon</li>
<li>Verbatim-Field Badge — a grey <strong>+N</strong>; shown only where the row carries unconsumed <code>$TC_DP</code>
fields, tooltipped that they are stored and saved with the project and not used by the
simulation</li>
</ul>
</li>
</ul>
</li>
<li>Footnote — <em>&quot;All values in mm. Effective length 1 = Length 1 (Z) + Length 1 Wear; same for the
other columns.&quot;</em></li>
</ul>
</li>
<li>Remove-Row Confirmation Dialog — <strong>Remove tool offset row</strong>, <em>&quot;Remove the offset row for (T{tool},
D{edge})?&quot;</em>, with a cancel button</li>
<li><strong>Tool Names</strong> Panel
<ul>
<li>No-Runner Body — <em>&quot;No NC runner — load a project first.&quot;</em></li>
<li>Absent-Table Body — <em>&quot;No Siemens tool-name table on the active runner.&quot;</em></li>
<li>Hint Caption — <em>&quot;Maps the tool names written in the NC program (<code>T=&quot;D16R3Z6&quot;</code>) to tool numbers.
Names are case-insensitive. An unmapped name cannot mount a tool and its <code>D</code> word resolves no
offset.&quot;</em>, with the call form and the <code>D</code> word set in code style</li>
<li>Name Table — dense, flat, bordered
<ul>
<li>Header Row — <strong>Tool Name</strong>, <strong>Tool #</strong>, then an unlabelled action column</li>
<li>Name Row, one per mapping, ordered case-insensitively by name
<ul>
<li>Name Cell — bold plain text</li>
<li>Tool Number Numeric Field — minimum 1</li>
<li>Delete Button — flat, delete icon, no confirmation</li>
</ul>
</li>
</ul>
</li>
<li>Add Row Footer
<ul>
<li><strong>Tool name</strong> Text Field</li>
<li><strong>Tool #</strong> Numeric Field — minimum 1</li>
<li><strong>Add / Set</strong> Button — primary; the only submit path, since neither field submits on Enter</li>
</ul>
</li>
</ul>
</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/SoftNcSiemensToolOffsetsPanel.vue</code> — the <code>$TC_DP</code> panel:
the eight unbounded numeric cells, the whole-row write with its finite-value guard, the two add
buttons and the local append-and-sort, the confirmed delete, and the verbatim-field badge.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcToolNamesPanel.vue</code> — the tool-name panel: the
plain-text key column, the bounded tool-number cell, the unconfirmed delete, and the <strong>Add / Set</strong>
footer with its two client-side refusals and its full re-read.</li>
<li><code>wwwroot-src/src/components/controlTree/softNcItemTypes.ts</code> — the branch builder: the single flag
test that pushes both node ids, their labels and label keys, and the relabel it applies to the
generic offset leaf at the same time.</li>
<li><code>wwwroot-src/src/api/softNcRunner.ts</code> — the typed wrappers: the row and mapping shapes with their
presence flags, the whole-row upsert, the add that returns a minted pair, the two deletes, and the
name-keyed upsert with its URL encoding.</li>
<li><code>wwwroot-src/src/composables/useSoftNcRunner.ts</code> — the shared snapshot behind the first empty layer
and behind the tree's flag test.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue</code> — the shared no-runner line both
panels open with.</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, and the empty-text-to-null parse both panels drop.</li>
<li><code>wwwroot-src/src/components/controlTree/SoftNcToolOffsetsPanel.vue</code> — the neighbouring generic
ledger, its subtracting sign rule, and the Siemens caveat it shows from the brand string.</li>
<li><code>wwwroot-src/src/i18n/en/softNc.ts</code> — the two node labels, the description and the hint, the ten
column headers, the footnote, the two absent-table lines, the add-strip refusals and the error
contexts.</li>
<li><code>wwwroot-src/src/i18n/en/common.ts</code> — the shared <strong>Tool #</strong> header and the <strong>Add / Set</strong> label.</li>
<li><code>wwwroot-src/src/i18n/en/dialog.ts</code> — the <code>$TC_DP</code> remove-row dialog's title and message, a
different key pair from the generic ledger's.</li>
<li><code>Mech/SoftNcRunnerController.cs</code> — the REST surface: the snapshot probe behind both nodes, the
ordered reads whose presence flag is the table object itself, the row upsert that assigns the eight
components and leaves the verbatim bag alone, the add that mints a tool or an edge, the two deletes
with their refusals, the name upsert with its blank-name refusal, and the proxy re-wire the three
writes run first.</li>
</ul>
<h3 id="hiapi-engine">HiAPI Engine</h3>
<ul>
<li><code>HiMech/NcParsers/Dependencys/Siemens/SiemensToolOffsetTable.cs</code> — the object both leaves edit: the
pair-keyed row dictionary, the case-insensitive name map and its lookup, the additive effective
values, the row type with its typed components and verbatim bag, and the serializer that keeps a
consumed index out of the bag.</li>
<li><code>HiMech/NcParsers/Dependencys/Siemens/ISiemensToolOffsetConfig.cs</code> — the two-key offset contract:
the try-form that is the only miss signal, and the direction-indexed and radius accessors nothing
calls.</li>
<li><code>HiMech/NcParsers/Dependencys/Siemens/SiemensToolOffsetTableProxy.cs</code> — the seedless get-or-create
placeholder the Siemens preset carries, and the bare table it installs into a project holding none.</li>
<li><code>HiMech/NcParsers/SoftNcRunner.cs</code> — the five brand presets, of which only the Siemens list carries
that proxy, and the proxy resolution every read of the table goes through.</li>
<li><code>HiMech/NcParsers/NcRunnerSuit.cs</code> — the per-case list this table is stored in, and the proxy wiring
the three writes re-run.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/Siemens/SiemensToolOffsetSyntax.cs</code> — the <code>D</code> path: the cancel arm,
the modal ownership rule, the tool-number resolution through the name map, the fallback onto the
generic ledger with its two warnings, and the suppression of both on a modal re-resolve.</li>
<li><code>HiMech/NcParsers/LogicSyntaxs/ToolHeightOffsetSyntax.cs</code> — the ISO sibling, and the shared
composition of the height as one replaceable entry of the transform chain.</li>
<li><code>HiMech/NcParsers/Semantics/ToolChangeSemantic.cs</code> — the other consumer of the name map: the string
tool id it resolves, and the tooling step it declines to emit when the name is unmapped.</li>
<li><code>HiMech/NcParsers/PostLogicSyntaxs/RadiusCompensationSyntax.cs</code> — the radius side, which reads the
generic single-integer table rather than this one.</li>
<li><code>HiMech/NcParsers/Dependencys/Generic/ToolOffsetTable.cs</code> — the fallback source: the subtracting
effective values, and the zero it answers for an offset number it does not hold.</li>
<li><code>HiMech/NcParsers/Dependencys/Generic/ToolOffsetTableProxy.cs</code> — the placeholder every brand preset
carries, which is why the fallback always resolves a table on Siemens.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="index.html">Program Data Plane</a> — the plane both leaves sit on, where this table is stored, and
what a brand switch does to it</li>
<li><a class="xref" href="tool-offsets.html">Tool Offsets</a> — the generic ledger one node above, whose label this table's
presence changes and whose wear convention is the opposite of the one stated here</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>