This commit is contained in:
2026-09-09 17:35:23 +08:00
parent 2a98ae7556
commit 161af68fe3
1271 changed files with 58251 additions and 98639 deletions
@@ -0,0 +1,223 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>APT Profile Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="APT Profile Panel | 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-AptProfilePanel">
<h1 id="apt-profile-panel">APT Profile Panel</h1>
<p>The main model is <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a> and its property <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a>.<a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a>.</p>
<p>See <a class="xref" href="../../../technique/milling-physics/cutter-geometry.html">Cutter Geometry</a>. <a class="xref" href="../../../api/Hi.Milling.Apts.GeneralApt.html">GeneralApt</a> is the generalization of the other <a class="xref" href="../../../api/Hi.Milling.Apts.IAptBased.html">IAptBased</a> types.</p>
<p>On the web client these fields have no panel of their own: they are rendered inline by the Flute Profile section of the cutter, the Control-Tree node whose role path is <code>toolhouse/tool-&lt;id&gt;/cutter/profile</code>, reached at <code>/tool-house/:toolId/cutter/profile</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. That same section carries the Profile Type selector above the fields. In the WPF client the APT fields are a component of their own, hosted by the Milling Cutter panel's Flute-Profile tab.</p>
<h2 id="layout">Layout</h2>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Flute Profile Section
<ul>
<li>Profile Type Selection Dropdown
<ul>
<li>General APT (<a class="xref" href="../../../api/Hi.Milling.Apts.GeneralApt.html">GeneralApt</a>)</li>
<li>Ball APT (<a class="xref" href="../../../api/Hi.Milling.Apts.BallApt.html">BallApt</a>)</li>
<li>Column APT (<a class="xref" href="../../../api/Hi.Milling.Apts.ColumnApt.html">ColumnApt</a>)</li>
<li>Cone APT (<a class="xref" href="../../../api/Hi.Milling.Apts.ConeApt.html">ConeApt</a>)</li>
<li>Taper APT (<a class="xref" href="../../../api/Hi.Milling.Apts.TaperApt.html">TaperApt</a>)</li>
</ul>
</li>
<li>First row, always present
<ul>
<li>Diameter Input Field (mm)</li>
<li>Length of Cut Input Field (mm)</li>
</ul>
</li>
<li>Type-dependent rows, one field per row, in this order
<ul>
<li>Round Radius (Rc) Input Field (mm)</li>
<li>Round Ring Radius (Rr) Input Field (mm)</li>
<li>Round Ring Height (Rz) Input Field (mm)</li>
<li>Bottom Cone Angle (Alpha) Input Field (deg)</li>
<li>Top Cone Angle (Beta) Input Field (deg)</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Which of the five type-dependent fields appear is decided by a per-APT-type table held in the panel itself, not by testing the APT object's interfaces:</p>
<table>
<thead>
<tr>
<th>Profile Type</th>
<th>Fields shown</th>
</tr>
</thead>
<tbody>
<tr>
<td>General APT</td>
<td>Rc, Rr, Rz, Alpha, Beta</td>
</tr>
<tr>
<td>Ball APT</td>
<td>none — Diameter and Length of Cut only</td>
</tr>
<tr>
<td>Column APT</td>
<td>Rc</td>
</tr>
<tr>
<td>Cone APT</td>
<td>Alpha</td>
</tr>
<tr>
<td>Taper APT</td>
<td>Rc, Rz, Alpha, Beta</td>
</tr>
</tbody>
</table>
<p>The interface casts live one layer down, on the read side: the cutter DTO builder fills <code>rc_mm</code>, <code>rr_mm</code>, <code>rz_mm</code>, <code>alpha_deg</code> and <code>beta_deg</code> by casting the APT to <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRc.html">IAptRc</a>, <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRr.html">IAptRr</a>, <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRz.html">IAptRz</a>, <a class="xref" href="../../../api/Hi.Milling.Apts.IAptAlpha.html">IAptAlpha</a> and <a class="xref" href="../../../api/Hi.Milling.Apts.IAptBeta.html">IAptBeta</a>, and emits null for a cast that fails.</p>
<p>Taper APT is where the panel's table and the engine's types disagree. <a class="xref" href="../../../api/Hi.Milling.Apts.TaperApt.html">TaperApt</a> is declared over <code>IAptBased</code>, <code>IAptRz</code>, <code>IAptAlpha</code> and <code>IAptBeta</code> and carries no round radius, so the table's Rc entry gives a Taper profile a Round Radius box that the DTO fills with null — the field reads 0 — and the value the panel sends back is not read by the server's Taper branch, which builds the APT from Diameter, Rz, Alpha, Beta and Flute Height alone. Rc on a Taper APT is therefore inert in both directions.</p>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>APT Profile Panel
<ul>
<li>Diameter Input Field (mm)</li>
<li>Round Radius Input Field (mm)
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRc.html">IAptRc</a></li>
<li>Round Ring Radius Input Field (mm)
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRr.html">IAptRr</a></li>
<li>Round Ring Height Input Field (mm)
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRz.html">IAptRz</a></li>
<li>Bottom Cone Angle Input Field (deg)
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptAlpha.html">IAptAlpha</a></li>
<li>Top Cone Angle Input Field (deg)
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptBeta.html">IAptBeta</a></li>
<li>Length of Cut Input Field (mm)</li>
</ul>
</li>
</ul>
<div class="TIP">
<h5>Tip</h5>
<p>Keep field format <code>G4</code> on this client. The web fields apply no format: they show the value as stored and commit on blur or Enter.</p>
</div>
<h2 id="features">Features</h2>
<p>Every edit re-sends the whole profile. Changing the type, or any one field, builds a fresh shaper-profile request carrying the type, Diameter, Length of Cut and only those of Rc / Rr / Rz / Alpha / Beta that the chosen type's table lists, and the server replaces the cutter's <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a> with a newly constructed APT of that type. The panel then clears the tool cache so the canvas redraws.</p>
<p>Clearing a field is ignored. The shared numeric input emits null for an empty box, and the panel returns on null instead of committing, so a blanked box keeps the previous value rather than writing 0.</p>
<p>Because the profile changes the flute geometry, the server does more than drop the cutter's cached solids: it also re-aligns the tool's holder-to-cutter anchor transformer, so the cutter is re-placed under the holder at its new height instead of rendering with a wrong exposed length.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterSectionPanel.vue</code> — the shipped home of these fields: the Profile Type selector, Diameter, Length of Cut, the per-type field table, and the whole-profile commit.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — builds the <code>profile</code> section node this panel renders.</li>
<li><code>wwwroot-src/src/router/treeRoutes.ts</code> — maps that node's role path onto the page's <code>:subtab</code> param.</li>
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the numeric field behind every APT input: unit as a suffix, commit on blur or Enter, no <code>G4</code>.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — the exact labels: &quot;Round Radius (Rc)&quot;, &quot;Round Ring Radius (Rr)&quot;, &quot;Round Ring Height (Rz)&quot;, &quot;Bottom Cone Angle (Alpha)&quot;, &quot;Top Cone Angle (Beta)&quot;, &ldquo;Diameter&rdquo;, &ldquo;Length of Cut&rdquo;, and the five APT type names.</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — <code>setShaperProfile</code> and the shaper-profile DTO shape, which carries only the fields the selected APT type lists.</li>
<li><code>Mech/CutterController.cs</code> — the shaper-profile endpoint: it builds a <code>ColumnApt</code>, <code>ConeApt</code>, <code>BallApt</code>, <code>TaperApt</code> or <code>GeneralApt</code> from the DTO, assigns a new <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a>, and runs the cache-clear and re-align hook.</li>
<li><code>Mech/CutterDtoBuilder.cs</code> — the read side that emits <code>aptType</code>, <code>diameter_mm</code>, <code>fluteHeight_mm</code> and the five interface-cast fields.</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>
@@ -0,0 +1,192 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cutter Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Cutter Panel | 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-CutterPanel">
<h1 id="cutter-panel">Cutter Panel</h1>
<h2 id="overview">Overview</h2>
<p>The key component is <a class="xref" href="../../../api/Hi.Machining.ICutter.html">ICutter</a>. A tool carries at most one cutter, and two concrete types answer to that interface: <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html">MillingCutter</a> and <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html">FreeformRemover</a>. This panel is where the type is chosen, and it holds the cutter's own General fields.</p>
<p>On the web client it is the Cutter tab of the <a class="xref" href="../index.html">Tool House Page</a>, reached at <code>/tool-house/:toolId/cutter</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. It is the panel of the Control-Tree Cutter node under the selected tool — the node whose role path is <code>toolhouse/tool-&lt;id&gt;/cutter</code>. In the WPF client the same surface is the Cutter Management Panel embedded in the tool's editor.</p>
<h2 id="layout">Layout</h2>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Cutter Node Panel
<ul>
<li>Title Label — Cutter</li>
<li>Cutter Type Selector — Milling Cutter / Freeform Remover / None</li>
<li>Milling Cutter branch, rendered only while the type is Milling Cutter
<ul>
<li>Shank Mass Input Field (g)</li>
<li>Hone Radius Input Field (um)</li>
<li>Relief Angle Input Field (deg)</li>
<li>Sections Hint Caption — points at the section tabs below</li>
</ul>
</li>
<li>Freeform Remover branch — one caption, <code>toolhouse.cutter.freeformRemoverUnavailable</code>, sending the reader to the WPF client or HiNcRcl</li>
<li>No-cutter branch — one hint, <code>toolhouse.cutter.noCutterHint</code>, inviting the reader to pick Milling Cutter</li>
</ul>
</li>
</ul>
<p>The three numeric fields are the cutter's General fields, and they sit here under the Metadata-on-container convention — a container's own General fields are edited on the container's panel instead of in a General child. They are plain, always-editable inputs: one label each, no label switching and no auto-computed mode, and all three commit together through the general endpoint, which accepts exactly <code>shankMass_g</code>, <code>honeRadius_um</code> and <code>reliefAngle_deg</code>. A blanked box commits nothing, so clearing a field never writes a zero.</p>
<p>The type also decides what grows below the node. A Milling Cutter grows the cutter's section tabs — Material, Flute Profile, Flute Contours, Upper Beam, Optimization — as the nodes whose role paths end in <code>.../cutter/material</code>, <code>.../cutter/profile</code>, <code>.../cutter/contours</code>, <code>.../cutter/upper-beam</code> and <code>.../cutter/opt</code>; Material is the one gated behind the Advanced Physics preference. Selecting one replaces this panel with that section's own panel; see <a class="xref" href="milling-cutter-panel.html">Milling Cutter Panel</a>. A Freeform Remover or no cutter grows nothing, so the Cutter node is a leaf and the caption or hint is the whole surface; see <a class="xref" href="freeform-remover-panel.html">Freeform Remover Panel</a>.</p>
<p>This panel carries no object management of its own. Object management for the tool library sits on the tool-house root node, where the <a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a> is bound to the whole <code>.MachiningToolHouse</code> file rather than to a per-cutter file.</p>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>Cutter Management Panel
<ul>
<li>Head Line
<ul>
<li><a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a>
<ul>
<li>File extension is <code>.Cutter</code>, load type <a class="xref" href="../../../api/Hi.Machining.ICutter.html">ICutter</a></li>
<li>The pointed Editor Panel is the cutter content presenter below</li>
</ul>
</li>
<li>Title Label</li>
<li>Cutter Type Selection Dropdown
<ul>
<li>Options: Milling Cutter, Freeform Remover, Unset</li>
</ul>
</li>
</ul>
</li>
<li>Cutter Content Presenter
Varies by the Cutter Type. It can be:
<ul>
<li><a class="xref" href="milling-cutter-panel.html">Milling Cutter Panel</a></li>
<li><a class="xref" href="freeform-remover-panel.html">Freeform Remover Panel</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The per-cutter <code>.Cutter</code> file is this client's, and so is the third option's Unset wording; the web selector's third option reads None.</p>
<h2 id="features">Features</h2>
<p>Committing a type on the web is one server call plus a cache clear. Milling Cutter calls <code>EnsureCutter</code>, which keeps the tool's existing MillingCutter and only creates one when the tool has none; None calls <code>ClearCutter</code>, which drops the tool's cutter altogether. The panel then clears the tool cache, re-reads the tool and emits a structure change for its own node, which is how the section tabs appear or disappear with the type.</p>
<p>Cache clearing is not a step the user performs. <a class="xref" href="../../../api/Hi.Machining.ICutter.html">ICutter</a> implements <a class="xref" href="../../../api/Hi.Common.IClearCache.html">IClearCache</a>, and every cutter endpoint that changes a field or a geometry clears the cache server-side before it answers: the field endpoints call <code>ClearCache()</code> on the milling cutter directly, while the ones that change flute or beam geometry go through the controller's resync hook, which clears the cache <em>and</em> re-aligns the tool's holder-to-cutter anchor transformer so the cutter is re-placed under the holder at its new height. On top of that the panels call <code>clearToolCache(toolId)</code>, which clears the tool's cached solids and the holder's, so the tool canvas redraws.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolCutterPanel.vue</code> — the Cutter node's panel: the Milling Cutter / Freeform Remover / None selector, the Shank Mass / Hone Radius / Relief Angle fields, the Freeform Remover caption and the no-cutter hint. Commits a type change through <code>ensureCutter</code> or <code>clearCutter</code> followed by <code>clearToolCache</code>.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — registers this panel as the <code>ToolCutter</code> item type; its cutter child builder grows the section tabs only for a MillingCutter, and gates Material on the Advanced Physics preference.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterSectionPanel.vue</code> and <code>wwwroot-src/src/components/controlTree/toolhouse/CutterContoursPanel.vue</code> — the panels those section nodes render.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHouseRootPanel.vue</code> — the tool-house root panel, which carries the Object Management Menu Button for the <code>.MachiningToolHouse</code> file.</li>
<li><code>wwwroot-src/src/components/widgets/ObjectManagementMenuButton.vue</code> — the reused object-management dropdown that root panel mounts.</li>
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the shared numeric field behind the three General inputs; it commits on blur or Enter and reverts an unparseable entry.</li>
<li><code>wwwroot-src/src/pages/ToolHousePage.vue</code> — the routed page that hosts the tool list and the tab cascade this panel appears in; the route is <code>/tool-house/:toolId?/:tab?/:subtab?</code>.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — the <code>toolhouse.cutter.*</code> strings this panel renders: cutterType, shankMass, honeRadius, reliefAngle, sectionsHint, freeformRemoverUnavailable, noCutterHint, millingCutter, freeformRemover. The None option's label comes from <code>common.options.none</code> in <code>wwwroot-src/src/i18n/en/common.ts</code>.</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — the typed wrapper: <code>/api/ToolHouse</code> for the house and the tool-level fields, <code>/api/Cutter</code> for every cutter mutation, plus <code>ensureCutter</code>, <code>clearCutter</code>, <code>setGeneral</code> and <code>clearToolCache</code>.</li>
<li><code>Mech/CutterController.cs</code> — the cutter backend at <code>/api/Cutter</code>: <code>EnsureCutter</code> / <code>ClearCutter</code>, the shaper-profile, fluting, general and opt-limit endpoints, the upper-beam endpoints and the material and coating-layer endpoints. Every field and geometry mutator clears the cutter cache before it answers.</li>
<li><code>Mech/CutterDtoBuilder.cs</code> — the single source of truth for the read-side cutter DTO (integralMode, general, shaperProfile, fluting, optLimit, material), shared by <code>CutterController</code> and the tool detail in <code>ToolHouseController</code>.</li>
<li><code>Mech/ToolHouseController.cs</code> — the tool detail that embeds that cutter DTO and that this panel reads on mount, plus the tool-cache clear the panel calls after every commit.</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>
@@ -0,0 +1,215 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Freeform Remover Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Freeform Remover Panel | 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-FreeformRemoverPanel">
<h1 id="freeform-remover-panel">Freeform Remover Panel</h1>
<p>The key model is <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html">FreeformRemover</a>: a cutter whose removal volume comes from two referenced geometries — a non-cutting strut and a cutting shaper — anchored to the holder buckle.</p>
<p>The two clients divide this cutter between them. The WPF client owns the editing surface: both geometries, the anchor, the spinning flag and the identity fields. The web client offers the type in the Cutter Type selector and nothing more; there is no Freeform Remover editor on the web, and no freeform-remover endpoint in the backend, so a freeform remover is built and edited on the WPF client or through HiNcRcl.</p>
<h2 id="layout">Layout</h2>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>Freeform Remover Panel
<ul>
<li>Tabs
<ul>
<li>Strut Geometry Tab
<ul>
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Panel</a>
<ul>
<li>Manages <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_StrutGeom">StrutGeom</a></li>
</ul>
</li>
</ul>
</li>
<li>Shaper Geometry Tab
<ul>
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Panel</a>
<ul>
<li>Manages <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_ShaperGeom">ShaperGeom</a></li>
</ul>
</li>
</ul>
</li>
<li>Anchor Tab
<ul>
<li>Label: Geometry Anchor To Holder Buckle</li>
<li><a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_KeepHolderBuckleOnTop">KeepHolderBuckleOnTop</a> Checkbox</li>
<li><a class="xref" href="../../geom/transformer-panel.html">Transformer Manage Panel</a>
<ul>
<li>Model is <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_GeomToHolderTransformer">GeomToHolderTransformer</a></li>
<li>Enabled if <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_KeepHolderBuckleOnTop">KeepHolderBuckleOnTop</a> is true.</li>
</ul>
</li>
</ul>
</li>
<li>Property Tab
<ul>
<li>Is Spinning Cutter Checkbox
<ul>
<li>Controls <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_IsSpinningCutter">IsSpinningCutter</a></li>
</ul>
</li>
</ul>
</li>
<li>Info Tab
<ul>
<li>Name TextField (editable)</li>
<li>AbstractNote TextField (readonly)</li>
<li>Note TextField (editable)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>This panel calls <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_ClearCache">ClearCache()</a> itself after a geometry or anchor change, so the cached solids are dropped before the tool is redrawn.</p>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Cutter Node Panel, the Cutter tab of the <a class="xref" href="../index.html">Tool House Page</a> at <code>/tool-house/:toolId/cutter</code> — the Control-Tree node <code>toolhouse/tool-&lt;id&gt;/cutter</code>
<ul>
<li>Cutter Type Selector — its second option, Freeform Remover, is this cutter</li>
<li>Freeform Remover Caption (<code>toolhouse.cutter.freeformRemoverUnavailable</code>) — the panel's whole body while that option is showing, directing the reader to the WPF client or HiNcRcl</li>
</ul>
</li>
</ul>
<p>Nothing else on the web belongs to this cutter. The Shank Mass / Hone Radius / Relief Angle fields on that panel are gated to the Milling Cutter branch, and the cutter's child builder grows section tabs only for a MillingCutter, so the Cutter node is a leaf here: no Material, Flute Profile, Flute Contours, Upper Beam or Optimization section appears. See <a class="xref" href="cutter-panel.html">Cutter Panel</a> for the panel these live on.</p>
<h2 id="geometry-definitions">Geometry Definitions</h2>
<ul>
<li><strong>Strut Geometry</strong> — The non-cutting portion (holder/shank)
<ul>
<li>Used for collision detection</li>
</ul>
</li>
<li><strong>Shaper Geometry</strong> — The cutting portion
<ul>
<li>Defines cutting surfaces</li>
<li>Used for material removal simulation</li>
</ul>
</li>
</ul>
<h2 id="features">Features</h2>
<p>Picking Freeform Remover on the web is a no-op that does not stick. The panel makes no API call for that option — it sets the selector locally, clears the tool cache, then re-reads the tool, and the re-read is what puts the selector back to Milling Cutter or None. The model on the tool is left exactly as it was.</p>
<p>A tool that already carries a freeform remover reads as None. The tool detail casts the tool's cutter to a MillingCutter and reports both <code>hasCutter</code> and the embedded cutter DTO from that one cast, so a non-milling cutter comes back as no cutter at all, and the selector — which derives its value from those two fields — shows None. The Freeform Remover option is therefore reachable by the user's click but never by a load.</p>
<p>That makes one sequence worth knowing before using the web page on such a tool: picking Milling Cutter calls <code>EnsureCutter</code>, which returns the tool's existing cutter only when it is already a MillingCutter and otherwise assigns a new one — so on a tool holding a freeform remover, that choice replaces it. Leaving the selector alone leaves the freeform remover intact, which is what a round trip through the web page does by default.</p>
<p>Cache clearing needs no user action on either client. The WPF panel clears the remover's cache after each geometry or anchor edit; on the web there is nothing to clear for this cutter, since no endpoint mutates it, and the tool-cache clear the selector performs only drops the tool's and the holder's cached solids so the canvas redraws.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolCutterPanel.vue</code> — the only web surface this cutter has: the selector option, the caption shown in its place, and the branch of the type handler that makes no call.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — its cutter child builder grows sections only for a MillingCutter, so this cutter's Cutter node is a leaf.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — <code>toolhouse.cutter.freeformRemover</code>, the option label, and <code>toolhouse.cutter.freeformRemoverUnavailable</code>, the caption; the zh-Hans and zh-Hant files carry the same keys.</li>
<li><code>Mech/ToolHouseController.cs</code> — the tool detail, which casts the cutter to a MillingCutter and reports <code>hasCutter</code> from that cast; this is why the selector cannot come back showing Freeform Remover.</li>
<li><code>Mech/CutterController.cs</code> — <code>EnsureCutter</code> / <code>ClearCutter</code> and every cutter mutation, all MillingCutter-only; the backend has no freeform-remover endpoint.</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>
@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cutter Tab | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Cutter Tab | 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-Cutter">
<h1 id="cutter-tab">Cutter Tab</h1>
<p>The Cutter tab of the Tool House page, reached as <code>/tool-house/:toolId/cutter</code> and, for its inner
editors, <code>/tool-house/:toolId/cutter/:subtab</code>. The tab's own panel chooses the cutter type and holds
the identity fields every cutter has; the type chosen decides which editor grows below it.</p>
<p>Ordered with the tab's own panel first, then one page per cutter type, then the profile editor the
types share.</p>
<h2 id="pages">Pages</h2>
<ul>
<li><a href="cutter-panel.html">Cutter Panel</a> — The tab itself: the cutter type selector and the fields common to every cutter</li>
<li><a href="milling-cutter-panel.html">Milling Cutter Panel</a> — The shipped cutter type: material, profile, flute contours, upper beam and optimization limits</li>
<li><a href="freeform-remover-panel.html">Freeform Remover Panel</a> — The freeform removal volume, and where it is edited</li>
<li><a href="apt-profile-panel.html">APT Profile Panel</a> — The five APT profile types the shaper profile offers, shared by the cutter editors</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../index.html">Tool House Page</a> — the page these tabs belong to</li>
<li><a href="../holder/index.html">Holder Tab</a> — the sibling tab, and the other half of a tool</li>
<li><a href="../stick-tool-panel.html">Stick Tool Panel</a> — the tool node whose tab cascade this tab belongs to</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>
@@ -0,0 +1,394 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Milling Cutter Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Milling Cutter Panel | 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-MillingCutterPanel">
<h1 id="milling-cutter-panel">Milling Cutter Panel</h1>
<p>The key model is <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html">MillingCutter</a>, the cutter type both clients edit in full.</p>
<p>On the web client this cutter is not one panel but the section tabs the <a class="xref" href="cutter-panel.html">Cutter Panel</a> grows once a Milling Cutter is assigned: the Control-Tree nodes under <code>toolhouse/tool-&lt;id&gt;/cutter</code>, reached at <code>/tool-house/:toolId/cutter/:subtab</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. The five <code>:subtab</code> values are <code>material</code>, <code>profile</code>, <code>contours</code>, <code>upper-beam</code> and <code>opt</code>. The cutter's General fields — Shank Mass, Hone Radius, Relief Angle — are not among them: they sit on the Cutter node's own panel. In the WPF client the same cutter is one tab control, and it carries several groups the web does not offer.</p>
<h2 id="layout">Layout</h2>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Cutter Section Tabs, in this order
<ul>
<li><a href="#material-section">Material Section</a> — grows only while the Advanced Physics preference is on</li>
<li><a href="#flute-profile-section">Flute Profile Section</a></li>
<li><a href="#flute-contours-section">Flute Contours Section</a></li>
<li><a href="#upper-beam-section">Upper Beam Section</a></li>
<li><a href="#optimization-section">Optimization Section</a></li>
</ul>
</li>
</ul>
<p>Material is the only physics-gated section. Flute Profile, Flute Contours, Upper Beam and Optimization grow for every Milling Cutter. The preference behind the gate is the SPA's Advanced Physics option, held as <code>isShowPhysicsOptions</code> in the app-state store and read from the server's preference endpoint, which reports it as on only while the physics feature is licensed. <code>UserService.EnablePhysics</code> is the WPF client's name for the same preference.</p>
<p>Integral mode is read-only on the web. The cutter DTO reports it, and the Material section reads it to decide whether the Shank Material picker applies, but no endpoint sets it; it is chosen on the WPF client's Property tab.</p>
<h4 id="material-section">Material Section</h4>
<ul>
<li>Material Section (<code>.../cutter/material</code>)
<ul>
<li>Flute Material
Applies <a class="xref" href="../../../api/Hi.Physics.CutterMaterial.html">CutterMaterial</a>
<ul>
<li>Intro caption naming the <code>.CutterMaterial</code> extension</li>
<li>Material File Selector
<ul>
<li>Menu Dropdown — Browse Resource…, plus Clear once a file is picked</li>
<li>Readonly path TextBox with the placeholder &ldquo;No flute material selected&rdquo;</li>
</ul>
</li>
<li>Name and note caption beneath the picker, the two joined on one line</li>
</ul>
</li>
<li>Shank Material, rendered only while the cutter's integral mode is Insert End
Applies <a class="xref" href="../../../api/Hi.Physics.IStructureMaterial.html">IStructureMaterial</a>
<ul>
<li>Intro caption naming the <code>.xml</code> structure material and the <code>.CutterMaterial</code> alternative</li>
<li>Material File Selector, filtered to <code>.xml</code> — same Browse Resource… menu, with the placeholder &ldquo;Default: AlloySteel42CrMo&rdquo;</li>
<li>Name and note caption beneath the picker</li>
</ul>
</li>
<li>Solid-End Note, shown in place of that block for a solid-end cutter — the shank material mirrors the flute material, so it has no separate setting</li>
<li>Coating Layers
Manages <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_CoatingLayerList">CoatingLayerList</a>
<ul>
<li>Add Layer Button</li>
<li>One sequence hint above the whole list: the sequence starts from the surface, <code>#0</code> is the outermost / air-exposing layer, and each layer is a <code>.CoatingMaterial</code> plus a thickness in um</li>
<li>One row per <a class="xref" href="../../../api/Hi.Physics.ThermalLayer1D.html">ThermalLayer1D</a>, all controls on that one line
<ul>
<li>Index Badge <code>#i</code></li>
<li>Coating Material File Selector — Browse Resource…, placeholder &ldquo;No coating material&rdquo;</li>
<li>Thickness Input Field (um) — <a class="xref" href="../../../api/Hi.Physics.ThermalLayer1D.html#Hi_Physics_ThermalLayer1D_Length_um">Length_um</a></li>
<li>Move Toward Surface Button, disabled on the first row</li>
<li>Move Toward Body Button, disabled on the last row</li>
<li>Delete Layer Button</li>
</ul>
</li>
<li>Empty state caption &ldquo;No coating layers.&rdquo;</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>All three pickers are resource-only, which is what leaves the dropdown with a single browse entry: the absolute Browse item is hidden and only Browse Resource… remains. The picked material's name and note are rendered as a caption line under the picker rather than as a tooltip on a readonly name box.</p>
<p>The mirroring for a solid-end cutter is enforced server-side: loading a flute material onto a solid-end cutter assigns the same material as the shank material, and unsetting it clears both. For an insert-end cutter, unsetting the shank material resets it to the built-in AlloySteel42CrMo rather than to nothing.</p>
<p>Every coating endpoint answers with the whole cutter DTO, so the row list re-renders from the server's own ordering after an add, a move or a delete.</p>
<h5 id="default-resource">Default Resource</h5>
<p>The default resources of Material live in the built-in <code>Resource</code> folder the server exposes as a named root of its own — not in the project folder. Each picker opens Browse Resource… into its own subfolder of that root:</p>
<ul>
<li><code>StructureMaterial</code> — the Shank Material picker</li>
<li><code>CutterMaterial</code> — the Flute Material picker</li>
<li><code>CoatingMaterial</code> — the coating rows' pickers</li>
</ul>
<h4 id="flute-profile-section">Flute Profile Section</h4>
<ul>
<li>Flute Profile Section (<code>.../cutter/profile</code>)
<ul>
<li>Profile Type Selection Dropdown
<ul>
<li>General APT (<a class="xref" href="../../../api/Hi.Milling.Apts.GeneralApt.html">GeneralApt</a>)</li>
<li>Ball APT (<a class="xref" href="../../../api/Hi.Milling.Apts.BallApt.html">BallApt</a>)</li>
<li>Column APT (<a class="xref" href="../../../api/Hi.Milling.Apts.ColumnApt.html">ColumnApt</a>)</li>
<li>Cone APT (<a class="xref" href="../../../api/Hi.Milling.Apts.ConeApt.html">ConeApt</a>)</li>
<li>Taper APT (<a class="xref" href="../../../api/Hi.Milling.Apts.TaperApt.html">TaperApt</a>)</li>
</ul>
</li>
<li>The APT fields themselves, rendered inline in this same panel</li>
</ul>
</li>
</ul>
<p>The five types are all wrapped by <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a>, with a different <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> assigned; which fields appear depends on the type. See <a class="xref" href="apt-profile-panel.html">APT Profile Panel</a> for the field list and the per-type table that drives it.</p>
<p>See the <code>DemoBuildMachiningProject</code> sample in the <a class="xref" href="../../../technique/api-foundations/packages-and-samples.html">Hi.Sample repository</a> for creating the APT profile and setting it on the cutter.</p>
<p><code>CustomSpinningProfile</code> is the WPF client's sixth profile type; the web offers the five APT types only.</p>
<h4 id="flute-contours-section">Flute Contours Section</h4>
<p>This part manages <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_Fluting">Fluting</a>. It is a stem, not a leaf: the section node carries only the type selector, and the fluting itself is a sub-tree of nodes below it.</p>
<ul>
<li>Flute Contours Section (<code>.../cutter/contours</code>)
<ul>
<li>Title Label — Fluting</li>
<li>Fluting Type Selection Dropdown
<ul>
<li>Uniform (shared baseline) — <a class="xref" href="../../../api/Hi.Milling.FluteContours.UniformFluting.html">UniformFluting</a></li>
<li>Free (per-flute) — <a class="xref" href="../../../api/Hi.Milling.FluteContours.FreeFluting.html">FreeFluting</a></li>
<li><code>— unset —</code></li>
</ul>
</li>
<li>A caption describing the chosen kind, or &ldquo;Fluting unset.&rdquo; while none is set</li>
<li>Fluting Node, grown only once a fluting is set — labelled Uniform Fluting or Free Fluting
<ul>
<li>For a uniform fluting: Flute Number Input Field (minimum 1)</li>
<li>For a free fluting: a &ldquo;Flutes: n&rdquo; caption and an Add Flute Button, with a &ldquo;No flutes yet&rdquo; hint while the list is empty</li>
<li>Flute Contour Node(s)
<ul>
<li>One Baseline Contour node (<code>.../fluting/baseline</code>) for a uniform fluting; one Flute <em>n</em> node (<code>.../fluting/flute-{i}</code>) per flute for a free fluting</li>
<li>Setup Angle Input Field (deg)</li>
<li>Delete This Flute Button — free fluting only</li>
<li>Side Contour Sub-Node (<code>.../baseline/side</code>, <code>.../flute-{i}/side</code>)
<ul>
<li>Kind Selector — Const Helix / Freeform / <code>— unset —</code></li>
<li>Const Helix Side Contour form: Helix Angle (deg), Radial Rake Angle (deg), Radial Relief Angle (deg)</li>
<li>Freeform Side Contour form: the span-position table, ordered by Z</li>
</ul>
</li>
<li>Bottom Contour Sub-Node (<code>.../baseline/bottom</code>, <code>.../flute-{i}/bottom</code>)
<ul>
<li>Kind Selector — Slide / Freeform / <code>— unset —</code></li>
<li>Slide Bottom Contour form: Outer Radius (mm), Cutter Length on Bottom Projection (mm), Eccentric Angle (deg), Disk Angle (deg), Axial Rake Angle (deg)</li>
<li>Freeform Bottom Contour form: the span-position table, ordered by R</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Both freeform forms share one span-position table: four numeric columns — R (mm), A (deg), Z (mm), R.Ang (deg) — one row per 4D span position, with an insert-next button that clones the row and a double-click to remove it. The header wording mirrors the CSV field order the wire format uses, and the R.Ang column carries a tooltip explaining that the radial angle feeds the bottom-surface loft.</p>
<p>A flute contour is always committed as a whole. Editing a Setup Angle, a side contour or a bottom contour re-sends the entire contour: a uniform fluting re-sends the fluting with its current flute number, and a free fluting updates the slot at its index. Free flute node ids are positional, so adding or deleting a flute rebuilds the branch to re-point them.</p>
<p>Picking <code>— unset —</code> in the Fluting Type selector is inert — the panel returns without a call, because the backend exposes no way to null a fluting. Picking <code>— unset —</code> on a Side or Bottom Contour, in contrast, does commit: it clears that contour on the flute.</p>
<h4 id="upper-beam-section">Upper Beam Section</h4>
<p>The upper beam is the cutter's shank / body above the flute.</p>
<ul>
<li>Upper Beam Section (<code>.../cutter/upper-beam</code>)
<ul>
<li>Intro caption</li>
<li>Warnings Banner — one orange banner per geometry issue the backend reports, e.g. an ExtendedCylinder beam whose FullLength sits below the flute top</li>
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Control</a>, limited to the six <a class="xref" href="../../../api/Hi.Geom.IGetStl.html">IGetStl</a> kinds an upper beam can be
<ul>
<li><a class="xref" href="../../../api/Hi.Geom.Cylindroid.html">Cylindroid</a></li>
<li><a class="xref" href="../../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a></li>
<li><a class="xref" href="../../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a></li>
<li><a class="xref" href="../../../api/Hi.Geom.StlFile.html">StlFile</a></li>
<li><a class="xref" href="../../../api/Hi.Geom.Box3d.html">Box3d</a></li>
<li><a class="xref" href="../../../api/Hi.Geom.GeomCombination.html">GeomCombination</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The banner is persistent rather than a transient toast: the same unreasonable settings fail thermal physics at run time as configuration errors, so they are surfaced at edit time. Creating a geometry here is container-aware — the server builds it, sets it as the cutter's upper-beam geometry, auto-links an ExtendedCylinder to the flute with a valid seed length, and indexes it under the same key so the per-kind editor edits it in place. Each later edit resyncs the cutter and refreshes the warning list.</p>
<h4 id="optimization-section">Optimization Section</h4>
<p>This part manages <a class="xref" href="../../../api/Hi.NcOpt.MillingCutterOptOption.html">MillingCutterOptOption</a>.</p>
<ul>
<li>Optimization Section (<code>.../cutter/opt</code>)
<ul>
<li>Enable Optimization Checkbox
<ul>
<li>Controls whether the limits below are shown and active</li>
</ul>
</li>
<li>When optimization is enabled:
<ul>
<li>Limit by Theoretical Minimum Feed Per Tooth Checkbox</li>
<li>Limit by Relief Angle Checkbox</li>
<li>Min Feed Per Tooth Input Field (mm)</li>
<li>Max Feed Per Tooth Input Field (mm)</li>
<li>Yielding Utilization Factor Input Field
<ul>
<li>The reciprocal of the Yielding Safety Factor the server stores; the panel converts in both directions</li>
</ul>
</li>
<li>Hint caption: typical values run 0.33 (conservative) to 1.0 (aggressive)</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Both checkboxes are plain labelled checkboxes — neither displays a computed value. The server's defaults when a limit set is written without them are a Yielding Safety Factor of 3 (a utilization factor of about 0.33), a Max Feed Per Tooth of 999, and both limit flags on.</p>
<p>The minimum uncut chip thickness itself is not on this surface: no cutter endpoint returns it, and no field displays it. It is the WPF client's Optimization panel that computes it from the cutter and the project workpiece's cutting parameter and shows it beside the checkbox.</p>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>Milling Cutter Panel
<ul>
<li>Tabs
<ul>
<li>Flute-Profile Tab — the profile type dropdown plus the APT panel, and the <code>CustomSpinningProfile</code> option with its own geometry-management panel</li>
<li>Upper-Beam Tab
<ul>
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Control</a>, with the <a class="xref" href="../../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a> option enabled</li>
</ul>
</li>
<li>Property Tab
<ul>
<li>Integral Mode Selection Dropdown — Solid End / Insert End</li>
<li>Cutter/Shank Mass Input Field (g), with an Auto Update CheckBox driven by <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_ShankMassAssignmentMode">ShankMassAssignmentMode</a>: when enabled the field turns readonly and shows the mass computed from the inner-beam and upper-beam volume and the density</li>
<li>Hone Radius (um) and Relief Angle (deg) Input Fields</li>
<li>Minimum Available Cutting Thickness (um), readonly, from <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_GetMinimumUncutChipThickness_um_Hi_MillingForces_Fittings_ICuttingPara_">GetMinimumUncutChipThickness_um(ICuttingPara)</a> with the project workpiece's <a class="xref" href="../../../api/Hi.NcMech.Workpieces.Workpiece.html#Hi_NcMech_Workpieces_Workpiece_CuttingPara">CuttingPara</a>, and a note label naming that cutting parameter</li>
</ul>
</li>
<li>Insert-Cutter Tab
<ul>
<li>Insert Number, Insert Mass (g) and Insert Thickness (mm) Input Fields; the thickness feeds heat transfer</li>
</ul>
</li>
<li>Material Tab</li>
<li>Flute-Contours Tab</li>
<li>Flute-Inner-Beam Tab
<ul>
<li>Profile Type Selection Dropdown for <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_InnerBeamProfile">InnerBeamProfile</a> — Flute Dependent Ratio (<a class="xref" href="../../../api/Hi.Milling.Cutters.FluteDependentRatioProfile.html">FluteDependentRatioProfile</a>), Const Ratio (<a class="xref" href="../../../api/Hi.Milling.Cutters.ConstRatioProfile.html">ConstRatioProfile</a>), Custom Spinning (<a class="xref" href="../../../api/Hi.Milling.Cutters.CustomSpinningProfile.html">CustomSpinningProfile</a>)</li>
<li>For Flute Dependent Ratio: a readonly Radius Ratio field whose label also names the flute number it depends on</li>
<li>For Const Ratio: an editable Radius Ratio field</li>
<li>For Custom Spinning: a <a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Control</a></li>
</ul>
</li>
<li>Optimization Tab — the same limits as the web section, plus the computed minimum uncut chip thickness beside the minimum-feed checkbox</li>
<li>Info Tab
<ul>
<li>Name TextField (editable)</li>
<li>AbstractNote TextField (readonly)</li>
<li>Note TextField (editable)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><code>UserService.EnablePhysics</code> gates the Property, Material, Flute-Contours, Flute-Inner-Beam and Optimization tabs on this client; the Insert-Cutter tab additionally requires Insert End. Flute-Profile, Upper-Beam and Info are always visible. On the web only the Material section is gated, and the same preference is named <code>isShowPhysicsOptions</code>.</p>
<p>Numeric fields on this client are formatted <code>G4</code>. The web's numeric field applies no format: it shows the value as stored and commits on blur or Enter.</p>
<p>The cutter has no identity fields on the web. Tool ID, Note and the auto-derived Abstract Note belong to the tool, one level up, and are edited on the tool's own General tab; see <a class="xref" href="../index.html">Tool House Page</a>.</p>
<h2 id="features">Features</h2>
<p>Every web edit is a whole-object commit followed by a cache clear. The Flute Profile panel re-sends the entire shaper profile on any field change — only the fields the selected APT type carries are included — then clears the tool cache. The contour panels re-send the whole flute contour. The optimization panel re-sends the whole limit set. The material and coating endpoints each answer with the full cutter DTO, which the panels re-render from.</p>
<p>A blanked numeric box commits nothing. The shared numeric field emits null for an empty entry, and every cutter panel returns on null rather than writing a zero, so clearing a field leaves the stored value alone.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — the item-type registry and the child builders: the cutter's five sections, the Material physics gate, and the fluting / flute / side / bottom sub-tree.</li>
<li><code>wwwroot-src/src/router/treeRoutes.ts</code> — role-path to route translation; <code>CUTTER_SECTIONS</code> pins <code>material</code>, <code>profile</code>, <code>contours</code>, <code>upper-beam</code> and <code>opt</code>, and it also translates a <code>…/contours/tray…</code> id onto the <code>fluting</code> segment the node carries, so both spellings of the engine's Fluting type family resolve.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolCutterPanel.vue</code> — the parent Cutter node: the type selector plus the cutter's General fields.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterSectionPanel.vue</code> — the one panel shared by the material / profile / upper-beam / opt sections, keyed off the node's last role segment. It renders the Flute Profile fields inline and delegates the other three.</li>
<li><code>wwwroot-src/src/components/toolhouse/MaterialDiv.vue</code> — the Material section: flute material, the insert-end-only shank material, the solid-end note, and the coating list.</li>
<li><code>wwwroot-src/src/components/toolhouse/CoatingLayersDiv.vue</code> — the coating rows: index badge, material picker, thickness, move toward surface / body, delete.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterContoursPanel.vue</code> — the Flute Contours stem: the Fluting Type selector.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/FlutingPanel.vue</code> — the concrete fluting node: Flute Number for uniform, the flute count and Add Flute for free.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/FluteContourPanel.vue</code> — one flute contour node: Setup Angle, and Delete This Flute for a free flute.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/FluteSideContourPanel.vue</code> and <code>wwwroot-src/src/components/controlTree/toolhouse/FluteBottomContourPanel.vue</code> — the two sub-nodes: kind selector plus the matching form.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/fluteContourNode.ts</code> — the shared load and commit logic behind those three panels, and the rule that a contour is committed whole.</li>
<li><code>wwwroot-src/src/components/toolhouse/fluting/ConstHelixSideContourDiv.vue</code>, <code>wwwroot-src/src/components/toolhouse/fluting/SlideBottomContourDiv.vue</code>, <code>wwwroot-src/src/components/toolhouse/fluting/FreeformSideContourDiv.vue</code> and <code>wwwroot-src/src/components/toolhouse/fluting/FreeformBottomContourDiv.vue</code> — the four contour parameter forms.</li>
<li><code>wwwroot-src/src/components/toolhouse/fluting/SpanContourPosListDiv.vue</code> — the R / A / Z / R.Ang span-position table both freeform forms share.</li>
<li><code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> — the Upper Beam section: the six allowed geometry kinds, the container-aware create, the resync-on-edit and the warnings banner.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the shared geometry editor that section reuses.</li>
<li><code>wwwroot-src/src/components/toolhouse/MillingCutterOptLimitDiv.vue</code> — the Optimization section, including the Yielding Utilization Factor conversion.</li>
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the numeric field every cutter form uses: no <code>G4</code>, commit on blur or Enter, revert on an unparseable entry.</li>
<li><code>wwwroot-src/src/components/widgets/FilePathInput.vue</code> — the picker behind the material selectors; its resource-only mode hides the absolute Browse item and leaves Browse Resource….</li>
<li><code>wwwroot-src/src/stores/appState.ts</code> — holds <code>isShowPhysicsOptions</code>, the Advanced Physics preference that gates the Material section.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — every label quoted above: <code>cutter.*</code>, <code>material.*</code>, <code>contour.*</code>, <code>fluting.*</code>, <code>upperBeam.*</code> and <code>opt.*</code>.</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — the typed wrapper over <code>/api/Cutter</code>: shaper profile, fluting, the free-contour CRUD, the material and coating endpoints, the upper beam and the opt limit.</li>
<li><code>Mech/CutterController.cs</code> — the cutter backend: the APT construction from the profile DTO, the fluting builders, the opt-limit defaults, the solid-end shank-material mirroring, and the cache clear every field and geometry mutator performs.</li>
<li><code>Mech/CutterDtoBuilder.cs</code> — the read-side cutter DTO: integral mode, general, shaper profile, fluting, opt limit and material.</li>
<li><code>Mech/ToolHouseController.cs</code> — the tool detail that embeds that DTO, which every cutter section refreshes from.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../../geom/extended-cylinder-panel.html">Extended Cylinder Panel</a> — the Upper Beam's kind that exists
for this cutter, and the one surface that gives it a start section</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>
@@ -0,0 +1,34 @@
<div id="sidetoggle">
<div>
<div class="sidefilter">
<form class="toc-filter">
<span class="glyphicon glyphicon-filter filter-icon"></span>
<span class="glyphicon glyphicon-remove clear-icon" id="toc_filter_clear"></span>
<input type="text" id="toc_filter_input" placeholder="Filter by title" onkeypress="if(event.keyCode==13) {return false;}">
</form>
</div>
<div class="sidetoc">
<div class="toc" id="toc">
<ul class="nav level1">
<li>
<a href="index.html" name="" title="Overview">Overview</a>
</li>
<li>
<a href="cutter-panel.html" name="" title="Cutter Panel">Cutter Panel</a>
</li>
<li>
<a href="milling-cutter-panel.html" name="" title="Milling Cutter Panel">Milling Cutter Panel</a>
</li>
<li>
<a href="freeform-remover-panel.html" name="" title="Freeform Remover Panel">Freeform Remover Panel</a>
</li>
<li>
<a href="apt-profile-panel.html" name="" title="APT Profile Panel">APT Profile Panel</a>
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -0,0 +1,2 @@
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Cutter Panel","href":"cutter-panel.html","topicHref":"cutter-panel.html"},{"name":"Milling Cutter Panel","href":"milling-cutter-panel.html","topicHref":"milling-cutter-panel.html"},{"name":"Freeform Remover Panel","href":"freeform-remover-panel.html","topicHref":"freeform-remover-panel.html"},{"name":"APT Profile Panel","href":"apt-profile-panel.html","topicHref":"apt-profile-panel.html"}]}
@@ -0,0 +1,189 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cylindroid Holder Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Cylindroid Holder Panel | 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-CylindroidHolderPanel">
<h1 id="cylindroid-holder-panel">Cylindroid Holder Panel</h1>
<p>The key model is <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html">CylindroidHolder</a>: a holder revolved from a Z-R profile, carrying its own name and note and its own STL tessellation resolution.</p>
<p>On the web client the holder occupies two child sections of the Holder node under the selected tool — Geometry and Resolution, the nodes whose role paths end in <code>.../holder/geometry</code> and <code>.../holder/resolution</code>, reached at <code>/tool-house/:toolId/holder/geometry</code> and <code>/tool-house/:toolId/holder/resolution</code>. Its Name, readonly Abstract Note and Note are edited one level up, on the <a class="xref" href="holder-panel.html">Holder Panel</a> itself, under the Metadata-on-container convention. Every field ships on both clients; what differs is the surface hosting them — the WPF client gives the same three fields a tab of their own.</p>
<h2 id="layout">Layout</h2>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Geometry Section
<ul>
<li><a class="xref" href="../../geom/cylindroid-control.html">Cylindroid Panel</a> — the reusable Z-R pair table, driven by a model key</li>
<li>Initializing Caption — stands in for the editor until the holder's cylindroid has been published under a key</li>
</ul>
</li>
<li>Resolution Section
<ul>
<li>Resolution Hint Caption — names the STL tessellation resolution used for display and collision meshing</li>
<li>Linear Resolution (mm) Input Field</li>
<li>Angle Resolution (deg) Input Field</li>
</ul>
</li>
</ul>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>Cylindroid Holder Panel
<ul>
<li>Head Line
<ul>
<li>Title Label</li>
</ul>
</li>
<li>Tabs
<ul>
<li>Geometry Tab
<ul>
<li><a class="xref" href="../../geom/cylindroid-control.html">Cylindroid Panel</a></li>
</ul>
</li>
<li>Resolution Tab
Model: <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_PolarResolution2d">PolarResolution2d</a>
<a class="xref" href="../../widget/polar-resolution-2d-panel.html">Polar Resolution 2d</a></li>
<li>Info Tab
<ul>
<li>Name TextField (editable)</li>
<li>AbstractNote TextField (readonly)</li>
<li>Note TextField (editable)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Remember to call <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_UpdateByCylindroid">UpdateByCylindroid()</a> after geometry reference or content changed.</p>
<h2 id="feature">Feature</h2>
<p>The two web sections reach the model by different routes, and that difference is why the holder resync belongs to one of them and not the other.</p>
<p><strong>Geometry.</strong> The section mounts the reusable Cylindroid editor on a key. <code>Get</code> publishes the holder's own <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_Cylindroid">Cylindroid</a> in the index service under a per-session <code>-HolderCylindroid</code> key and hands that key back — but only when the caller supplies its session key; with no session key the response carries a null key and the section shows its initializing caption in the editor's place. The key names the same object the holder holds, so an edit lands on the holder's geometry directly. Because that generic editor mutates the bare geometry and holds no reference back to the holder, the section issues the holder resync itself after each geometry edit: <code>UpdateGeometryContent</code> runs <code>UpdateByCylindroid()</code> and then <code>ClearCache()</code>, recomputing the holder topology before regenerating the solid — clearing the cache alone would skip the recompute. The slave column mounts only the selected node's panel, so at most one holder-geometry panel is alive at a time and the shared key never collides.</p>
<p><strong>Resolution.</strong> The section writes the polar resolution straight onto the holder: <code>SetPolarResolution</code> assigns a fresh <a class="xref" href="../../../api/Hi.Geom.Resolution.PolarResolution2d.html">PolarResolution2d</a> built from the two values and calls <code>ClearCache()</code>, so the server regenerates the solid cache at the new tessellation. No topology resync is involved on this path. <code>Get</code> also returns the current pair, which is how the two fields are seeded; a null resolution on the model is reported as 0 mm / 0 deg.</p>
<p>Guards sit on both sides. Every action on the controller answers Not Found for an unknown tool id and Bad Request when the tool's holder is not a <code>CylindroidHolder</code>; <code>SetPolarResolution</code> additionally rejects a linear or angle value that is not greater than zero, and the Resolution section refuses to send a non-positive value at all. Both fields commit on blur or Enter.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue</code> — both sections in one panel, chosen by the last segment of the node's role path: the Cylindroid editor on the indexed key plus the resync on change, and the linear-mm / angle-deg fields with their positive-value guard.</li>
<li><code>wwwroot-src/src/components/geom/CylindroidEditor.vue</code> — the reusable Z-R profile editor the Geometry section wraps, driven by model key.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHolderPanel.vue</code> — the parent Holder node's panel, which hosts this holder's Name, readonly Abstract Note and Note and commits them through <code>setCylindroidHolderName</code> / <code>setCylindroidHolderNote</code>.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — grows the two child sections for a <code>CylindroidHolder</code> and routes both to the <code>HolderSection</code> item type.</li>
<li><code>wwwroot-src/src/api/cylindroidHolder.ts</code> — the typed wrapper over <code>/api/CylindroidHolder</code>: <code>getCylindroidHolder</code>, <code>updateCylindroidHolderGeometry</code>, <code>setCylindroidHolderName</code>, <code>setCylindroidHolderNote</code>, <code>setCylindroidHolderResolution</code>.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — the two section labels, the tessellation hint, the two field labels and the initializing caption.</li>
<li><code>Mech/CylindroidHolderController.cs</code> — <code>GET Get</code> (name / note / abstract note, the polar resolution, and — with a session key — the indexed cylindroid key) plus <code>POST UpdateGeometryContent | SetName | SetNote | SetPolarResolution</code>.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../../widget/polar-resolution-2d-panel.html">Polar Resolution 2D Panel</a> — the resolution editor this panel embeds</li>
<li><a class="xref" href="../../geom/cylindroid-control.html">Cylindroid Control</a> — the shape editor this panel's Geometry surface
embeds, and the shape whose tessellation the Resolution surface governs</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>
@@ -0,0 +1,209 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Freeform Holder Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Freeform Holder Panel | 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-FreeformHolderPanel">
<h1 id="freeform-holder-panel">Freeform Holder Panel</h1>
<p>The key model is <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a>: a holder whose shape comes from a referenced geometry, typically an STL, positioned by two anchor transformers — one to the spindle, one to the cutter.</p>
<p>On the web client the holder occupies four child sections of the Holder node under the selected tool — Geometry, Geom To Spindle, Geom To Cutter and Resolution, the nodes whose role paths end in <code>.../holder/geometry</code>, <code>.../holder/geom-to-spindle</code>, <code>.../holder/geom-to-cutter</code> and <code>.../holder/resolution</code>, reached at <code>/tool-house/:toolId/holder/:subtab</code>. Its Name, readonly Abstract Note and Note are edited one level up, on the <a class="xref" href="holder-panel.html">Holder Panel</a> itself, under the Metadata-on-container convention. Every field ships on both clients; what differs is the surface hosting them — the WPF client gives the same fields a tab strip of its own.</p>
<p>The three shape sections are not holder-specific editors. They are the same generic Geometry and Transformer slots the <a class="xref" href="../../general-setup/fixture.html">Fixture</a> branch of the General Setup page is built from: a kind picker on the section node, and the chosen kind's own editor on the child node below it. So an STL holder is picked as <code>StlFile</code> and its source file set through the shared StlFile editor, a <code>TransformationGeom</code> holder grows Inner Geometry and Inner Transformer nodes, a <code>GeomCombination</code> holder grows one node per item, and each placement grows the chosen transformer kind's editor — Static Translation for the usual <code>(0, 0, h)</code> offset.</p>
<h2 id="layout">Layout</h2>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Geometry Section
<ul>
<li>Geometry Type Selector — None / Box3d / Cylindroid / StlFile / TransformationGeom / GeomCombination</li>
<li>The chosen kind's editor, on the child node the kind grows</li>
</ul>
</li>
<li>Geom To Spindle Section — where the holder sits relative to the spindle
<ul>
<li>Transformer Type Selector — Static Translation / Static Rotation / Static Freeform / Dynamic Translation / Dynamic Rotation / General Transform / No Transform</li>
<li>The chosen kind's editor, on the child node the kind grows</li>
</ul>
</li>
<li>Geom To Cutter Section — where the cutter sits relative to the holder
<ul>
<li>Transformer Type Selector and the chosen kind's editor, as above</li>
</ul>
</li>
<li>Resolution Section
<ul>
<li>Resolution Hint Caption — names the STL tessellation resolution used for display and collision meshing</li>
<li>Linear Resolution (mm) Input Field</li>
<li>Angle Resolution (deg) Input Field</li>
</ul>
</li>
</ul>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>Freeform Holder Panel
<ul>
<li>Head Line
<ul>
<li>Title Label</li>
</ul>
</li>
<li>Tabs
<ul>
<li>Geometry Tab
<ul>
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Panel</a></li>
</ul>
</li>
<li>Anchor Tab
(Apply <a class="xref" href="../../geom/transformer-panel.html">Transformer Manage Panel</a> to set the following tabs)
<ul>
<li>Geom To Spindle Tab</li>
<li>Geom To Cutter Tab</li>
</ul>
</li>
<li>Resolution Tab
Model: <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_PolarResolution2d">PolarResolution2d</a>
<a class="xref" href="../../widget/polar-resolution-2d-panel.html">Polar Resolution 2d</a></li>
<li>Info Tab
<ul>
<li>Name TextField (editable)</li>
<li>AbstractNote TextField (readonly)</li>
<li>Note TextField (editable)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>Remember to call <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_UpdateByGeom">UpdateByGeom()</a> after geometry reference or content changed.</p>
<h2 id="feature">Feature</h2>
<p>The generic editors reach the holder's own members, and that is what makes the split work. When the Holder node's children are built, the page calls <code>FreeformHolderController</code>'s <code>Get</code> with its session key; the server publishes the holder's <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_Geom">Geom</a>, <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_GeomToSpindleTransformer">GeomToSpindleTransformer</a> and <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_GeomToCutterTransformer">GeomToCutterTransformer</a> in the index service under three per-session keys (<code>-HolderGeom</code>, <code>-HolderGeomToSpindle</code>, <code>-HolderGeomToCutter</code>) and hands the keys back. The keys name the very objects the holder holds, so an edit through a kind editor lands on the holder directly. The keys are returned even when a member is empty — nothing is published then, the section's picker reads an empty slot, and picking a kind fills that same key — which is how a freshly switched-to Freeform holder, whose geometry starts empty, gets its first shape.</p>
<p>Picking a kind is a container-aware create, not a bare <code>New</code>. The Geometry picker calls <code>CreateGeometry</code>, which builds the geometry, sets it as the holder's <code>Geom</code> and publishes it under the section's key (None clears the geometry). A placement picker first creates the transformer through the kind's own <code>New</code> endpoint and then attaches it with <code>UpdateGeomToSpindleTransformer</code> or <code>UpdateGeomToCutterTransformer</code>. Without the attach, only the index-service entry would change and the holder would keep pointing at its old transformer.</p>
<p>Because the generic editors hold no reference back to the holder, every edit at or below a section ends in the holder resync the page wires onto the section: a geometry edit calls <code>UpdateGeometryContent</code>, a placement edit re-attaches the transformer under its key. Both run <code>UpdateByGeom()</code> to regenerate the solid, <code>ClearCache()</code>, and <code>AlignAnchorByExposedCutterHeight()</code> to re-place the cutter under the holder — clearing the cache alone would leave the cutter where it was. The page then refreshes the tool list and the canvas.</p>
<p>The Resolution section writes the polar resolution straight onto the holder: <code>SetPolarResolution</code> assigns a fresh <a class="xref" href="../../../api/Hi.Geom.Resolution.PolarResolution2d.html">PolarResolution2d</a> and the holder swaps its solid for one born with the new value, keeping the geometry. <code>Get</code> also returns the current pair, which is how the two fields are seeded.</p>
<p>Guards sit on both sides. Every action on the controller answers Not Found for an unknown tool id and Bad Request when the tool's holder is not a <code>FreeformHolder</code>; <code>SetPolarResolution</code> rejects a linear or angle value that is not greater than zero, and the Resolution section refuses to send one. Fields commit on blur or Enter.</p>
<p>Switching a tool to Freeform is a committing choice. <code>SetHolderType</code> assigns a new <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a> only when the tool does not already carry one, so a holder authored on the WPF client or through HiNcRcl survives a round trip through the web page with its geometry, anchors and resolution intact.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — grows the four child sections for a <code>FreeformHolder</code>: reads <code>Get</code> to publish the three members, binds the Geometry section to the generic <code>Geometry</code> item type and the two placements to the generic <code>Transformer</code> item type (with the create hooks and the resync chain), and routes Resolution to the <code>HolderSection</code> item type.</li>
<li><code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> / <code>TransformerSlotPanel.vue</code> — the kind pickers on the three shape sections; the chosen kind's editor lives on the child node (<code>wwwroot-src/src/components/geom/geometryEditors.ts</code>, <code>wwwroot-src/src/components/topo/transformerEditors.ts</code>).</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue</code> — the Resolution section, dispatching on the holder type to <code>FreeformHolderController</code> for a Freeform holder.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHolderPanel.vue</code> — the parent Holder node's panel, which hosts this holder's Name, readonly Abstract Note and Note and commits them through <code>setFreeformHolderName</code> / <code>setFreeformHolderNote</code>.</li>
<li><code>wwwroot-src/src/api/freeformHolder.ts</code> — the typed wrapper over <code>/api/FreeformHolder</code>: <code>getFreeformHolder</code>, <code>createFreeformHolderGeometry</code>, <code>updateFreeformHolderGeometry</code>, <code>resyncFreeformHolder</code>, <code>updateFreeformHolderGeomToSpindle</code>, <code>updateFreeformHolderGeomToCutter</code>, <code>setFreeformHolderName</code>, <code>setFreeformHolderNote</code>, <code>setFreeformHolderResolution</code>.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — the two placement section labels (<code>toolhouse.node.geomToSpindle</code> / <code>geomToCutter</code>) and the Freeform sections hint; the zh-Hans and zh-Hant files carry the same keys.</li>
<li><code>Mech/FreeformHolderController.cs</code> — <code>GET Get</code> (name / note / abstract note, the polar resolution, and — with a session key — the three member keys) plus <code>POST CreateGeometry | UpdateGeometry | IndexCurrentGeometry | UpdateGeometryContent | UpdateGeomToSpindleTransformer | UpdateGeomToCutterTransformer | SetName | SetNote | SetPolarResolution</code>.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../../widget/polar-resolution-2d-panel.html">Polar Resolution 2D Panel</a> — the resolution editor this panel embeds</li>
<li><a class="xref" href="../../general-setup/fixture.html">Fixture Page</a> — the other user of the generic Geometry and Transformer slots this holder's shape sections are made of</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>
@@ -0,0 +1,191 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Holder Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Holder Panel | 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-HolderPanel">
<h1 id="holder-panel">Holder Panel</h1>
<p>This section describes the user interface and behavior for managing different types of tool holders in the application. Tool holders are crucial components in defining a complete tool assembly.</p>
<div class="NOTE">
<h5>Note</h5>
<p>While tool holders are essential components in real-world machining operations, some users may choose not to define them in simulation environments for convenience, particularly when collision detection is not a primary concern. The system allows for this flexibility, though it's recommended to include holders for accurate representation and comprehensive collision analysis.</p>
</div>
<p>The primary models involved are subclasses of <a class="xref" href="../../../api/Hi.NcMech.Holders.IHolder.html">IHolder</a>. Two common types are:</p>
<ul>
<li><strong><a class="xref" href="cylindroid-holder-panel.html">Cylindroid Holder</a></strong>: Represents holders with a cylindrical geometry. See <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html">CylindroidHolder</a>.</li>
<li><strong><a class="xref" href="freeform-holder-panel.html">Freeform Holder</a></strong>: Represents holders with more complex, freeform geometry, often defined by STL files. See <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a>.</li>
</ul>
<p>Each holder type has its own user interface elements for defining its geometry and properties.</p>
<p>On the web client this panel is the Holder tab of the <a class="xref" href="../index.html">Tool House Page</a>, reached at <code>/tool-house/:toolId/holder</code>. It is the panel of the Control-Tree Holder node under the selected tool — the node whose role path ends in <code>.../holder</code>.</p>
<h2 id="layout">Layout</h2>
<h3 id="web-layout">Web Layout</h3>
<ul>
<li>Holder Node Panel
<ul>
<li>Title Label</li>
<li>Holder Type Selector — None / Cylindroid Holder / Freeform Holder</li>
<li>Holder branch, rendered while the type is Cylindroid or Freeform
<ul>
<li>Name TextField (editable)</li>
<li>Abstract Note TextField (readonly, derived by the model)</li>
<li>Note TextField (editable)</li>
<li>Sections Hint Caption — names the sections below for the current type</li>
</ul>
</li>
<li>No-holder branch — one hint, <code>toolhouse.holder.noHolderHint</code>, inviting the reader to pick Cylindroid Holder or Freeform Holder</li>
</ul>
</li>
</ul>
<p>The three identity fields belong to whichever holder the tool carries. They sit on this panel under the Metadata-on-container convention — a container's own General fields are edited on the container's panel instead of in a General child — and they commit through the per-type holder controller's <code>SetName</code> and <code>SetNote</code> (<code>CylindroidHolderController</code> or <code>FreeformHolderController</code>), not through <code>ToolHouseController</code>. No holder leaves the panel without them.</p>
<p>The type also decides what grows below the node. A Cylindroid holder grows two child sections, Geometry and Resolution — the nodes whose role paths end in <code>.../holder/geometry</code> and <code>.../holder/resolution</code>; see <a class="xref" href="cylindroid-holder-panel.html">Cylindroid Holder Panel</a>. A Freeform holder grows four — Geometry, Geom To Spindle, Geom To Cutter and Resolution; see <a class="xref" href="freeform-holder-panel.html">Freeform Holder Panel</a>. Selecting a section replaces this panel in the slave column with that section's own panel. None grows no children, so the Holder node is a leaf and the hint is the whole surface.</p>
<p>This panel carries no object management of its own. Object management for the tool library sits on the tool-house root node, where the <a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a> is bound to the whole <code>.MachiningToolHouse</code> file rather than to a per-holder file.</p>
<h3 id="wpf-layout">WPF Layout</h3>
<ul>
<li>Holder Panel
<ul>
<li>Head Line
<ul>
<li><a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a>
<ul>
<li>File extension is <code>.Holder</code>, load type <a class="xref" href="../../../api/Hi.NcMech.Holders.IHolder.html">IHolder</a></li>
<li>The pointed Editor Panel is the Holder Sub Management Panel.</li>
</ul>
</li>
<li>Title Label</li>
</ul>
</li>
<li>Holder Management Panel
<ul>
<li>Holder Type Selection Bar — None / Cylindroid / Freeform</li>
<li>Holder Sub Management Panel
A ContentPresenter whose content varies by the Holder Type: the <a class="xref" href="cylindroid-holder-panel.html">Cylindroid Holder Panel</a>, the <a class="xref" href="freeform-holder-panel.html">Freeform Holder Panel</a>, or nothing for None.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="feature">Feature</h2>
<p>Committing a type on the web is one server call plus a cache clear. <code>SetHolderType</code> maps the selector value onto the holder classes: none clears the tool's holder, while cylindroid and freeform each assign a new holder <strong>only when the tool does not already carry one of that class</strong> — so re-picking the type a tool already has keeps the holder it has, and the edits on it, rather than replacing it. When the caller passes its session key the server re-indexes the resulting holder under that session's holder key, and removes that entry for None, so the session key keeps pointing at the tool's current holder. The response carries the holder's class name and its abstract note.</p>
<p>The panel then calls <code>ClearToolCache</code>, which clears the tool's cached solids and, when the holder implements <a class="xref" href="../../../api/Hi.Common.IClearCache.html">IClearCache</a>, the holder's own cache as well, so the tool canvas redraws against the new holder. Finally it emits a structure change for its own node, which is how the Geometry and Resolution sections appear or disappear with the type.</p>
<p><code>GetHolder</code> reports the same pair — class name and abstract note — and is what the panel reads on mount to seed the selector; an unknown tool id answers Not Found. The panel then reads the per-type controller's <code>Get</code> (<code>CylindroidHolderController</code> or <code>FreeformHolderController</code>) to fill the three identity fields; for a Freeform holder that same call also publishes the holder's geometry and two placements under the session's keys for the sections below.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHolderPanel.vue</code> — the Holder node's panel: the None / Cylindroid / Freeform selector, the holder's Name / readonly Abstract Note / Note (committed through the per-type controller) and the no-holder hint. Commits a type change through <code>setHolderType</code> followed by <code>clearToolCache</code>.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — registers this panel as the <code>ToolHolder</code> item type; its holder child builder grows Geometry and Resolution for a <code>CylindroidHolder</code>, Geometry / Geom To Spindle / Geom To Cutter / Resolution for a <code>FreeformHolder</code>, and nothing for None.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue</code> — the panel behind the Cylindroid holder's two sections and both holders' Resolution section, dispatching on the last segment of the node's role path and on the holder type.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHouseRootPanel.vue</code> — the tool-house root panel, which carries the Object Management Menu Button for the <code>.MachiningToolHouse</code> file.</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — <code>getHolder</code>, <code>setHolderType</code> and <code>clearToolCache</code>, plus the <code>HolderType</code> union (<code>None</code> / <code>CylindroidHolder</code> / <code>FreeformHolder</code>) the selector's three values map onto.</li>
<li><code>wwwroot-src/src/api/cylindroidHolder.ts</code> / <code>wwwroot-src/src/api/freeformHolder.ts</code> — <code>get…Holder</code>, <code>set…HolderName</code> and <code>set…HolderNote</code> for each holder type, behind the three identity fields.</li>
<li><code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — the <code>toolhouse.holder.*</code> strings this panel renders: holderType, abstractNote, sectionsHint, freeformSectionsHint, noHolderHint, cylindroidHolder, freeformHolder.</li>
<li><code>Mech/ToolHouseController.cs</code> — <code>POST SetHolderType</code>, <code>GET GetHolder</code> and <code>POST ClearToolCache</code>, the three endpoints behind the selector. Per-holder-type editing lives in the dedicated holder controllers.</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>
@@ -0,0 +1,131 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Holder Tab | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Holder Tab | 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-Holder">
<h1 id="holder-tab">Holder Tab</h1>
<p>The Holder tab of the Tool House page, reached as <code>/tool-house/:toolId/holder</code> and, for its inner
editors, <code>/tool-house/:toolId/holder/:subtab</code>. The tab's own panel chooses the holder type; the type
chosen decides which editor grows below it, and each type carries its own geometry and resolution.</p>
<p>Ordered with the tab's own panel first, then one page per holder type.</p>
<h2 id="pages">Pages</h2>
<ul>
<li><a href="holder-panel.html">Holder Panel</a> — The tab itself: the holder type selector and the fields common to every holder</li>
<li><a href="cylindroid-holder-panel.html">Cylindroid Holder Panel</a> — The revolved Z-R profile holder, its geometry and its polar resolution</li>
<li><a href="freeform-holder-panel.html">Freeform Holder Panel</a> — The freeform holder, and where its geometry is edited</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../index.html">Tool House Page</a> — the page these tabs belong to</li>
<li><a href="../cutter/index.html">Cutter Tab</a> — the sibling tab, and the other half of a tool</li>
<li><a href="../stick-tool-panel.html">Stick Tool Panel</a> — the tool node whose tab cascade this tab belongs to</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>
@@ -0,0 +1,31 @@
<div id="sidetoggle">
<div>
<div class="sidefilter">
<form class="toc-filter">
<span class="glyphicon glyphicon-filter filter-icon"></span>
<span class="glyphicon glyphicon-remove clear-icon" id="toc_filter_clear"></span>
<input type="text" id="toc_filter_input" placeholder="Filter by title" onkeypress="if(event.keyCode==13) {return false;}">
</form>
</div>
<div class="sidetoc">
<div class="toc" id="toc">
<ul class="nav level1">
<li>
<a href="index.html" name="" title="Overview">Overview</a>
</li>
<li>
<a href="holder-panel.html" name="" title="Holder Panel">Holder Panel</a>
</li>
<li>
<a href="cylindroid-holder-panel.html" name="" title="Cylindroid Holder Panel">Cylindroid Holder Panel</a>
</li>
<li>
<a href="freeform-holder-panel.html" name="" title="Freeform Holder Panel">Freeform Holder Panel</a>
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -0,0 +1,2 @@
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Holder Panel","href":"holder-panel.html","topicHref":"holder-panel.html"},{"name":"Cylindroid Holder Panel","href":"cylindroid-holder-panel.html","topicHref":"cylindroid-holder-panel.html"},{"name":"Freeform Holder Panel","href":"freeform-holder-panel.html","topicHref":"freeform-holder-panel.html"}]}
@@ -0,0 +1,248 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Tool House Page | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Tool House Page | 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-ToolHousePage">
<h1 id="tool-house-page">Tool House Page</h1>
<p>The Tool House is a page of its own at <code>/tool-house/:toolId?/:tab?/:subtab?</code>, reached from the menu bar's <code>Page ▾</code> dropdown. In the WPF client it is a sub-window opened from the <a class="xref" href="../shell/main-panel.html">Main Panel</a>.</p>
<p>The key model is MachiningToolHouse.
The model <code>UserService</code> is per-client. On the web it is the server-side <code>Environments/UserService.cs</code>, which <code>Mech/ToolHouseDisplayController.cs</code> reads <code>EnablePhysics</code> from; the WPF client resolves its own <code>UserService</code> from the application's service provider.</p>
<h2 id="layout">Layout</h2>
<p>Three columns, left to right, in two nested resizable splitters — the tool house and its tool list, the selected tool's editor tabs, and the tool canvas. Creating a tool opens no window of its own: <strong>New Tool</strong> adds a default tool and the user sets it up in the editor tabs.</p>
<ul>
<li>Tool House Page
<ul>
<li>Tool List Column
<ul>
<li>Tool House Root Panel
<ul>
<li><a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a>
<ul>
<li>file extension is <code>.MachiningToolHouse</code>, load type <code>Hi.Machining.MachiningToolHouse, HiMech</code></li>
<li>The managed object is the whole tool house, not one tool</li>
</ul>
</li>
<li>New Tool Button (disabled until the project has a tool house)</li>
<li>Ready / No-Project Badge</li>
<li>Tool-count caption with the pick hint — replaced, while the project has no tool house, by an empty-state block naming New Tool and the Object Management button's <code>.MachiningToolHouse</code> extension</li>
</ul>
</li>
<li>Tool List
<ul>
<li>one router-link row per tool: the Tool ID badge, then the tool's note — or the auto abstract note as an italic caption when the note is empty</li>
</ul>
</li>
</ul>
</li>
<li>Selected Tool Editor Column
<ul>
<li><a class="xref" href="stick-tool-panel.html">Stick Tool Panel</a> — the tool's five tabs: General, Cutter, Holder, Clamping, Int. Holder</li>
</ul>
</li>
<li>Viewer Column
<ul>
<li>Viewer ToolBar
<ul>
<li><a class="xref" href="../widget/renderingcanvas-tool-bar.html">RenderingCanvas Tool Bar</a></li>
<li>Display Options Menu Dropdown — three flat groups, no submenus
<ul>
<li>Head Label: Cutter
<ul>
<li>Show Cutter CheckBox</li>
</ul>
</li>
<li>Head Label: Holder
<ul>
<li>Show Holder CheckBox</li>
<li>Show Geometry Anchor CheckBox</li>
<li>Show Spindle Buckle CheckBox</li>
<li>Show Cutter Buckle CheckBox</li>
</ul>
</li>
<li>Head Label: Holder Rendering Mode
<ul>
<li>Solid / Edge / Hide Radio Buttons</li>
</ul>
</li>
</ul>
</li>
<li>Selected-Tool Badge</li>
<li>Rendering-Connection Badge</li>
</ul>
</li>
<li>RenderingCanvas
<ul>
<li>The <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_Displayee">Displayee</a> is <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingToolEditorDisplayee.html">MillingToolEditorDisplayee</a>.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The three anchor-and-buckle flags of <a class="xref" href="../../api/Hi.NcMech.Holders.HolderEditorDisplayee.html">HolderEditorDisplayee</a> and the Holder Rendering Mode radios are all disabled while Show Holder is off, so a child option is reachable only when its parent is on. The menu is one flat list of labelled groups rather than nested submenus, which is what keeps it one click deep.</p>
<p>The cutter's shape mode is not a control here. The server picks it when the canvas binds: <code>InitializeDisplay</code> sets <a class="xref" href="../../api/Hi.Milling.Cutters.MillingCutterEditorDisplayee.html#Hi_Milling_Cutters_MillingCutterEditorDisplayee_ShapeMode">ShapeMode</a> to Solid Bounding Shape whenever <code>UserService.EnablePhysics</code> is false, and the web Display Options dropdown offers no switch for it. The WPF page is the client whose Editor Displayee Options menu carries the Solid Bounding Shape / Detail Physics Shape radio submenu.</p>
<p>The left column is the other place the two clients differ. The WPF Tool House page lists its tools in a DataGrid with a checkbox column, an editable Tool ID column and a read-only Note column, and puts a Batch Actions menu above it — Select All, De-Select All, then Batch Duplicate and Batch Delete — with Duplicate and Delete also on the grid's context menu. On the web page Tool ID and Note are edited on the selected tool's General tab, where Duplicate and Delete are per-tool icon buttons, so the list itself stays a plain navigation column of router links.</p>
<p>The Tool ID can not be repeated. Create Tool takes the largest existing ID plus 1 (or 1 in an empty house), Duplicate Tool inserts the clone at the first free ID past both the source and the largest existing ID, and renaming a tool onto an ID the house already holds is refused as a conflict.</p>
<p>When the canvas first binds, <code>InitializeDisplay</code> attaches the <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingToolEditorDisplayee.html">MillingToolEditorDisplayee</a> and snaps the camera to the isometric view. Each later tool selection re-points that displayee's <code>MillingToolGetter</code> at the chosen tool and calls the renderingCanvas.<a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_SetViewToHomeView">SetViewToHomeView()</a>.</p>
<h3 id="duplication-button">Duplication Button</h3>
<p>Use <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingTool.html#Hi_Milling_MillingTools_MillingTool_Duplicate_System_Object___">Duplicate(params object[])</a> to duplicate the tool; the clone joins the house under a fresh ID.</p>
<h3 id="tool-row-note">Tool Row Note</h3>
<p>A tool's row shows its note when the note exists and is not an empty string; otherwise it shows the <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingTool.html#Hi_Milling_MillingTools_MillingTool_AbstractNote">AbstractNote</a>, set in an italic caption so the auto-derived text reads as a fallback.</p>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA). The page is built on the shared Control Tree: the tool nodes on the left, the selected node's tab cascade in the middle, the canvas on the right.</p>
<ul>
<li><code>wwwroot-src/src/router/routes.ts</code> — declares the route itself: path <code>tool-house/:toolId(\d+)?/:tab?/:subtab?</code>, name <code>tool-house</code>.</li>
<li><code>wwwroot-src/src/components/AppMenuBar.vue</code> — the <code>Page ▾</code> dropdown; its first item targets the <code>tool-house</code> route.</li>
<li><code>wwwroot-src/src/router/treeRoutes.ts</code> — declares <code>TOOL_TABS</code>, <code>CUTTER_SECTIONS</code> and <code>HOLDER_SECTIONS</code>, and <code>routeForTreeId</code> / <code>migrateLegacyTreeId</code>, which map a Control-Tree id onto this page's tab params.</li>
<li><code>wwwroot-src/src/composables/useRouteTabs.ts</code> — the <code>:tab?</code> / <code>:subtab?</code> URL sync, defaulting to <code>general</code>, and to <code>profile</code> under Cutter / <code>geometry</code> under Holder.</li>
<li><code>wwwroot-src/src/composables/useToolHouse.ts</code> — the module-singleton state every tool-house panel and the canvas share: the tool list, the active tool, the tool-house key and the rendering connection id.</li>
<li><code>wwwroot-src/src/pages/ToolHousePage.vue</code> — routed page: <code>ToolHouseRootPanel</code> + tool list on the left, the tool's own five-tab strip in the middle, <code>ToolHouseSetupPanel</code> on the right, in two nested resizable <code>&lt;q-splitter&gt;</code> panes. Cutter and Holder grow a second, URL-synced sub-tab strip from the tab node's children, and <code>NodeTabCascade.vue</code> hosts the active tab's panel and the levels nested below it.</li>
<li><code>wwwroot-src/src/components/controlTree/NodeTabCascade.vue</code> — the nested-level host the page mounts inside the active tab.</li>
<li><code>wwwroot-src/src/components/toolhouse/ToolHouseSetupPanel.vue</code> — the canvas column: one RenderingCanvas bound server-side to <code>MillingToolEditorDisplayee</code>, following the page's selected tool, with the Display Options dropdown (Show Cutter / Show Holder + the 3 anchor-and-buckle flags + the Holder Rendering Mode radios).</li>
<li><code>wwwroot-src/src/components/widgets/DisplayOptionsMenu.vue</code> — the generic groups/items dropdown that panel feeds, which is why the menu is flat groups rather than nested submenus.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — the tool house's ItemType registry: one tool node per tool, and each tool node's <code>…/cutter</code>, <code>…/holder</code>, <code>…/clamping</code>, <code>…/intelligent</code> children.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHouseRootPanel.vue</code> — the tool-house root node: Object Management over the <code>MachiningToolHouse</code> + New Tool. The button's own entries are <strong>Load</strong>, <strong>Save As</strong>, <strong>Copy</strong>, <strong>Paste</strong> and <strong>XML</strong>; the <strong>Load Resource</strong> entry is conditional on a <code>resourceDirectory</code> prop this panel does not pass, so it is absent here.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolNodePanel.vue</code> — one tool's General tab: Tool ID / Note / auto Abstract Note + Duplicate / Delete. Mounting it points the tool canvas at that tool.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolCutterPanel.vue</code> — the Cutter stem: cutter type selector plus the MillingCutter identity fields (Shank Mass / Hone Radius / Relief Angle).</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterSectionPanel.vue</code> — the cutter's inner tabs, keyed off the node's role path (<code>material</code> / <code>profile</code> / <code>upper-beam</code> / <code>opt</code>). Flute Profile is edited inline; the others dispatch to <code>wwwroot-src/src/components/toolhouse/MaterialDiv.vue</code> (which grows <code>CoatingLayersDiv.vue</code>), <code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> and <code>wwwroot-src/src/components/toolhouse/MillingCutterOptLimitDiv.vue</code>.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterContoursPanel.vue</code> — the Flute Contours stem: the fluting <strong>type</strong> selector only. The selected fluting's editor grows below it.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/FlutingPanel.vue</code> — the concrete fluting node and its fluting-level fields; uniform fluting grows one Baseline Contour, free fluting one tab per flute.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/FluteContourPanel.vue</code> — one flute contour node (<code>baseline</code>, or <code>flute-&lt;i&gt;</code> for a free fluting): hosts Setup Angle, with Side Contour and Bottom Contour as sub-tabs. <code>fluteContourNode.ts</code> carries the shared re-commit.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/FluteSideContourPanel.vue</code> / <code>FluteBottomContourPanel.vue</code> — kind selector + editor, dispatching to <code>wwwroot-src/src/components/toolhouse/fluting/ConstHelixSideContourDiv.vue</code>, <code>FreeformSideContourDiv.vue</code>, <code>SlideBottomContourDiv.vue</code> and <code>FreeformBottomContourDiv.vue</code>; the two freeform editors share <code>SpanContourPosListDiv.vue</code> for the per-flute position list.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHolderPanel.vue</code> — the Holder stem: holder type selector plus the holder's Name / Note / auto Abstract Note, committed through the per-type holder controller.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue</code> — the Cylindroid holder's Geometry (the Z-R profile, via <code>wwwroot-src/src/components/geom/CylindroidEditor.vue</code>) and both holders' Resolution tabs; resyncs the Cylindroid holder (<code>UpdateByCylindroid()</code>) after each geometry edit. A Freeform holder's Geometry / Geom To Spindle / Geom To Cutter tabs are the generic <code>Geometry</code> / <code>Transformer</code> Control-Tree slots (<code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> / <code>TransformerSlotPanel.vue</code>), wired by <code>toolHouseItemTypes.ts</code> to <code>FreeformHolderController</code>'s keys and resync.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolClampingPanel.vue</code> — the Clamping tab: <code>ExposedCutterHeight</code> = <code>PreservedDistance</code> + <code>FluteHeight</code>; changing either field updates the other on the server.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolIntelligentPanel.vue</code> — the Intelligent Holder tab; a thin wrapper over <code>wwwroot-src/src/components/toolhouse/IntelligentHolderDiv.vue</code> (Observation Location: <code>ObservationAnchorReference</code> dropdown + relative Z + ring radius).</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — typed wrapper over three server modules: <code>ToolHouseController</code> (<code>/api/ToolHouse</code>), <code>CutterController</code> (<code>/api/Cutter</code>) and <code>ToolHouseDisplayController</code> (<code>/api/mech/tool-house-display</code>).</li>
<li><code>wwwroot-src/src/api/cylindroidHolder.ts</code> / <code>wwwroot-src/src/api/freeformHolder.ts</code> — typed wrappers over <code>CylindroidHolderController</code> / <code>FreeformHolderController</code>.</li>
<li><code>Mech/ToolHouseController.cs</code> — the tool-house collection and the tool-level fields. REST endpoints: <code>GET /</code>, <code>GET /{id}</code>, <code>GET /GetHolder</code>, <code>GET/PUT /{id}/observation</code>, <code>PUT /{id}/note | exposed-height | preserved-distance</code>, <code>POST /Initialize | Update | SelectTool | CreateTool | DuplicateTool | RenameTool | SetHolderType | ClearToolCache</code>, <code>DELETE /DeleteTool</code>.</li>
<li><code>Mech/CutterController.cs</code> — cutter editing, the <code>/api/Cutter</code> sibling of <code>ToolHouseController</code>. REST endpoints at <code>/api/Cutter/*</code>: <code>POST EnsureCutter | ClearCutter</code>, <code>PUT /{id}/shaper-profile | fluting | general | opt-limit</code>, <code>FreeFluting</code> child CRUD at <code>/{id}/fluting/contours[/{index}]</code>, <code>GET/POST /{id}/upper-beam[/create | /resync]</code>, and the material endpoints <code>/{id}/flute-material/*</code>, <code>/{id}/shank-material/*</code>, <code>/{id}/coating-layers/*</code>.</li>
<li><code>Mech/ToolHouseDisplayController.cs</code> — REST endpoints at <code>/api/mech/tool-house-display/*</code> for display options (initialize, select-tool, show-cutter / show-holder / show-geom-anchor / show-spindle-buckle / show-cutter-buckle, holder-rendering-mode, cutter-shape-mode, clear-cache). <code>initialize</code> attaches the <code>MillingToolEditorDisplayee</code> and snaps to the isometric view; <code>select-tool</code> re-points the <code>MillingToolGetter</code> and snaps to the home view. It also reports <code>enablePhysics</code> from <code>UserService</code>.</li>
<li><code>Mech/CylindroidHolderController.cs</code> — holder-aware layer over a tool's <code>CylindroidHolder</code>. REST endpoints at <code>/api/CylindroidHolder/*</code>: <code>GET Get</code> (returns name / note / abstract note / resolution + indexes the holder's <code>Cylindroid</code>), <code>POST UpdateGeometryContent | SetName | SetNote | SetPolarResolution</code>. <code>UpdateGeometryContent</code> is the post-edit resync (<code>UpdateByCylindroid()</code> + <code>ClearCache()</code>) that the generic <code>CylindroidController</code> cannot perform.</li>
<li><code>Mech/FreeformHolderController.cs</code> — the Freeform counterpart. REST endpoints at <code>/api/FreeformHolder/*</code>: <code>GET Get</code> (name / note / abstract note / resolution + indexes the holder's geometry and two placement transformers under per-session keys), <code>POST CreateGeometry | UpdateGeometry | IndexCurrentGeometry | UpdateGeometryContent | UpdateGeomToSpindleTransformer | UpdateGeomToCutterTransformer | SetName | SetNote | SetPolarResolution</code>. Every shape edit ends in <code>UpdateByGeom()</code> + <code>ClearCache()</code> + <code>AlignAnchorByExposedCutterHeight()</code>, the resync the generic geometry and transformer controllers cannot perform.</li>
<li><code>Environments/UserService.cs</code> — the web client's own per-user service, living on the server; <code>ToolHouseDisplayController</code> reads <code>EnablePhysics</code> from it.</li>
</ul>
<div class="NOTE">
<h5>Note</h5>
<p>The fluting type is named loosely on the wire, and every spelling resolves. <code>PUT /{id}/fluting</code> accepts <code>UniformFluting</code> / <code>uniform</code> and <code>FreeFluting</code> / <code>free</code>, and equally <code>UniformContourTray</code> / <code>FreeContourTray</code>. A Control-Tree id whose cutter branch reads <code>…/contours/tray…</code> resolves to the <code>…/contours/fluting…</code> node.</p>
</div>
<p>One editor lives on the WPF client only, and the app says so where the type is chosen: the <strong>FreeformRemover</strong> cutter. Selecting that type on the web page keeps the existing model intact and shows a note pointing at the WPF client or HiNcRcl.</p>
<p>Three smaller surfaces are likewise the WPF client's: the InsertCutter and FluteInnerBeam physics groups, and the <code>CustomSpinningProfile</code> shaper-profile type — the web profile tab offers the five APT types (General / Ball / Column / Cone / Taper).</p>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="cutter/index.html">Cutter Tab</a> — the cutter half of a tool, and the editors each cutter type grows</li>
<li><a href="holder/index.html">Holder Tab</a> — the holder half, and the editors each holder type grows</li>
<li><a href="stick-tool-panel.html">Stick Tool Panel</a> — the selected tool’s tab cascade, which those two tabs belong to</li>
<li><a class="xref" href="../general-setup/index.html">General Setup Page</a> — the equipment these tools are mounted into</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>
@@ -0,0 +1,249 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Stick Tool Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Stick Tool Panel | 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-StickToolPanel">
<h1 id="stick-tool-panel">Stick Tool Panel</h1>
<p>The term stick is for not only milling, but other remover like electric discharge machining tool.</p>
<p>On the shipped web client the Stick Tool Panel is the <code>toolhouse/tool-&lt;n&gt;</code> node of the
<a class="xref" href="index.html">Tool House Page</a>: picking a tool in that page's left list mounts it, and
its editor is the tab strip filling the page's middle column.</p>
<p>The key model is <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingTool.html">MillingTool</a>.
Other model: <code>UserService</code> — the WPF client reads its <code>EnablePhysics</code> to decide whether its
Intelligent Holder tab is shown.</p>
<h2 id="layout">Layout</h2>
<ul>
<li>Tool Node (<code>toolhouse/tool-&lt;n&gt;</code>)
<ul>
<li>General Tab
<ul>
<li>Tool ID TextField — the T-number; committing it renames the tool</li>
<li>Note TextField (editable)</li>
<li>Abstract Note (read-only, auto-derived, with a one-click copy button)</li>
<li>Duplicate Button and Delete Button (icon buttons on the tab's title bar)</li>
</ul>
</li>
<li>Cutter Tab
<ul>
<li><a class="xref" href="cutter/cutter-panel.html">Cutter Panel</a></li>
</ul>
</li>
<li>Holder Tab
<ul>
<li><a class="xref" href="holder/holder-panel.html">Holder Panel</a></li>
</ul>
</li>
<li>Clamping Tab
<ul>
<li>Exposed-Cutter-Height numeric field</li>
<li>Preserved-Distance-Between-Flute-and-Spindle-Nose numeric field</li>
</ul>
</li>
<li>Int. Holder Tab
<ul>
<li>Observation Location
<ul>
<li>Reference Anchor Dropdown (<code>ObservationAnchorReference</code>) — its options are the <code>MillingToolAnchorReference</code> names the server sends with the observation: None, Tool Tip, Holder Anchor, Spindle Buckle Anchor</li>
<li>Relative-Z-From-Reference numeric field (<code>RelativeHeightFromObservationAnchor_mm</code>)</li>
<li>Observation-Ring-Radius numeric field (<code>ObservationRingRadius_mm</code>)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>All five tabs ship unconditionally on the web page: the Int. Holder tab is one of the five
<code>TOOL_TABS</code>, and the tool node always grows its <code>…/intelligent</code> child. The WPF Stick Tool Panel is
the client that hides its Intelligent Holder tab when <code>UserService.EnablePhysics</code> is false, from
<code>UpdateIntelligentHolderTabVisibility</code> in <code>Mech/ToolHouse/StickToolPanel.xaml.cs</code>.</p>
<p>Object Management on the web page is house-level rather than per-tool: the
<a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a> sits on the Tool House root
panel with file extension <code>.MachiningToolHouse</code> (load type <code>Hi.Machining.MachiningToolHouse, HiMech</code>)
and covers the whole house, while the tool node offers Duplicate and Delete for the single tool. The
WPF Stick Tool Panel is the client that carries a per-tool Object Management Menu Button on its head
line, with file extension <code>.MillingTool</code> and the Stick Tool Management Panel as its pointed editor
panel. That client also gives the identity fields a tab of their own — <strong>Info</strong>, a read-only Abstract
Note TextBox over an editable Note TextBox; on the web page those two fields are the General tab,
alongside Tool ID and the Duplicate / Delete buttons.</p>
<h2 id="tabs-and-the-url">Tabs and the URL</h2>
<p>The tabs are <code>TOOL_TABS</code> — <strong>General</strong>, <strong>Cutter</strong>, <strong>Holder</strong>, <strong>Clamping</strong>, <strong>Int. Holder</strong> —
declared in <code>wwwroot-src/src/router/treeRoutes.ts</code>, and those same five names are the <code>:tab?</code> segment
of the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. General is the tool node's own panel; the
other four are the tool node's children (<code>…/cutter</code>, <code>…/holder</code>, <code>…/clamping</code>, <code>…/intelligent</code>),
registered in <code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code>.</p>
<p>Cutter and Holder are type-selector stems, so each grows a second, URL-synced sub-tab strip — the
<code>:subtab?</code> segment, from <code>CUTTER_SECTIONS</code> (Material / Flute Profile / Flute Contours / Upper Beam /
Optimization — Material only while the shell's <strong>Show Physics Options</strong> preference is on) and
<code>HOLDER_SECTIONS</code> (Geometry / Resolution). The levels below that — Flute Contours
to fluting to flutes to side and bottom contour — nest inside
<code>wwwroot-src/src/components/controlTree/NodeTabCascade.vue</code>, which the page mounts inside the active
tab. <code>wwwroot-src/src/composables/useRouteTabs.ts</code> keeps both segments in the URL, defaulting to
<code>general</code>, and to <code>profile</code> under Cutter / <code>geometry</code> under Holder.</p>
<p>Selecting another tool keeps the tab segments: only the tool part of the URL moves, so the reader
stays on the tab they were reading. A Control-Tree id addressing any of these levels is translated
into the page's route params by <code>routeForTreeId</code>, and an id deeper than the URL carries lands on the
nearest tab.</p>
<div class="NOTE">
<h5>Note</h5>
<p>The Exposed-Cutter-Height and Preserved-Distance-Between-Flute-and-Spindle-Nose are directly
related: <code>ExposedCutterHeight</code> = <code>PreservedDistance</code> + <code>FluteHeight</code>, so each value changes when
the other is changed. Editing Preserved Distance commits
<code>PUT /api/ToolHouse/{id}/preserved-distance</code>, whose response carries the recomputed pair and fills
both fields; editing Exposed Height commits <code>PUT /api/ToolHouse/{id}/exposed-height</code>, which
answers without a body, so the panel re-reads the tool to pick up the new preserved distance.</p>
</div>
<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>
<p>HiNC-2025-webservice (Quasar CLI SPA). The tool node is a set of tabs on the Tool House page rather
than a panel of its own:</p>
<ul>
<li><code>wwwroot-src/src/router/treeRoutes.ts</code> — declares <code>TOOL_TABS</code> (general / cutter / holder /
clamping / intelligent) with <code>CUTTER_SECTIONS</code> and <code>HOLDER_SECTIONS</code>, and <code>routeForTreeId</code>, which
turns a <code>toolhouse/tool-&lt;n&gt;/&lt;tab&gt;/&lt;subtab&gt;</code> Control-Tree id into the <code>/tool-house</code> route params.</li>
<li><code>wwwroot-src/src/pages/ToolHousePage.vue</code> — renders the five-tab strip, mounts only the active
tab's panel, and keeps the tab segments when the selected tool changes.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — the Control-Tree ItemType
registry: <code>buildToolChildren</code> emits the tool node's <code>…/cutter</code>, <code>…/holder</code>, <code>…/clamping</code> and
<code>…/intelligent</code> children, General being the tool node's own panel.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolNodePanel.vue</code> — the General tab: Tool ID /
Note / read-only auto Abstract Note with copy, plus Duplicate and Delete. Mounting it points the
tool canvas at that tool.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolCutterPanel.vue</code> — the Cutter tab's type
selector (Milling Cutter / Freeform Remover / None) plus the MillingCutter identity fields.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolHolderPanel.vue</code> — the Holder tab's type
selector (None / Cylindroid / Freeform) plus the Cylindroid holder's Name / Note / auto Abstract
Note.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolClampingPanel.vue</code> — the Clamping tab and
its two coupled fields.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/ToolIntelligentPanel.vue</code> — the Int. Holder tab;
a thin wrapper over <code>wwwroot-src/src/components/toolhouse/IntelligentHolderDiv.vue</code>, which holds
the Observation Location controls and reads no physics flag.</li>
<li><code>wwwroot-src/src/components/controlTree/NodeTabCascade.vue</code> — hosts the active tab's panel and the
levels nested below it.</li>
<li><code>wwwroot-src/src/composables/useRouteTabs.ts</code> — syncs the <code>:tab?</code> / <code>:subtab?</code> params with the URL.</li>
<li><code>wwwroot-src/src/composables/useToolHouse.ts</code> — the module-singleton state every tool-house panel
is a thin view over: the tool list, the active tool, and the rendering connection id.</li>
<li><code>Mech/ToolHouseController.cs</code> — <code>[Route(&quot;api/[controller]&quot;)]</code>, so <code>/api/ToolHouse</code>: the tool-level
fields the tool node edits — <code>PUT /{id}/note | exposed-height | preserved-distance</code>,
<code>GET/PUT /{id}/observation</code>, <code>POST DuplicateTool | RenameTool | SetHolderType</code>,
<code>DELETE DeleteTool</code>.</li>
<li><code>Mech/CutterController.cs</code> (<code>/api/Cutter</code>) and <code>Mech/CylindroidHolderController.cs</code>
(<code>/api/CylindroidHolder</code>) — the server surface behind the Cutter and Holder tabs.</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — the typed client for those endpoints.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="index.html">Tool House Page</a> — the page this tool node sits in, and where the tool list and the route live</li>
<li><a href="cutter/index.html">Cutter Tab</a> — the cutter half of the tab cascade</li>
<li><a href="holder/index.html">Holder Tab</a> — the holder half</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>
@@ -0,0 +1,31 @@
<div id="sidetoggle">
<div>
<div class="sidefilter">
<form class="toc-filter">
<span class="glyphicon glyphicon-filter filter-icon"></span>
<span class="glyphicon glyphicon-remove clear-icon" id="toc_filter_clear"></span>
<input type="text" id="toc_filter_input" placeholder="Filter by title" onkeypress="if(event.keyCode==13) {return false;}">
</form>
</div>
<div class="sidetoc">
<div class="toc" id="toc">
<ul class="nav level1">
<li>
<a href="index.html" name="" title="Overview">Overview</a>
</li>
<li>
<a href="stick-tool-panel.html" name="" title="Stick Tool Panel">Stick Tool Panel</a>
</li>
<li>
<a href="cutter/index.html" name="cutter/toc.html" title="Cutter Tab">Cutter Tab</a>
</li>
<li>
<a href="holder/index.html" name="holder/toc.html" title="Holder Tab">Holder Tab</a>
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -0,0 +1,2 @@
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Stick Tool Panel","href":"stick-tool-panel.html","topicHref":"stick-tool-panel.html"},{"name":"Cutter Tab","href":"cutter/index.html","tocHref":"cutter/toc.html","topicHref":"cutter/index.html","homepage":"cutter/index.html"},{"name":"Holder Tab","href":"holder/index.html","tocHref":"holder/toc.html","topicHref":"holder/index.html","homepage":"holder/index.html"}]}