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,184 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Box3d Control | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Box3d Control | 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-Box3dControl">
<h1 id="box3d-control">Box3d Control</h1>
<p>The Box3d editor edits an axis-aligned <a class="xref" href="../../api/Hi.Geom.Box3d.html">Box3d</a> through four vector rows — Min, Max,
Dimension and Center — of which an <strong>Edit Mode</strong> selector decides which two are writable. It is
reached wherever a Geometry slot admits the <code>Box3d</code> kind: a Control-Tree kind node under a Geometry
slot, or the geometry switchboard embedded inline.</p>
<h2 id="layout">Layout</h2>
<ul>
<li><strong>Edit Mode</strong> — a selector over three modes. Its internal values are <code>MinMax</code>, <code>MinDimension</code> and
<code>CenterDimension</code>; the web labels them &ldquo;Min / Max&rdquo;, &ldquo;Min + Dimension&rdquo; and &ldquo;Center + Dimension&rdquo;,
the desktop client &ldquo;Min and Max&rdquo;, &ldquo;Min and Dimension&rdquo; and &ldquo;Center and Dimension&rdquo;.</li>
<li><strong>Min</strong>, <strong>Max</strong>, <strong>Dimension</strong>, <strong>Center</strong> — four vector rows, one X / Y / Z input each. The web
captions Dimension &ldquo;Dimension (Max − Min)&rdquo; and Center &quot;Center ((Max + Min) / 2)&quot;; the Min and Max
captions come from the shared label set rather than the geometry one.</li>
</ul>
<p>The mode rules each row read-only or editable rather than showing a different set of rows: Min is
read-only in Center + Dimension, Max in anything but Min / Max, Dimension in Min / Max, and Center
in anything but Center + Dimension.</p>
<h2 id="key-model">Key Model</h2>
<p>Only <a class="xref" href="../../api/Hi.Geom.Box3d.html#Hi_Geom_Box3d_Min">Min</a> and <a class="xref" href="../../api/Hi.Geom.Box3d.html#Hi_Geom_Box3d_Max">Max</a> are settable on the type;
<a class="xref" href="../../api/Hi.Geom.Box3d.html#Hi_Geom_Box3d_Dim">Dim</a> and <a class="xref" href="../../api/Hi.Geom.Box3d.html#Hi_Geom_Box3d_Center">Center</a> are derived and get-only. That is why the
other two modes are arithmetic over the same two stored corners rather than a different storage
shape — and on the web that arithmetic happens in the browser, which then posts the resulting Min
and Max.</p>
<h2 id="behavior">Behavior</h2>
<ul>
<li><strong>A row commits on blur or Enter, not per keystroke.</strong> The vector widget emits only from its blur
handlers, suppresses the emit when the parsed value is unchanged, and reverts an unparseable entry
to its previous value.</li>
<li><strong>The web editor has no read-only variant.</strong> The desktop control additionally carries an
<code>IsInfoMode</code> property that a host sets to turn the whole control into a display: every field goes
read-only and the Edit Mode selector is hidden outright. Two hosts use it, the STL file control and
the geometry combination control. The web equivalent is not this editor — the STL file editor draws
its own read-only bounding-box rows.</li>
<li><strong>Four endpoints ship without a caller.</strong> The controller exposes <code>UpdateByMinDimension</code>,
<code>UpdateByCenterDimension</code>, <code>IndexDimension</code> and <code>IndexCenter</code>; the shipped SPA calls none of them,
because the editor resolves every mode to a plain <code>Update</code>.</li>
</ul>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/geom/Box3dEditor.vue</code> — the editor: the Edit Mode selector, the four
vector rows and their per-mode read-only rules, and the client-side arithmetic behind the two
derived modes. Its only prop is the IndexService key.</li>
<li><code>wwwroot-src/src/components/widgets/Vec3Input.vue</code> — the X / Y / Z row widget, in standard or
single-field text mode; its <code>readonly</code> prop is what the edit mode drives.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — maps the <code>Box3d</code> kind to this editor, the
single map both the switchboard and the Control Tree resolve through.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the kind picker that creates a Box3d and,
outside selector-only mode, embeds this editor beneath itself.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>Box3d</code> against the sole-editor
panel and lists it among the kinds a container may hold.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — the kind node's panel, resolving
<code>Box3d</code> through the kind map and binding the editor to the node's key.</li>
<li><code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> — the Geometry slot's picker, from
which a Box3d is chosen.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — <code>getBox3d</code>, <code>indexBox3dMin</code>, <code>indexBox3dMax</code> and the create
entry. There is deliberately no update wrapper here; the editor posts the update itself.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> — the <code>box.*</code> and <code>bounds.*</code> strings, and
<code>wwwroot-src/src/i18n/en/common.ts</code> — the shared Min and Max row captions.</li>
<li><code>Geom/Box3dController.cs</code> — REST endpoints at <code>/api/Box3d/*</code>: <code>New</code>, <code>NewWithValue</code>, <code>Get</code>,
<code>Update</code>, <code>IndexMin</code>, <code>IndexMax</code>, <code>IndexDimension</code>, <code>IndexCenter</code>, <code>UpdateByMinDimension</code> and
<code>UpdateByCenterDimension</code>.</li>
<li><code>Common/IndexService.cs</code> — the keyed object store every box key resolves against.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard that offers this kind and
hosts this editor</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>Cylindroid Control | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Cylindroid Control | 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-CylindroidControl">
<h1 id="cylindroid-control">Cylindroid Control</h1>
<p>The Cylindroid editor edits a <a class="xref" href="../../api/Hi.Geom.Cylindroid.html">Cylindroid</a> — a solid of revolution defined by a list of
(Z, R) pairs — as a table of rows, with a minimum of two. It is reached from any Geometry slot that
admits the <code>Cylindroid</code> kind, and again from the Tool House cylindroid holder, whose Geometry node
embeds the same editor directly.</p>
<h2 id="layout">Layout</h2>
<ul>
<li><strong>Z-R pairs</strong> — a header row carrying the section label and an <strong>Add</strong> button. Add appends a row
ten millimetres above the last one, at the same radius.</li>
<li><strong>The table</strong> — one row per pair, columns <code>#</code>, <code>Z (mm)</code> and <code>R (mm)</code>. Each Z and R cell is an
inline text field parsed as a number; there is no spinner. A per-row remove button sits at the end
of each row, disabled once only two pairs remain.</li>
<li><strong>The caption</strong> — a one-line statement of the type: a solid of revolution defined by (Z, R) pairs,
minimum two.</li>
</ul>
<p>The desktop control is shaped differently for the same job: a title, an <strong>Add Point</strong> and a <strong>Clear
All</strong> button, and a data grid with Z, R and Actions columns. Clear All has no web counterpart — it
confirms, wipes the list and re-seeds a single pair.</p>
<h2 id="behavior">Behavior</h2>
<ul>
<li><strong>A cell commits on blur or Enter.</strong> An empty or non-finite entry is dropped rather than written,
and a negative radius is clamped to zero — on the client and again on the server.</li>
<li><strong>The floor is two pairs, and both ends enforce it.</strong> The web disables the remove button at two
and the controller refuses the call below two. The desktop client blocks only at one, with a
warning dialog.</li>
<li><strong>Creating one seeds three pairs.</strong> The create endpoint starts a new cylindroid at (0, 20),
(30, 20) and (60, 10) rather than empty.</li>
<li><strong>Four endpoints ship without a caller.</strong> The controller exposes <code>GetPairCount</code>, <code>GetPairAt</code>,
<code>UpdatePairAt</code> and <code>SortByZ</code>; the shipped SPA uses none of them, committing the whole list instead.</li>
</ul>
<h2 id="tessellation-resolution-is-not-a-property-of-the-shape">Tessellation Resolution Is Not a Property of the Shape</h2>
<p>There is no longitude count, and no per-instance resolution, on a cylindroid. The STL longitude
number is derived internally at generation time from a resolution the caller supplies; the type
carries only a static default. The desktop client once had a Longitude Number field and its handler
was deleted when the backing property went away.</p>
<p>Where resolution <em>is</em> exposed, it belongs to the holder rather than to the shape: the Tool House
cylindroid holder carries a <strong>Resolution</strong> surface beside its Geometry one — a tree node on the web,
a tab in the desktop client — offering a linear resolution in millimetres and an angle resolution in
degrees, described in the app as the tessellation resolution used for display and collision meshing.</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/geom/CylindroidEditor.vue</code> — the editor: the header row and Add
button, the Z / R table with its per-cell commit, and the per-row remove and its two-pair floor.
Edits by IndexService key and emits <code>changed</code> so the owner can resync.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — maps the <code>Cylindroid</code> kind to this editor.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the kind picker that creates a Cylindroid
and embeds this editor beneath itself.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>Cylindroid</code> against the
sole-editor panel and lists it among the kinds a container may hold.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — the kind node's panel.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue</code> — the second host: it
embeds this editor on the holder's cylindroid key for the Geometry node, and renders the linear
and angle resolution fields for the sibling Resolution node.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — grows those two holder children,
and only for a cylindroid holder.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — <code>getCylindroid</code>, <code>updateCylindroidPairs</code>, <code>addCylindroidPair</code>,
<code>removeCylindroidPairAt</code> and the create entry.</li>
<li><code>wwwroot-src/src/api/cylindroidHolder.ts</code> — the holder side: the cylindroid key it exposes, the
geometry update, and the resolution setter.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> — the <code>cylindroid.*</code> strings, and
<code>wwwroot-src/src/i18n/en/toolhouse.ts</code> — the Resolution node's own labels and hint.</li>
<li><code>Geom/CylindroidController.cs</code> — REST endpoints at <code>/api/Cylindroid/*</code>: <code>New</code>, <code>Get</code>,
<code>GetPairCount</code>, <code>GetPairAt</code>, <code>UpdatePairAt</code>, <code>UpdateAllPairs</code>, <code>AddPair</code>, <code>RemovePairAt</code> and
<code>SortByZ</code>.</li>
<li><code>Mech/CylindroidHolderController.cs</code> — the holder surface at <code>/api/CylindroidHolder/*</code> behind the
Tool House host.</li>
<li><code>Common/IndexService.cs</code> — the keyed object store every cylindroid key resolves against.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard that offers this kind and
hosts this editor</li>
<li><a class="xref" href="../tool-house/holder/cylindroid-holder-panel.html">Cylindroid Holder Panel</a> — the second host, and the surface
that owns the tessellation resolution</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,212 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Extended Cylinder Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Extended Cylinder 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-ExtendedCylinderPanel">
<h1 id="extended-cylinder-panel">Extended Cylinder Panel</h1>
<p>The Extended Cylinder editor edits one number on an <a class="xref" href="../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a>: its full
length, measured from <code>Z=0</code> and <strong>including the span below the start section</strong>. Its only home on
either client is the Tool House cutter's Upper Beam, where the start section is the flute top.</p>
<h2 id="layout">Layout</h2>
<ul>
<li>An explanatory block stating what the type is and, in bold, how the length is measured.</li>
<li><strong>Full Length</strong> — a single numeric field in millimetres, with a hint under it.</li>
</ul>
<p>The desktop panel is a title over the same one field.</p>
<h2 id="behavior">Behavior</h2>
<ul>
<li><strong>The hint states a lower bound only when that bound is positive.</strong> The bound is the Z of the
start section, served with the value as <code>minFullLength</code>; above zero the hint reads &ldquo;must exceed
the start-section Z&rdquo;, and at zero it degrades to a plain &ldquo;full length from Z=0&rdquo;. The test is the
number, not the wiring — a geometry with no start-section source and one whose source sits at
<code>Z=0</code> read identically here, because the controller answers <code>0</code> for both. There is no upper bound
anywhere — not in the editor and not in the controller.</li>
<li><strong>A live bound belongs to the cutter alone.</strong> The bare create endpoint installs a constant start
pair at <code>Z=0</code>, and the container-aware create switches install no source at all; both answer a
bound of zero. Only the cutter upper beam wires a real one — setting the beam links it to the
flute top — so only there does a bound appear.</li>
<li><strong>The guard is two layers, and they differ by one.</strong> The numeric field rejects a value <em>below</em> the
minimum — its minimum is inclusive — so a value exactly equal to the bound passes the field and is
caught one layer up by the editor, which raises an error to its host as a banner rather than an
inline field message. The controller then rejects non-finite, non-positive, and at-or-below-bound
values with a 400.</li>
<li><strong>The field commits on blur or Enter.</strong> The desktop control does not: it writes on every
keystroke, and performs no minimum, positivity or finiteness check at all. The range guard is a
web and backend feature.</li>
<li><strong>Creating one through the cutter is not the same as creating one bare.</strong> The Upper Beam creates
through the cutter's own endpoint so the backend seeds a valid full length and can return
geometry-issue warnings — which the Upper Beam panel renders as persistent banners. The bare
create endpoint seeds a length of 100 and a single start pair.</li>
</ul>
<h2 id="reach">Reach</h2>
<p>Both clients restrict this kind to the cutter's upper beam, by different mechanisms. In the desktop
client the switchboard's Extended Cylinder entry ships collapsed and is revealed by a property that
exactly one host sets — the milling cutter panel. On the web <strong>no Geometry slot offers the kind at
all</strong>: it is absent from the container kinds, so it can be neither a transformation geometry's inner
geometry nor a combination child, and it was taken out of the workpiece's raw geometry once a saved
project was found to reload one degenerate. The single surface that offers it is the cutter's Upper
Beam, which mounts the switchboard itself over its own six-kind list rather than being a Geometry
slot.</p>
<div class="NOTE">
<h5>Note</h5>
<p><strong>A project saved earlier can still carry one on a workpiece, and the two halves of the tree
disagree about it.</strong> The kind is serialized; only the start-section hookup is not. Such a project
reloads with the raw geometry in place, and the Geometry slot's child builder tests the type
against the whole kind map rather than against the slot's whitelist, so the <code>ExtendedCylinder</code>
kind node and this editor still appear beneath it. The slot's own picker tests the whitelist,
finds the type outside it and blanks — leaving an empty type dropdown above a child node that
edits an Extended Cylinder. The bound reads zero there, because nothing is wiring a start
section.</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):</p>
<ul>
<li><code>wwwroot-src/src/components/geom/ExtendedCylinderEditor.vue</code> — the description block and the Full
Length field, its hint, and the at-or-below-bound check that raises an error to the host.</li>
<li><code>wwwroot-src/src/components/widgets/NumericInput.vue</code> — the shared numeric field: an inclusive
minimum rejected on blur, and the hint slot under it.</li>
<li><code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> — the component's real home: the cutter's
Upper Beam, which creates through the container-aware cutter endpoint and renders the returned
geometry-issue warnings.</li>
<li><code>wwwroot-src/src/components/controlTree/toolhouse/CutterSectionPanel.vue</code> — mounts that panel for
the cutter's Upper Beam node, and deliberately skips its own fetch there.</li>
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — builds the Upper Beam child of
the Cutter node.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — maps the <code>ExtendedCylinder</code> kind to this
editor.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the kind picker.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>ExtendedCylinder</code> against the
sole-editor panel, is where its absence from the container kinds is declared, and holds the
Geometry slot's child builder — the half that tests the whole kind map rather than the whitelist.</li>
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — the workpiece raw-geometry
whitelist, and the comment recording why the kind is no longer in it.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — <code>getExtendedCylinder</code>,
<code>updateExtendedCylinderFullLength</code> and the create entry.</li>
<li><code>wwwroot-src/src/api/toolHouse.ts</code> — the upper-beam get, create and resync wrappers, and the
warnings contract.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> — the <code>extCylinder.*</code> strings: the label, the description and
measure rule, both hints, and the below-minimum error.</li>
<li><code>Geom/ExtendedCylinderController.cs</code> — REST endpoints at <code>/api/ExtendedCylinder/*</code>: <code>New</code>, <code>Get</code>,
<code>UpdateFullLength</code> and <code>GetFullLength</code>. <code>Get</code> carries <code>minFullLength</code> alongside the value.</li>
<li><code>Mech/CutterController.cs</code> — the upper-beam routes the Tool House host actually goes through, and
the geometry-issue warnings it surfaces.</li>
<li><code>Mech/WorkpieceController.cs</code> — the raw-geometry create switch, which still carries an
<code>ExtendedCylinder</code> arm that no picker can now reach.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard that offers this kind and
hosts this editor</li>
<li><a class="xref" href="../tool-house/cutter/milling-cutter-panel.html">Milling Cutter Panel</a> — the cutter whose Upper Beam is this
editor's real home, and the one surface that supplies 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,205 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Geometry Combination Control | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Geometry Combination Control | 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-GeomCombinationControl">
<h1 id="geometry-combination-control">Geometry Combination Control</h1>
<p>A <a class="xref" href="../../api/Hi.Geom.GeomCombination.html">GeomCombination</a> is several geometries treated as one, and it has <strong>two faces on the
web</strong>: an inline editor that renders every child's own editor at once, and a Control-Tree panel that
manages the list only and puts each child on its own node. The desktop client has the inline shape
alone. There is no selection model on any of them — every child carries its own remove button.</p>
<h2 id="layout">Layout</h2>
<h3 id="the-inline-editor">The inline editor</h3>
<ul>
<li><strong>Add bar</strong> — a child-kind picker beside an <strong>Add</strong> button, and a <strong>Clear all</strong> button.</li>
<li><strong>One card per child</strong>, each with a <code>#n</code> index badge, the child's type name, its own remove
button, and — in the card body — that child's full editor, rendered recursively. All children are
editable at once.</li>
</ul>
<h3 id="the-control-tree-panel">The Control-Tree panel</h3>
<p>Deliberately shallow: a list of read-only rows with Add, a per-row remove and Clear all, and a
standing hint that an <strong>Item</strong> child node is where a child is actually edited. No editor is embedded
here; each child is its own <code>Item</code> node — <code>.../item-{index}</code> — under this one.</p>
<h3 id="the-desktop-control">The desktop control</h3>
<p>A title, then an <strong>Add</strong> and a <strong>Clear All</strong> button over a scrolling list of bordered cards, each
holding that child's own geometry management panel and a remove button — no index badge and no type
caption. Below the list sits a collapsed <strong>Combination Information</strong> expander reporting the aggregate
triangle count and bounding box, the latter as a read-only box control.</p>
<h2 id="adding-a-child">Adding a Child</h2>
<p>The two clients differ here, and the web is the one that gained something:</p>
<ul>
<li><strong>Web</strong> — pick the kind first, then Add; the request carries the kind.</li>
<li><strong>Desktop</strong> — Add takes no kind and always appends a 100 mm cube. The kind is switched afterwards,
on that child's own Geometry Type combo.</li>
</ul>
<p>Five kinds may be children — Box3d, Cylindroid, StlFile, TransformationGeom and a <strong>nested</strong>
GeomCombination, so combinations nest arbitrarily deep. <code>CubeTreeFile</code> and <code>ExtendedCylinder</code> are
accepted by neither client's switch.</p>
<h2 id="behavior">Behavior</h2>
<ul>
<li><strong>A type switch rewires the slot, not just the alias.</strong> Changing a child's kind goes through
<code>SetItemAt</code>, which replaces the entry in <a class="xref" href="../../api/Hi.Geom.GeomCombination.html#Hi_Geom_GeomCombination_StlSources">StlSources</a> itself.</li>
<li><strong>The aggregate STL is cached, and a child's own controller does not invalidate it.</strong> Editing a
child through its own endpoints leaves the combination returning the mesh it had already built, so
both web faces call <code>CleanCache</code> before bubbling the change, and compose that call into the
ancestor chain. This is the behavioural fact the rest of the page depends on.</li>
<li><strong>Removing a child does not renumber the ones after it.</strong> Item keys are minted as
<code>{key}-item-{index}</code> and the remove endpoint leaves later indices pointing at the old aliases,
which is why every structural change rebuilds the branch and re-mints them.</li>
<li><strong>Clear all confirms only on the desktop.</strong> The web posts it directly.</li>
</ul>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/geom/GeomCombinationEditor.vue</code> — the inline face: the Add bar, the
per-child cards, and the recursive editor in each. Type switches route through <code>SetItemAt</code>, a
cache clean precedes every <code>changed</code> bubble, and item aliases are released on refresh and unmount.</li>
<li><code>wwwroot-src/src/components/controlTree/GeomCombinationTreePanel.vue</code> — the Control-Tree face:
list management only, emitting a structure change so the host re-mints the item aliases.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers the kind against that panel with
a child builder that mints one <code>Item</code> node per element, and declares the five container kinds a
child may be.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — maps the <code>GeomCombination</code> kind to the
inline editor.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the recursive kind picker each child card
embeds.</li>
<li><code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> and
<code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — an <code>Item</code> node's picker and, once a
kind is chosen, that kind's editor.</li>
<li><code>wwwroot-src/src/components/geom/TransformationGeomEditor.vue</code> — the nesting host: a combination
is an allowed inner geometry.</li>
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code>,
<code>wwwroot-src/src/pages/MechBuilderPage.vue</code> and
<code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> — the slots that admit the kind: the
fixture geometry, the workpiece raw geometry, a mechanism anchor's geometry and the cutter upper
beam. The workpiece's target geometry deliberately does not.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — <code>getGeomCombination</code>, <code>addGeomCombinationItem</code>,
<code>setGeomCombinationItemAt</code>, <code>removeGeomCombinationItemAt</code>, <code>clearGeomCombination</code>,
<code>cleanGeomCombinationCache</code> and <code>indexGeomCombinationItemAt</code>, with the child-kind and combination
types and the create entry.</li>
<li><code>wwwroot-src/src/api/index-service.ts</code> — the index release the editor uses to drop item aliases.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> — the <code>combination.*</code> strings, and
<code>wwwroot-src/src/i18n/en/tree.ts</code> — the tree panel's own strings and the <code>Item</code> node label.</li>
<li><code>Geom/GeomCombinationController.cs</code> — REST endpoints at <code>/api/GeomCombination/*</code>: <code>New</code>, <code>Get</code>,
<code>GetCount</code>, <code>AddItem</code>, <code>SetItemAt</code>, <code>RemoveItemAt</code>, <code>Clear</code>, <code>CleanCache</code>, <code>IndexItemAt</code> and
<code>GetItemTypeAt</code>. <code>AddItem</code> and <code>SetItemAt</code> share one five-arm kind switch and both clean the
cache.</li>
<li><code>Geom/TransformationGeomController.cs</code>, <code>Mech/FixtureController.cs</code>,
<code>Mech/WorkpieceController.cs</code>, <code>Mech/MechBuilder/GeneralMechanismController.cs</code> and
<code>Mech/CutterController.cs</code> — the container-aware create switches behind each host's <code>onCreate</code>.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard that offers this kind, and
the panel each desktop child card embeds</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,252 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Geometry Management Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Geometry Management 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-GeomManageControl">
<h1 id="geometry-management-panel">Geometry Management Panel</h1>
<p>The geometry switchboard is one control: a kind picker over the kinds its host allows, and — unless
the host asked for the picker alone — the picked kind's editor beneath it. On the web it binds a
<strong>key into the shared object store</strong>, not an object, and every Control-Tree Geometry slot is this
same control in selector-only mode.</p>
<h2 id="layout">Layout</h2>
<p>Web: a geometry-type dropdown; a separator, drawn only while a kind is active; then that kind's
editor. Picking a kind commits immediately — there is no Apply button. In selector-only mode
everything below the dropdown is dropped, which is the form each Geometry slot node shows.</p>
<p>Desktop: a combo box on the left of a head line with a <strong>Convert</strong> menu on its right, over a bordered
content presenter that hosts the kind's own control.</p>
<h2 id="what-it-binds">What It Binds</h2>
<p>The web panel has no target-geometry property. It takes a <code>modelKey</code> naming the object it edits and
mutates what sits behind that key; a host that also owns the <em>field</em> holding the geometry passes an
<code>onCreate</code> hook, so switching the kind rebinds the host's field rather than just the key. The
desktop panel is the one that exchanges an <a class="xref" href="../../api/Hi.Geom.IStlSource.html">IStlSource</a> directly, through a getter and
setter pair its host supplies.</p>
<p>Each host's field type decides which kinds it <em>may</em> offer; whether the kind survives a save decides
which of those it <em>does</em>. A fixture's geometry and a transformation geometry's inner geometry are
<a class="xref" href="../../api/Hi.Geom.IGetStl.html">IGetStl</a>; a workpiece's initial geometry is an <code>IMakeXmlSource</code>, which is why the
cube-tree file — which is not an <code>IGetStl</code> — reaches that picker and no other.</p>
<p>Type compatibility alone is not sufficient, and <a class="xref" href="../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a> is the case that
shows it. It is an <code>IMakeXmlSource</code>, so the workpiece's raw slot could hold one and once did — but
its start section is supplied by a host at run time and is not serialized, so a saved project
reloaded it with a zero-radius start and the shape degenerated. The kind is now offered by the one
host that wires that source, the cutter's upper beam.</p>
<h2 id="reach">Reach</h2>
<p>The picker's own default is <strong>six of the seven kinds</strong>: <a class="xref" href="../../api/Hi.Geom.Box3d.html">Box3d</a>,
<a class="xref" href="../../api/Hi.Geom.Cylindroid.html">Cylindroid</a>, <a class="xref" href="../../api/Hi.Geom.StlFile.html">StlFile</a>, <a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a>,
<a class="xref" href="../../api/Hi.Geom.GeomCombination.html">GeomCombination</a> and <a class="xref" href="../../api/Hi.Cbtr.CubeTreeFile.html">CubeTreeFile</a>. <a class="xref" href="../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a> is
in the kind map but out of that default: a host that can wire its start section names it explicitly.
Nothing is hidden by a flag on the web.</p>
<p><strong>The default is a guard rail, not a shipped list.</strong> Every host passes its own whitelist — the five
Control-Tree Geometry slots from the node context, the four inline hosts as a constant — so no
shipped surface renders the default at all, and the whitelist is what really decides reach.</p>
<table>
<thead>
<tr>
<th>Host</th>
<th>Kinds offered</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fixture geometry, mechanism anchor, a transformation geometry's inner geometry, a combination child</td>
<td>the five container kinds — Box3d, Cylindroid, StlFile, TransformationGeom, GeomCombination</td>
</tr>
<tr>
<td>Workpiece raw geometry</td>
<td>six — the five container kinds plus CubeTreeFile</td>
</tr>
<tr>
<td>Workpiece target geometry</td>
<td>four</td>
</tr>
<tr>
<td>Cutter upper beam</td>
<td>six — Cylindroid, ExtendedCylinder, TransformationGeom, StlFile, Box3d, GeomCombination</td>
</tr>
</tbody>
</table>
<p>A null geometry is a legal state of the model, but the web picker offers its <strong>None (unset)</strong> entry
only when the host asks for it: the three General Setup slots and a transformation geometry's inner
geometry do, while the mechanism anchor, the cutter upper beam and combination children do not, so
those pickers cannot clear the slot. Clearing goes through the host's create hook with the literal
kind <code>None</code>, which the container-aware endpoints map to null. The desktop combo always lists a
<strong>None</strong> item.</p>
<h2 id="converting-is-desktop-only">Converting Is Desktop-Only</h2>
<p>Wrapping an existing geometry into a <a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a> — and extracting it back out
— exists only in the desktop client, as items in the <strong>Convert</strong> menu rather than as buttons. The
<em>Convert to Transformation</em> item re-titles itself <em>Extract from Transformation</em> when the current
geometry already is one; the combination item behaves the same way, and its extract is offered only
when the combination holds exactly one child. Three code-behind properties can hide the menu and each
of its two items, but no shipped host sets any of them.</p>
<p><strong>The web has no equivalent, and the difference is not cosmetic.</strong> Picking <code>TransformationGeom</code> in
the picker creates a new, empty one and discards the geometry that was there — it does not wrap it.</p>
<h2 id="in-the-control-tree">In the Control Tree</h2>
<p><code>Geometry</code> is a slot item type. Its child builder probes the slot's key for the type behind it and,
when that type is a known kind, grows exactly <strong>one</strong> child node of that kind bound to the same key
— so the slot node carries the picker and its single child carries the editor. Five kinds resolve to
the shared sole-editor panel; <code>TransformationGeom</code> and <code>GeomCombination</code> instead map to panels of
their own, because they grow further slot children rather than hosting one editor. The two
file-backed kinds compose the referenced file into their node label.</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/geom/GeometryEditor.vue</code> — the switchboard: the kind picker over the
allowed kinds, the opt-in unset entry, the immediate commit through the create hook, and the
active kind's editor.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — the single kind → editor map both this
picker and the Control Tree's sole-editor panel resolve through.</li>
<li><code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> — the slot node's panel: this
switchboard in selector-only mode, fed its allowed kinds, its unset flag and its create hook from
the node.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — the kind child's panel.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>Geometry</code> as a slot type with
its child builder, registers each kind against its panel, and holds both the container-kind list
and the file-backed node labels.</li>
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — the three General Setup Geometry
slots and their per-host kind whitelists.</li>
<li><code>wwwroot-src/src/pages/MechBuilderPage.vue</code> and
<code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> — the two inline, non-tree hosts.</li>
<li><code>wwwroot-src/src/api/index-service.ts</code> — the type probe the picker calls to discover which kind is
currently behind the key.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — the kind union, the create dispatcher and its per-kind
endpoint map, and every per-kind call.</li>
<li><code>wwwroot-src/src/api/fixture.ts</code>, <code>wwwroot-src/src/api/workpiece.ts</code>,
<code>wwwroot-src/src/api/toolHouse.ts</code> and <code>wwwroot-src/src/api/generalMechanism.ts</code> — the
container-aware create wrappers each host's hook posts through.</li>
<li><code>wwwroot-src/src/i18n/en/common.ts</code> and <code>wwwroot-src/src/i18n/en/geom.ts</code> — the picker's label and
its unset and empty-state strings. Geometry type names are deliberately not translated.</li>
<li>The seven per-kind controllers under <code>Geom/</code> — <code>Geom/Box3dController.cs</code>,
<code>Geom/CylindroidController.cs</code>, <code>Geom/ExtendedCylinderController.cs</code>, <code>Geom/StlFileController.cs</code>,
<code>Geom/CubeTreeFileController.cs</code>, <code>Geom/TransformationGeomController.cs</code> and
<code>Geom/GeomCombinationController.cs</code> — each at <code>/api/{Kind}/*</code>. There is no single geometry
controller and no geometry hub.</li>
<li><code>Common/IndexController.cs</code> — the type probe at <code>/api/Index/GetType</code>.</li>
<li><code>Common/IndexService.cs</code> — the keyed object store all of the above read and write. There is no
per-panel session object.</li>
<li><code>Mech/FixtureController.cs</code>, <code>Mech/WorkpieceController.cs</code>, <code>Mech/CutterController.cs</code> and
<code>Mech/MechBuilder/GeneralMechanismController.cs</code> — the container-aware create endpoints that set
the host's own field, and the ones that accept <code>None</code> and store null.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../util/mech-builder.html">Mechanism Builder Page</a> — embeds this control under its anchor
editor</li>
<li><a href="box3d-control.html">Box3d Control</a> — the kind editors this switchboard resolves</li>
<li><a href="cylindroid-control.html">Cylindroid Control</a> — the same, for a solid of revolution</li>
<li><a href="extended-cylinder-panel.html">Extended Cylinder Panel</a> — the same, and the kind exactly one host offers</li>
<li><a href="stlfile-control.html">STL File Control</a> — the same, for an STL reference</li>
<li><a href="meshed-geom-panel.html">Meshed Geometry Panel</a> — the same, for a voxel cube tree</li>
<li><a href="transformation-geom-control.html">Transformation Geometry Control</a> — the container kind this panel
can wrap into on the desktop client</li>
<li><a href="geom-combination-control.html">Geometry Combination Control</a> — the other container kind, whose
every child embeds this panel again</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,228 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Geometry Panels | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Geometry Panels | 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-Geom">
<h1 id="geometry-panels">Geometry Panels</h1>
<p>The Geometry Panels are the editors for <a class="xref" href="../../technique/api-foundations/basic-geometry.html">Geometry Objects</a>, together
with the switchboard that picks which <a class="xref" href="../../api/Hi.Mech.Topo.ITransformer.html">ITransformer</a> places them. Two switchboards
run the folder: the <a href="geom-manage-control.html">Geometry Management Panel</a> chooses a geometry kind and
hosts that kind's editor, and the <a href="transformer-panel.html">Transformer Select Panel</a> does the same for
a transformer.</p>
<p>On the shipped SPA a Control Tree is where both switchboards are usually met. A <strong>Geometry slot</strong> or
a <strong>Transformer slot</strong> carries the kind picker, and the picked kind becomes the slot's single child
node, whose panel is that kind's editor. The same editors are also embedded inline, without a tree —
by <a href="transformation-geom-control.html">Transformation Geometry Control</a> for its inner geometry and inner
transformer, by <a href="geom-combination-control.html">Geometry Combination Control</a> for each child, by the
Mechanism Builder page, and by the Tool House cutter's upper beam.</p>
<p>A page belongs in this folder when it documents one geometry kind's editor, or a switchboard that
picks a kind and hosts that editor. The transformer switchboard lives beside the geometry kinds
rather than under a route because it sits in the same Control-Tree slot pattern and is embedded by
the same editors.</p>
<p>Ordered the way the folder builds up: the primitive solids first, then the file-backed geometries,
then the operators that wrap and combine them, and last the two switchboards that host all of them.</p>
<h2 id="geometry-kinds">Geometry Kinds</h2>
<table>
<thead>
<tr>
<th>Page</th>
<th>What it edits</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="box3d-control.html">Box3d Control</a></td>
<td>A 3D box defined by min/max coordinates</td>
</tr>
<tr>
<td><a href="cylindroid-control.html">Cylindroid Control</a></td>
<td>A cylindroid with radius values along the Z axis</td>
</tr>
<tr>
<td><a href="extended-cylinder-panel.html">Extended Cylinder Panel</a></td>
<td>An <a class="xref" href="../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a> and its full length</td>
</tr>
<tr>
<td><a href="stlfile-control.html">STL File Control</a></td>
<td>An <a class="xref" href="../../api/Hi.Geom.IStlSource.html">IStlSource</a> loaded from an STL file</td>
</tr>
<tr>
<td><a href="meshed-geom-panel.html">Meshed Geometry Panel</a></td>
<td>A <a class="xref" href="../../api/Hi.Cbtr.CubeTreeFile.html">CubeTreeFile</a>, the pre-computed voxel cube tree; the kind picker shows it as <code>MeshedGeomFile</code></td>
</tr>
<tr>
<td><a href="transformation-geom-control.html">Transformation Geometry Control</a></td>
<td>An inner geometry plus the transformer that places it</td>
</tr>
<tr>
<td><a href="geom-combination-control.html">Geometry Combination Control</a></td>
<td>Several geometries combined into one</td>
</tr>
</tbody>
</table>
<p>Every kind above is an ordinary entry in the same geometry kind map, and the switchboard resolves each
one the same way. What separates them in practice is reach, not class: each host names the kinds its
own model accepts, so <code>CubeTreeFile</code> reaches only the workpiece's raw-geometry picker, and
<code>ExtendedCylinder</code> only the cutter's upper beam.</p>
<h2 id="switchboards">Switchboards</h2>
<table>
<thead>
<tr>
<th>Page</th>
<th>What it hosts</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="geom-manage-control.html">Geometry Management Panel</a></td>
<td>The geometry kind picker and the picked kind's editor</td>
</tr>
<tr>
<td><a href="transformer-panel.html">Transformer Select Panel</a></td>
<td>The transformer kind picker and the picked kind's editor, over all seven transformer kinds</td>
</tr>
</tbody>
</table>
<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>The editors and the two switchboards:</p>
<ul>
<li><code>wwwroot-src/src/components/geom/</code> — the geometry editors, plus
<code>wwwroot-src/src/components/geom/GeometryEditor.vue</code>, the geometry switchboard itself.</li>
<li><code>wwwroot-src/src/components/topo/</code> — the transformer editors, plus
<code>wwwroot-src/src/components/topo/TransformerSelectPanel.vue</code>.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> and
<code>wwwroot-src/src/components/topo/transformerEditors.ts</code> — the two kind → editor maps every host
resolves an editor through.</li>
</ul>
<p>The Control-Tree glue that makes them reachable:</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> and
<code>wwwroot-src/src/components/controlTree/TransformerSlotPanel.vue</code> — the two slot panels, each its
switchboard in selector-only mode.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — the kind node's panel, resolving the
node's kind through both maps.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>Geometry</code> and <code>Transformer</code> as
slot types; the five leaf geometry kinds and all seven transformer kinds against <code>SoleEditorPanel</code>;
and <code>TransformationGeom</code> and <code>GeomCombination</code> against their own tree panels, which grow further
slot children instead of one editor.</li>
</ul>
<p>The REST controllers, one per kind:</p>
<ul>
<li><code>Geom/Box3dController.cs</code>, <code>Geom/CylindroidController.cs</code>, <code>Geom/ExtendedCylinderController.cs</code>,
<code>Geom/StlFileController.cs</code>, <code>Geom/CubeTreeFileController.cs</code>,
<code>Geom/TransformationGeomController.cs</code>, <code>Geom/GeomCombinationController.cs</code>.</li>
<li><code>Mech/Topo/StaticTranslationController.cs</code>, <code>Mech/Topo/StaticRotationController.cs</code>,
<code>Mech/Topo/StaticFreeformController.cs</code>, <code>Mech/Topo/DynamicTranslationController.cs</code>,
<code>Mech/Topo/DynamicRotationController.cs</code>, <code>Mech/Topo/GeneralTransformController.cs</code>,
<code>Mech/Topo/NoTransformController.cs</code>.</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>Meshed Geometry Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Meshed Geometry 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-MeshedGeomPanel">
<h1 id="meshed-geometry-panel">Meshed Geometry Panel</h1>
<p>The meshed-geometry editor points a geometry at a pre-computed voxel cube tree in a <code>.wct</code> file. Its
model is <a class="xref" href="../../api/Hi.Cbtr.CubeTreeFile.html">CubeTreeFile</a>, a <em>reference</em> to that file: neither the editor nor the
controller loads the voxel data, which stays deferred until something actually needs the mesh.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p><strong>The kind is <code>CubeTreeFile</code>; the label is <code>MeshedGeomFile</code>.</strong> The rename is display-only and lives
in exactly two registries — the kind picker's option label and the Control-Tree node label — while
the value sent to the backend stays the type name. The domain type carries the matching display
name of its own. Any page describing a mesh source has to keep the two apart.</p>
</div>
<h2 id="layout">Layout</h2>
<ul>
<li>A caption naming what the field takes, <code>.wct</code>.</li>
<li><strong>The file selector</strong> — the shared file-path widget, filtered to <code>.wct</code>, with an empty-state hint
when nothing is chosen.</li>
<li>A standing description: the geometry is a pre-computed voxel cube tree, and loading it is deferred
until it is needed.</li>
</ul>
<p>The desktop panel is a read-only path field with <strong>Browse</strong> and <strong>Reload</strong> buttons. The web has no
Reload: the controller has no such action.</p>
<h2 id="reach">Reach</h2>
<p><strong>One slot offers this kind: the workpiece's Raw Geometry.</strong> The fixture's geometry and the
workpiece's target geometry both exclude it, and it is not among the container kinds, so it can be
neither a transformation geometry's inner geometry nor a combination child. The Control-Tree node
carries the chosen file in its label, as <code>MeshedGeomFile [&lt;path&gt;]</code>.</p>
<p>The desktop client reaches it differently. There, the workpiece page carries a <strong>Geometry Source</strong>
combo — Common Geometry or Meshed Geometry — that decides whether this panel or the geometry
switchboard is visible. The web has no such toggle: picking the <code>MeshedGeomFile</code> kind <em>is</em> choosing
the meshed source. The classification survives on the server, which still reports a raw geometry of
this type as a meshed one.</p>
<h2 id="key-model">Key Model</h2>
<p><a class="xref" href="../../api/Hi.Cbtr.CubeTreeFile.html">CubeTreeFile</a> is the file reference; <a class="xref" href="../../api/Hi.Cbtr.CubeTree.html">CubeTree</a> is the voxel tree itself.
The reader resolves the stored relative path and opens it with no extension test of its own — <code>.wct</code>
is what the app writes and what every user-facing string names, not something the loader enforces.</p>
<p>The consumer that reads the data is the equipment-setup scene: it recognises a workpiece whose
initial geometry is a cube-tree file and builds the meshed geometry for the canvas, behind the
canvas's own Meshed Geometry display toggle.</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/geom/CubeTreeFileEditor.vue</code> — the editor: the caption, the <code>.wct</code>
file selector and the deferred-loading description.</li>
<li><code>wwwroot-src/src/components/widgets/FilePathInput.vue</code> and
<code>wwwroot-src/src/components/widgets/FileExplorerDialog.vue</code> — the picker and the in-app browser it
opens.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — maps the <code>CubeTreeFile</code> kind to this
editor.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the kind picker, and the display-only
rename applied to its option label.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers the kind against the sole-editor
panel, holds the other half of the rename, builds the node label that carries the file, and is
where the kind's absence from the container kinds is declared.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> and
<code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> — the kind node's panel and the
parent slot's picker.</li>
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — the workpiece raw-geometry slot,
the only slot whose allowed kinds admit it, and the node-label refresh when the file changes.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — <code>getCubeTreeFile</code>, <code>setCubeTreeFileSourceFile</code> and the create
entry.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> — the <code>meshedFile.*</code> strings, and
<code>wwwroot-src/src/i18n/en/tree.ts</code> — the Raw Geometry slot label.</li>
<li><code>Geom/CubeTreeFileController.cs</code> — REST endpoints at <code>/api/CubeTreeFile/*</code>: <code>New</code>, <code>Get</code> and
<code>SetSourceFile</code>, and nothing else. None of them loads the voxel data.</li>
<li><code>Mech/WorkpieceController.cs</code> — the raw-geometry create path, and the classification that still
reports this type as a meshed geometry.</li>
<li><code>Common/IndexService.cs</code> — the keyed object store every cube-tree-file key resolves against.</li>
<li><code>Disp/EquipmentSetupDisplayee.cs</code> and <code>Mech/EquipmentSetupDisplayController.cs</code> — the scene that
builds the meshed geometry for the canvas, and the display toggle that shows it.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard that offers this kind and
hosts this editor</li>
<li><a href="stlfile-control.html">STL File Control</a> — the other file-backed kind, and the one this slot offers
beside it</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,208 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>STL File Control | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="STL File Control | 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-StlFileControl">
<h1 id="stl-file-control">STL File Control</h1>
<p>The STL file editor points a geometry at an <code>.stl</code> file rather than describing a shape: the model
holds a file reference, and the editor is a picker over it plus a read-only summary of what was
loaded. On the web the file lives on the <strong>server</strong>, not on the machine running the browser, and
that difference shapes everything else on the page.</p>
<h2 id="layout">Layout</h2>
<ol>
<li><strong>File reference</strong> — a read-only field showing the path currently referenced, with an empty-state
hint when there is none.</li>
<li><strong>The picker</strong> — on the web a <strong>Select</strong> dropdown whose menu holds <em>Browse…</em>, <em>Browse Resource…</em>
and, only while a path is set, <em>Clear</em>. Either Browse entry opens the in-app File Explorer dialog
filtered to <code>.stl</code>. In the desktop client this is a <strong>Browse</strong> button opening the operating
system's file dialog, beside a <strong>Reload</strong> button and a status line; the web has no Reload.</li>
<li><strong>STL info</strong> — behind an info icon on the web, opening a dialog; a collapsed <em>Information</em>
expander in the desktop client. Both show the triangle count and the bounding box as read-only
vector rows, and the web dialog states an empty case when nothing is loaded.</li>
</ol>
<h2 id="behavior">Behavior</h2>
<ul>
<li><strong>The picker browses the server's named roots, not a file system.</strong> Three roots are exposed —
Project, Resource and Admin — and nothing outside them is reachable.</li>
<li><strong>A pick outside the current project is silently re-homed.</strong> The update endpoint stores
<code>Geom/&lt;filename&gt;</code> rather than the picked location, so saving the project copies the geometry into
the project folder. The consequence is visible: after such a pick the read-only field shows the
re-homed path, not the one that was chosen.</li>
<li><strong>The info dialog refetches on each open</strong>, because the bounding box is computed server-side by
walking the triangles rather than kept resident. Only Min and Max come back from the server;
Dimension and Center are derived in the browser from them.</li>
<li><strong>The picker previews.</strong> Double-clicking an <code>.stl</code> row in the File Explorer dialog swaps its slave
panel to a 3D preview of that file before the pick is confirmed — a capability the desktop file
dialog has no equivalent of. The dialog opens with that panel hidden, which is why the double-click
is the gesture that reaches a preview there; a single click does so only once the toolbar's pencil
has revealed the panel. The preview belongs to the File Explorer rather than to this editor — see
<a class="xref" href="../util/stl-preview-pane.html">STL Preview Pane</a>.</li>
<li><strong>One endpoint ships without a caller.</strong> The controller exposes <code>Reload</code>; nothing in the SPA calls
it.</li>
</ul>
<h2 id="reach">Reach</h2>
<p><code>StlFile</code> is the least restricted geometry kind. It is allowed in every Control-Tree geometry slot —
the fixture's geometry and both of the workpiece's — is one of the container kinds, so it can be a
transformation geometry's inner geometry or a combination child, and it is offered by the two inline
hosts as well: a mechanism anchor's geometry and the cutter's upper beam. The Control-Tree node
carries the referenced file in its own label.</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/geom/StlFileEditor.vue</code> — the editor: the caption, the file-path
input, and the info dialog with its triangle-count badge and four read-only vector rows.</li>
<li><code>wwwroot-src/src/components/widgets/FilePathInput.vue</code> — the picker widget: the Select dropdown
with its Browse, Browse Resource and Clear entries beside a read-only field.</li>
<li><code>wwwroot-src/src/components/widgets/FileExplorerDialog.vue</code> and
<code>wwwroot-src/src/components/FileExplorer.vue</code> — the in-app browser the Browse entries open, and
the row gestures that swap in the STL preview.</li>
<li><code>wwwroot-src/src/components/StlPreviewPane.vue</code> and <code>wwwroot-src/src/api/stlPreview.ts</code> — that
preview and the surface behind it.</li>
<li><code>wwwroot-src/src/components/widgets/Vec3Input.vue</code> — the read-only vector rows in the info dialog.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> — maps the <code>StlFile</code> kind to this editor.</li>
<li><code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the kind picker; it leaves this kind's
label verbatim.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>StlFile</code> against the
sole-editor panel, lists it among the container kinds, and builds the node label that carries the
referenced file.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> and
<code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code> — the kind node's panel and the
parent slot's picker.</li>
<li><code>wwwroot-src/src/components/controlTree/useControlTreeHost.ts</code> — the three tree slots that admit
the kind, and the node-label refresh when the source file changes.</li>
<li><code>wwwroot-src/src/components/geom/TransformationGeomEditor.vue</code>,
<code>wwwroot-src/src/components/geom/GeomCombinationEditor.vue</code>,
<code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> and
<code>wwwroot-src/src/pages/MechBuilderPage.vue</code> — the inline hosts that also admit it.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — <code>getStlFile</code>, <code>getStlFileInfo</code>, <code>setStlFileSource</code> and the
create entry.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> — the <code>stl.*</code> strings and the <code>bounds.*</code> captions shared with
the Box3d editor.</li>
<li><code>Geom/StlFileController.cs</code> — REST endpoints at <code>/api/StlFile/*</code>: <code>New</code>, <code>NewWithPath</code>, <code>Get</code>,
<code>GetInfo</code>, <code>UpdateSourceFile</code>, <code>UpdateSource</code>, <code>Clear</code>, <code>GetFileInfo</code> and <code>Reload</code>. <code>UpdateSource</code>
is where the re-homing happens; <code>GetInfo</code> answers <code>loaded: false</code> when nothing is cached.</li>
<li><code>Common/NamedRootResolver.cs</code> — the three named roots the picker can reach, and the only three.</li>
<li><code>Common/IndexService.cs</code> — the keyed object store every STL file key resolves against.</li>
<li><code>Mech/WorkpieceController.cs</code> — the workpiece slots' create paths.</li>
<li><code>Disp/StlPreviewController.cs</code> and <code>Disp/StlPreviewService.cs</code> — the picker's preview, loaded onto
the caller's own rendering connection and superseded as the selection moves.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard that offers this kind and
hosts this editor</li>
<li><a href="meshed-geom-panel.html">Meshed Geometry Panel</a> — the other file-backed kind, and the one the
workpiece's raw geometry offers beside this one</li>
<li><a class="xref" href="../util/stl-preview-pane.html">STL Preview Pane</a> — the preview the picker opens on an <code>.stl</code> row
before the pick is confirmed</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,49 @@
<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="box3d-control.html" name="" title="Box3d Control">Box3d Control</a>
</li>
<li>
<a href="cylindroid-control.html" name="" title="Cylindroid Control">Cylindroid Control</a>
</li>
<li>
<a href="extended-cylinder-panel.html" name="" title="Extended Cylinder Panel">Extended Cylinder Panel</a>
</li>
<li>
<a href="stlfile-control.html" name="" title="STL File Control">STL File Control</a>
</li>
<li>
<a href="geom-combination-control.html" name="" title="Geometry Combination Control">Geometry Combination Control</a>
</li>
<li>
<a href="meshed-geom-panel.html" name="" title="Meshed Geometry Panel">Meshed Geometry Panel</a>
</li>
<li>
<a href="transformation-geom-control.html" name="" title="Transformation Geometry Control">Transformation Geometry Control</a>
</li>
<li>
<a href="transformer-panel.html" name="" title="Transformer Panel">Transformer Panel</a>
</li>
<li>
<a href="geom-manage-control.html" name="" title="Geometry Management Panel">Geometry Management Panel</a>
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -0,0 +1,2 @@
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"Box3d Control","href":"box3d-control.html","topicHref":"box3d-control.html"},{"name":"Cylindroid Control","href":"cylindroid-control.html","topicHref":"cylindroid-control.html"},{"name":"Extended Cylinder Panel","href":"extended-cylinder-panel.html","topicHref":"extended-cylinder-panel.html"},{"name":"STL File Control","href":"stlfile-control.html","topicHref":"stlfile-control.html"},{"name":"Geometry Combination Control","href":"geom-combination-control.html","topicHref":"geom-combination-control.html"},{"name":"Meshed Geometry Panel","href":"meshed-geom-panel.html","topicHref":"meshed-geom-panel.html"},{"name":"Transformation Geometry Control","href":"transformation-geom-control.html","topicHref":"transformation-geom-control.html"},{"name":"Transformer Panel","href":"transformer-panel.html","topicHref":"transformer-panel.html"},{"name":"Geometry Management Panel","href":"geom-manage-control.html","topicHref":"geom-manage-control.html"}]}
@@ -0,0 +1,218 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Transformation Geometry Control | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Transformation Geometry Control | 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-TransformationGeomControl">
<h1 id="transformation-geometry-control">Transformation Geometry Control</h1>
<p>A <a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a> is an inner geometry plus the transformer that places it, and the
editor is those two things side by side. It has two faces on the web: an embedded two-card editor,
and a Control-Tree panel that shows only the status of each half and puts the editing on child
nodes.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p><strong>Choosing a kind here replaces, it does not wrap.</strong> Picking an inner geometry calls the
container-aware create endpoint, which constructs a fresh instance and discards whatever was
there. Wrapping an existing geometry into a transformation geometry, and extracting it back out,
exists only in the desktop client's
<a href="geom-manage-control.html">Geometry Management Panel</a> Convert menu.</p>
</div>
<h2 id="layout">Layout</h2>
<h3 id="the-embedded-editor">The embedded editor</h3>
<p>Two bordered cards, each badged with the live type behind it, over a short explanation of what a
transformer applied to a geometry means:</p>
<ul>
<li><strong>Inner Geometry</strong> (<code>.../inner-geom</code>) — the full <a href="geom-manage-control.html">Geometry Management Panel</a>,
its dropdown labelled <em>Inner geometry type</em>, over five kinds: Box3d, Cylindroid, StlFile, a nested
TransformationGeom and GeomCombination — which is what makes recursion and nesting legal — plus a
<strong>None (unset)</strong> entry.</li>
<li><strong>Inner Transformer</strong> — the
<a class="xref" href="transformer-panel.html">Transformer Select Panel</a>, mounted with no kind restriction at all, so
its own default of <strong>all seven</strong> transformer kinds applies.</li>
</ul>
<h3 id="the-control-tree-panel">The Control-Tree panel</h3>
<p>Status badges for the two halves and the same explanation, and nothing editable: the tree grows an
<strong>Inner Geometry</strong> slot and an <strong>Inner Transformer</strong> slot as children, and each of those grows its
own kind child. The registry deliberately overrides the kind → editor map here, so the two-card
editor never appears inside a tree.</p>
<h3 id="the-desktop-control">The desktop control</h3>
<p>A geometry-type combo over the inner geometry's own control, and a transformer group box. Its lists
are narrower on both sides: three inner geometry kinds — Box3d, Cylindroid and StlFile, with no
unset entry — and a transformer list restricted to No Transform, Static Translation, Static Freeform
and General Transform. <strong>Static Rotation is unreachable there for a second reason</strong>: the desktop
transformer picker never builds it into its base list, so it is absent whatever the restriction says.</p>
<h2 id="behavior">Behavior</h2>
<ul>
<li><strong>The identity transformer is the floor on the web.</strong> The inner-transformer picker offers no null
entry, and the server installs a <code>NoTransform</code> whenever the field is null, so the slot is never
unset. The desktop panel instead carries a <strong>Not Set</strong> entry, shown by default and never removed by
its type filter, which leaves the slot holding a null transformer.</li>
<li><strong>Creation is container-aware on both halves.</strong> Both go through this type's own create endpoints
rather than the generic per-kind ones, so the owning field is rebound and not merely the store
entry.</li>
<li><strong>Neither client previews.</strong> There is no viewport on this control. It reports edits upward — one
event when a half is mutated, another when a half is replaced — and the hosting page's shared 3D
canvas re-renders from there.</li>
<li><strong>A null inner geometry has a deterministic key anyway.</strong> When the inner geometry is unset the
server returns no key, so the editor falls back to a derived alias; without it the picker could
never create the first geometry.</li>
</ul>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
<ul>
<li><code>wwwroot-src/src/components/geom/TransformationGeomEditor.vue</code> — the embedded editor: the two
cards and their type badges, the two container-aware create hooks, and the fallback alias for a
null inner geometry.</li>
<li><code>wwwroot-src/src/components/controlTree/TransformationGeomTreePanel.vue</code> — the Control-Tree face:
status only.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers the kind against that panel with
a child builder that grows the Inner Geometry and Inner Transformer slots, and is where the
override of the kind → editor map lives.</li>
<li><code>wwwroot-src/src/components/controlTree/GeometrySlotPanel.vue</code>,
<code>wwwroot-src/src/components/controlTree/TransformerSlotPanel.vue</code> and
<code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — the two child slots' pickers and
each kind grandchild's editor.</li>
<li><code>wwwroot-src/src/components/geom/geometryEditors.ts</code> and
<code>wwwroot-src/src/components/geom/GeometryEditor.vue</code> — the kind map that reaches this editor, and
the switchboard it re-enters for its own inner geometry.</li>
<li><code>wwwroot-src/src/components/topo/TransformerSelectPanel.vue</code> and
<code>wwwroot-src/src/components/topo/transformerEditors.ts</code> — the inner-transformer picker and the
seven kinds it offers, with the labels it renders them under.</li>
<li><code>wwwroot-src/src/components/geom/GeomCombinationEditor.vue</code>,
<code>wwwroot-src/src/pages/MechBuilderPage.vue</code> and
<code>wwwroot-src/src/components/toolhouse/UpperBeamDiv.vue</code> — the three embedders of the non-tree
form.</li>
<li><code>wwwroot-src/src/api/geometry.ts</code> — the transformation-geometry DTO, the two index calls and the
two create calls.</li>
<li><code>wwwroot-src/src/api/transformer.ts</code> — the transformer kind union and the per-kind endpoints the
inner transformer's editors bind through.</li>
<li><code>wwwroot-src/src/i18n/en/geom.ts</code> and <code>wwwroot-src/src/i18n/en/tree.ts</code> — the card labels, the
explanation, and the two child-node labels.</li>
<li><code>Geom/TransformationGeomController.cs</code> — REST endpoints at <code>/api/TransformationGeom/*</code>: <code>New</code>,
<code>Get</code>, <code>IndexGeom</code>, <code>IndexTransformer</code>, <code>CreateGeom</code>, <code>CreateTransformer</code>, <code>UpdateTransformer</code>,
<code>GetGeomType</code> and <code>GetTransformerType</code>. <code>IndexGeom</code> answers empty for a null geometry, and
<code>IndexTransformer</code> is where the identity default is installed.</li>
<li><code>Geom/Box3dController.cs</code>, <code>Geom/CylindroidController.cs</code>, <code>Geom/StlFileController.cs</code> and
<code>Geom/GeomCombinationController.cs</code> — the four other inner-geometry kinds' own surfaces.</li>
<li>The seven per-kind transformer controllers under <code>Mech/Topo/</code> — reached by the inner transformer's
editors for their own reads and writes, not for creation, which this type's own endpoint owns.</li>
<li><code>Common/IndexController.cs</code> and <code>Common/IndexService.cs</code> — the type probe both pickers use, and
the store the two aliases are registered into.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../../technique/mechanism/transformers.html">Transformers</a></li>
<li><a href="geom-manage-control.html">Geometry Management Panel</a> — the switchboard this editor embeds for its
inner geometry, and the only place a wrap or extract exists</li>
<li><a class="xref" href="transformer-panel.html">Transformer Select Panel</a> — the inner-transformer picker and its seven
kinds</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,317 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Transformer Select Panel | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Transformer Select 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-Transformers">
<h1 id="transformer-select-panel">Transformer Select Panel</h1>
<p>The Transformer Select Panel is the switchboard that picks which <a class="xref" href="../../api/Hi.Mech.Topo.ITransformer.html">ITransformer</a>
occupies a transformer-valued slot and edits the one that is there. Both clients carry it under the
same name: <code>wwwroot-src/src/components/topo/TransformerSelectPanel.vue</code> on the web,
<code>Mech/Topo/TransformerSelectPanel.xaml</code> on WPF. For the model behind the picker — what each
transformer does to a frame — see
<a class="xref" href="../../technique/mechanism/transformers.html">Handle Transform Matrix by ITransformer</a>.</p>
<h2 id="surface">Surface</h2>
<p>The panel's principal home is a <strong>Transformer slot</strong> of the General Setup page's Control Tree
(<code>/general-setup</code>). Four slots on that tree are Transformer slots:</p>
<ul>
<li><code>equipment/fixture/geom-to-workpiece</code> — &ldquo;Geom To Workpiece&rdquo;</li>
<li><code>equipment/fixture/geom-to-table</code> — &ldquo;Geom To Table&rdquo;</li>
<li><code>equipment/workpiece/anchor/geom-to-fixture</code> — &ldquo;Geom To Fixture&rdquo;</li>
<li><code>equipment/workpiece/anchor/geom-to-program-zero</code> — &ldquo;Geom To Program Zero&rdquo;</li>
</ul>
<p>A fifth shape appears wherever a <a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a> is grown as a tree node: its
<code>.../inner-transformer</code> child is a Transformer slot too.</p>
<p>Two surfaces embed the panel outside any tree — the <a class="xref" href="../util/mech-builder.html">Mechanism Builder Page</a>
(<code>/util/mech-builder</code>), for the selected branch's transformer, and the inner-transformer card of
<a href="transformation-geom-control.html">Transformation Geometry Control</a>.</p>
<h2 id="layout">Layout</h2>
<ul>
<li>Transformer Select Panel
<ul>
<li>Transformer Type Dropdown — one dense, outlined <code>q-select</code> listing the kinds this host allows.
Its label is the host's <code>label</code> prop, falling back to <strong>Transformer type</strong>; the inner-transformer
card labels it <strong>Inner transformer</strong>. Picking a kind commits immediately; there is no Apply button.</li>
<li>Separator — drawn only when a kind is active.</li>
<li>Active Kind's Editor — the component the kind maps to in <code>TRANSFORMER_EDITORS</code>, bound to the
IndexService key the picker resolved for the live transformer.</li>
</ul>
</li>
</ul>
<p>The panel takes a <code>selectorOnly</code> prop that drops everything below the dropdown, which gives it two
forms:</p>
<table>
<thead>
<tr>
<th>Form</th>
<th>Where it is used</th>
<th>What renders</th>
</tr>
</thead>
<tbody>
<tr>
<td>Embedded (default)</td>
<td>Mechanism Builder page; the inner-transformer card of <code>TransformationGeomEditor.vue</code></td>
<td>dropdown, separator, and the active kind's editor in one column</td>
</tr>
<tr>
<td>Selector only</td>
<td>every Control-Tree Transformer slot, through <code>TransformerSlotPanel.vue</code></td>
<td>the dropdown alone</td>
</tr>
</tbody>
</table>
<p>In a Control Tree the picker and the editor sit on two different nodes. <code>buildTransformerChildren()</code>
grows <strong>at most one</strong> child under the slot, typed with the current kind, and that child's panel is
<code>SoleEditorPanel.vue</code>, which resolves the kind through the same <code>TRANSFORMER_EDITORS</code> map and binds
it to the slot's own key. The builder first probes the slot's key with <code>getIndexType</code> and returns no
child at all when that probe fails or names a type outside the seven kinds, so a slot holding
nothing is a picker with nothing beneath it. Selecting the slot shows the picker; selecting the
child shows the kind's editor.</p>
<h3 id="transformer-type-dropdown">Transformer Type Dropdown</h3>
<p>The dropdown gets and sets the <a class="xref" href="../../api/Hi.Mech.Topo.ITransformer.html">ITransformer</a> behind the bound key. On mount, and
again whenever that key changes, it probes the object's type with <code>getIndexType</code>; picking a different
kind creates the replacement through <code>POST /api/{Kind}/New</code> unless the host supplied an <code>onCreate</code>
hook, in which case that hook runs instead so the owning domain object is rebound alongside the
IndexService entry.</p>
<p>Which kinds it offers is the <code>allowedKinds</code> prop, defaulting to all seven. A Control-Tree slot feeds
it from the node's <code>ctx.allowedKinds</code>; none of the four General Setup slots narrows it, so all seven
appear there. The WPF panel restricts through four properties on its code-behind instead:
<code>AllowedTransformerTypes</code>, <code>SelectionFilter</code>, <code>ShowNoTransform</code> and <code>ShowNotSet</code>.</p>
<p>When the probed kind falls outside <code>allowedKinds</code>, both the active and the selected kind reset to
empty: the dropdown blanks, and the embedded form prints <em>No transformer attached.</em> in place of an
editor. The out-of-list transformer is not rendered. The WPF client resolves that case the other
way — <code>UpdateUI()</code> leaves the combo unselected when no item matches, then still calls
<code>UpdateTransformerPanel()</code> and builds the current transformer's content panel.</p>
<h2 id="transformer-kinds">Transformer Kinds</h2>
<p>The web client offers seven kinds, one editor each.</p>
<table>
<thead>
<tr>
<th>Kind</th>
<th>Editor</th>
<th>What the editor holds</th>
</tr>
</thead>
<tbody>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.StaticTranslation.html">StaticTranslation</a></td>
<td><code>StaticTranslationEditor.vue</code></td>
<td>one Vec3 input, the constant offset</td>
</tr>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.StaticRotation.html">StaticRotation</a></td>
<td><code>StaticRotationEditor.vue</code></td>
<td>axis Vec3 input (with Normalize), angle in degrees, pivot Vec3 input</td>
</tr>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.StaticFreeform.html">StaticFreeform</a></td>
<td><code>StaticFreeformEditor.vue</code></td>
<td>a 4×4 matrix grid with Identity and Invert (stored column-major, displayed row-major)</td>
</tr>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.DynamicTranslation.html">DynamicTranslation</a></td>
<td><code>DynamicTranslationEditor.vue</code></td>
<td>axis Vec3 input (with Normalize) and a step in mm</td>
</tr>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.DynamicRotation.html">DynamicRotation</a></td>
<td><code>DynamicRotationEditor.vue</code></td>
<td>axis Vec3 input (with Normalize), angle in degrees, pivot Vec3 input</td>
</tr>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.GeneralTransform.html">GeneralTransform</a></td>
<td><code>GeneralTransformEditor.vue</code></td>
<td>a scale field over two embedded sub-transformer cards</td>
</tr>
<tr>
<td><a class="xref" href="../../api/Hi.Mech.Topo.NoTransform.html">NoTransform</a></td>
<td><code>NoTransformEditor.vue</code></td>
<td>an identity-transform notice; no controls</td>
</tr>
</tbody>
</table>
<p>The WPF client offers six of them — <code>NoTransform</code>, <code>StaticTranslation</code>, <code>StaticFreeform</code>,
<code>GeneralTransform</code>, <code>DynamicTranslation</code>, <code>DynamicRotation</code> — plus a <em>Not Set</em> entry that leaves the
slot holding a null transformer. It has no <code>StaticRotation</code> panel, and selecting <code>NoTransform</code> there
simply empties its content area. The web picker offers no null entry of either sort: identity is
expressed by choosing <code>NoTransform</code>.</p>
<div class="NOTE">
<h5>Note</h5>
<p>The <a class="xref" href="../../api/Hi.Mech.Topo.GeneralTransform.html">GeneralTransform</a> editor is a composition, not a flat form: a scale field,
then the <a class="xref" href="../../api/Hi.Mech.Topo.StaticRotation.html">StaticRotation</a> and <a class="xref" href="../../api/Hi.Mech.Topo.StaticTranslation.html">StaticTranslation</a> editors
embedded in their own bordered cards, titled <em>Rotation sub-transformer</em> and <em>Translation
sub-transformer</em>. It keys the two sub-editors off <code>POST /api/GeneralTransform/IndexRotation</code> and
<code>/IndexTranslation</code>, edits the scale itself, and owns no vector widget — every
<a class="xref" href="../../api/Hi.Geom.Vec3d.html">Vec3d</a> field on it comes from the nested editors. The effective transform is
<code>T × R × scale × I</code>. Its WPF counterpart <code>Mech/Topo/GeneralTransformPanel.xaml</code> takes the other
approach: three Vec3dControls of its own (translation, rotation axis, rotation pivot) plus scale
and angle text boxes, embedding no sub-panel.</p>
</div>
<h2 id="key-model">Key Model</h2>
<ul>
<li><a class="xref" href="../../api/Hi.Mech.Topo.ITransformer.html">ITransformer</a> — the interface the slot holds and the dropdown swaps.</li>
<li><a class="xref" href="../../api/Hi.Mech.Topo.StaticTranslation.html">StaticTranslation</a>, <a class="xref" href="../../api/Hi.Mech.Topo.StaticRotation.html">StaticRotation</a>,
<a class="xref" href="../../api/Hi.Mech.Topo.StaticFreeform.html">StaticFreeform</a>, <a class="xref" href="../../api/Hi.Mech.Topo.DynamicTranslation.html">DynamicTranslation</a>,
<a class="xref" href="../../api/Hi.Mech.Topo.DynamicRotation.html">DynamicRotation</a>, <a class="xref" href="../../api/Hi.Mech.Topo.GeneralTransform.html">GeneralTransform</a> and
<a class="xref" href="../../api/Hi.Mech.Topo.NoTransform.html">NoTransform</a> — the seven implementations the web picker lists.</li>
<li><a class="xref" href="../../api/Hi.Geom.Vec3d.html">Vec3d</a> — the axis, pivot and translation fields the static and dynamic editors bind.</li>
</ul>
<h2 id="source-code-path">Source Code Path</h2>
<p>See <a class="xref" href="../index.html">HiNC App Anatomy</a> for git repository links.</p>
<p>The switchboard and its editors:</p>
<ul>
<li><code>wwwroot-src/src/components/topo/TransformerSelectPanel.vue</code> — the picker, the create call and the
optional inline editor; props <code>modelKey</code> / <code>label</code> / <code>allowedKinds</code> / <code>onCreate</code> / <code>selectorOnly</code>,
events <code>changed</code> / <code>typeChanged</code> / <code>error</code>.</li>
<li><code>wwwroot-src/src/components/topo/transformerEditors.ts</code> — <code>TRANSFORMER_EDITORS</code>, the single kind →
editor map, plus <code>isTransformerKind()</code> and <code>humanizeTransformerKind()</code>.</li>
<li><code>wwwroot-src/src/components/topo/StaticTranslationEditor.vue</code></li>
<li><code>wwwroot-src/src/components/topo/StaticRotationEditor.vue</code></li>
<li><code>wwwroot-src/src/components/topo/StaticFreeformEditor.vue</code></li>
<li><code>wwwroot-src/src/components/topo/DynamicTranslationEditor.vue</code></li>
<li><code>wwwroot-src/src/components/topo/DynamicRotationEditor.vue</code></li>
<li><code>wwwroot-src/src/components/topo/GeneralTransformEditor.vue</code></li>
<li><code>wwwroot-src/src/components/topo/NoTransformEditor.vue</code></li>
</ul>
<p>The Control-Tree glue and the two direct embedders:</p>
<ul>
<li><code>wwwroot-src/src/components/controlTree/TransformerSlotPanel.vue</code> — the slot's panel: this
switchboard in selector-only mode, fed <code>allowedKinds</code> and <code>onCreate</code> from the node context.</li>
<li><code>wwwroot-src/src/components/controlTree/SoleEditorPanel.vue</code> — the kind node's panel.</li>
<li><code>wwwroot-src/src/components/controlTree/itemTypes.ts</code> — registers <code>Transformer</code> as a slot type with
<code>buildTransformerChildren</code>, and each of the seven kinds against <code>SoleEditorPanel</code>.</li>
<li><code>wwwroot-src/src/pages/MechBuilderPage.vue</code> — embeds the panel for the selected branch.</li>
<li><code>wwwroot-src/src/components/geom/TransformationGeomEditor.vue</code> — embeds it for the inner transformer.</li>
</ul>
<p>The transport and the strings:</p>
<ul>
<li><code>wwwroot-src/src/api/transformer.ts</code> — the <code>TransformerKind</code> union, the per-kind <code>/api/{Kind}/New</code>
create endpoints, and the typed wrappers for every update and <code>Index*</code> call.</li>
<li><code>wwwroot-src/src/i18n/en/topo.ts</code> — every string on these panels, including
<code>topo.select.noTransformer</code>. Transformer type names are identity and stay verbatim.</li>
</ul>
<p>The REST controllers, one per kind:</p>
<ul>
<li><code>Mech/Topo/StaticTranslationController.cs</code></li>
<li><code>Mech/Topo/StaticRotationController.cs</code></li>
<li><code>Mech/Topo/StaticFreeformController.cs</code></li>
<li><code>Mech/Topo/DynamicTranslationController.cs</code></li>
<li><code>Mech/Topo/DynamicRotationController.cs</code></li>
<li><code>Mech/Topo/GeneralTransformController.cs</code> — also serves <code>IndexRotation</code> and <code>IndexTranslation</code>.</li>
<li><code>Mech/Topo/NoTransformController.cs</code> — <code>New</code> and <code>Get</code>; there is nothing on a <code>NoTransform</code> to update.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a class="xref" href="../util/mech-builder.html">Mechanism Builder Page</a> — edits a mechanism’s per-branch transformer through this switchboard</li>
<li><a href="transformation-geom-control.html">Transformation Geometry Control</a> — embeds this picker as its inner
transformer, with no kind restriction at all</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>