deploy.
This commit is contained in:
@@ -89,7 +89,7 @@
|
||||
|
||||
<p><code>HiNC-2025-webservice/wwwroot-src/src</code> is the flagship front end: a Quasar CLI single-page
|
||||
application in Vue 3, TypeScript and Pinia, served by the same ASP.NET Core process that answers its
|
||||
REST calls. Every page in Anatomy outside the desktop map documents something in this tree.</p>
|
||||
REST calls. Every page in Anatomy documents something in this tree or in the backend beside it.</p>
|
||||
<p>Folders below follow the stock Quasar skeleton order, with the two places the skeleton breaks called
|
||||
out where they occur.</p>
|
||||
<h2 id="the-one-thing-to-know-first">The One Thing to Know First</h2>
|
||||
|
||||
@@ -104,30 +104,18 @@
|
||||
</ul>
|
||||
<p>Then you should keep the Protability.</p>
|
||||
<h2 id="file-path-of-load-button-and-save-button">File Path of Load Button and Save Button</h2>
|
||||
<p>The genneral convention of the File Path of Load and Save is different by the single-user desktop application and web page application.</p>
|
||||
<div class="TIP">
|
||||
<h5>Tip</h5>
|
||||
<p>Always preserve an empty filter ( * . * ) for the browser.</p>
|
||||
</div>
|
||||
<h3 id="single-user-desktop-application">Single-User Desktop Application</h3>
|
||||
<p>The default directory of the Save/Load button are generally:</p>
|
||||
<ul>
|
||||
<li>System Default Directory or Project Directory (default, if not explicitly indicated)
|
||||
The initial directory is the project directory.</li>
|
||||
<li>Resource Directory
|
||||
The path always point to <code><application path>/Resource/<classification></code> directory.
|
||||
The button label has to explicitly show ‘Load Resource’.</li>
|
||||
</ul>
|
||||
<p>The kinds of buttons are not exclusive, they can be existed on the same tool bar.</p>
|
||||
<p>If the selected file path is under the project directory, apply the relative path from the project, i.e. baseDirectory is project directory and relFile is the relative path.</p>
|
||||
<h3 id="web-page-application">Web Page Application</h3>
|
||||
<p>The default directory of the Save/Load button are generally:</p>
|
||||
<p>A Load or Save button opens the browser at one of three roots:</p>
|
||||
<ul>
|
||||
<li>Admin Directory</li>
|
||||
<li>Project Directory</li>
|
||||
<li>Resource Directory</li>
|
||||
</ul>
|
||||
<p>The Resource Directory and Project Directory are generally under the Admin Directory. And the admin directory is generally set in the appsettings.json file.</p>
|
||||
<p>The Resource Directory and Project Directory are generally under the Admin Directory, and the admin directory is generally set in the appsettings.json file. The kinds of button are not exclusive — several may sit on the same tool bar — and a button that opens the Resource root has to say so in its label.</p>
|
||||
<p>If the selected file path is under the project directory, apply the relative path from the project: <code>baseDirectory</code> is the project directory and <code>relFile</code> is the relative path.</p>
|
||||
<div class="TIP">
|
||||
<h5>Tip</h5>
|
||||
<p>Always preserve an empty filter ( * . * ) for the browser.</p>
|
||||
</div>
|
||||
<h2 id="typical-action-if-exhibitiononly-false">Typical Action if <code>exhibitionOnly</code> false</h2>
|
||||
<p>On <a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html">IMakeXmlSource</a>.<a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html#Hi_Common_XmlUtils_IMakeXmlSource_MakeXmlSource_System_String_System_String_System_Boolean_">MakeXmlSource(string, string, bool)</a> with <code>exhibitionOnly</code> false, the argument (<code>baseDirectory</code> and <code>relFile</code>) should be the same from object's host (if exist) XML output function.</p>
|
||||
|
||||
|
||||
@@ -164,16 +164,11 @@ MIME-ish strings (<code>STL</code>, <code>*.hincproj</code>) · units (<code>mm<
|
||||
localStorage keys and series identifiers — anything a machine compares. Language self-names
|
||||
(English, 简体中文, 繁體中文) stay in their own language in every locale. The full list lives with
|
||||
the bundles, in the i18n folder's README.</p>
|
||||
<h2 id="terms-carried-by-the-desktop-client">Terms Carried by the Desktop Client</h2>
|
||||
<p>Three milling-cutter surfaces exist only on the WPF client, and their terms belong to the same
|
||||
contract, so none of the words is reused elsewhere:</p>
|
||||
<ul>
|
||||
<li>Insert-Cutter 刀片 — a tab on <code>Mech/ToolHouse/MillingCutterPanel.xaml</code></li>
|
||||
<li>Flute-Inner-Beam 刃中芯 — the tab served by <code>Mech/ToolHouse/FluteInnerBeamPanel.xaml</code></li>
|
||||
<li>Cutter Integral Mode 刀頭形式 — a labelled tab there as well; the web application carries the
|
||||
same choice as the <code>integralMode</code> datum, which decides whether the Tool House material section
|
||||
offers a separate shank material, and shows no label of its own</li>
|
||||
</ul>
|
||||
<h2 id="a-choice-that-carries-no-label">A Choice That Carries No Label</h2>
|
||||
<p>The cutter's integral mode reaches the web application as the <code>integralMode</code> datum rather than as a
|
||||
named field: it decides whether the Tool House material section offers a separate shank material,
|
||||
and shows no label of its own. A term with no visible string is still part of the contract — it has
|
||||
to be settled before anything renders a value derived from it.</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>
|
||||
<ul>
|
||||
|
||||
@@ -105,9 +105,8 @@
|
||||
<p>In the web application the status text moved out of the tool bar and onto the Execution tree item, which carries the run-state badge. The two single-advance buttons there share one <code>skip_next</code> icon and are separated by a letter drawn into the button's corner — <code>L</code> for the line button, <code>S</code> for the step button — rather than by colour; the tool-tips carry the key names.</p>
|
||||
<h2 id="behavior">Behavior</h2>
|
||||
<ul>
|
||||
<li>Both the webservice and the win-desktop application watch <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html">LocalProjectService</a> events to track <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_PacePlayer">PacePlayer</a> status changes.</li>
|
||||
<li>The webservice watches <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html">LocalProjectService</a> events to track <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_PacePlayer">PacePlayer</a> status changes.</li>
|
||||
<li>In the webservice, <code>ExecutionStatusService</code> subscribes to those events and broadcasts status changes over SignalR through <code>ExecutionStatusHub</code>.</li>
|
||||
<li>The win-desktop application subscribes to the same <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html">LocalProjectService</a> events directly.</li>
|
||||
<li>The frequently used buttons carry hotkeys: Start / Resume, Pause, Run One Line and Run One Step. The app's tool-tips are the only place those key bindings are written down.</li>
|
||||
<li>The background color of the <code>Status Text Field</code> follows the status:
|
||||
<ul>
|
||||
@@ -154,7 +153,7 @@
|
||||
<p>The F5–F8 handler applies the same predicates before acting, and declines in two more cases: when the event target is an <code>input</code>, a <code>textarea</code> or a contenteditable element, and when the hosting page is deactivated. The second matters because the shell keep-alives the routed pages, so leaving the Execution route deactivates rather than unmounts this component; without the detach, F5 elsewhere in the app would drive the transport instead of reloading the browser. Every declined key falls through to the browser.</p>
|
||||
<div class="TIP">
|
||||
<h5>Tip</h5>
|
||||
<p>Use icons rather than text on the tool-bar buttons. Run One Line and Run One Step share an icon, so they need a second mark to tell them apart — the win-desktop application seasons the icon green and blue, the web application draws an <code>L</code> and an <code>S</code> in the button corner. Either works; the default colour is enough for the rest.</p>
|
||||
<p>Use icons rather than text on the tool-bar buttons. Run One Line and Run One Step share an icon, so they need a second mark to tell them apart — this bar draws an <code>L</code> and an <code>S</code> in the button corner. The default colour is enough for the rest.</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>
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
|
||||
<h2 id="shipped-surface">Shipped Surface</h2>
|
||||
<p>The panel has no route and no Control-Tree node of its own. It is chrome on the Execution page (<code>/execution</code>): the canvas panel's expansion header carries the <code>Meshed Geom ▾</code> dropdown — titled <em>Workpiece rendering cache and geometry-diff settings</em> — whose <code>Graphic Cache</code> row opens this panel in a nested menu. It hangs there because it acts on the workpiece meshed geometry's rendering cache, and its sibling row in the same dropdown is <code>Diff Visual Radius</code>. It is therefore only reachable while the Execution page's canvas column is shown.</p>
|
||||
<p>In the WPF application the same submenu lives on the <a class="xref" href="../shell/preference-menu.html">Preference Menu Dropdown</a>.</p>
|
||||
<p>The panel is self-contained: it takes no parent-supplied model. It holds local lower / upper / current values, loads them on mount, and commits each edit to <code>GET</code>/<code>POST /api/preference/graphic-cache</code>. <code>UserService</code> / <code>UserConfig</code> is the server-side model behind that endpoint.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<p>Titled <strong>Graphic Cache (MB)</strong>, with the caption “Memory budget for rendering cache. Lower & upper bound the slider.”</p>
|
||||
@@ -125,7 +124,7 @@
|
||||
</ul>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../shell/preference-menu.html">Preference Menu Dropdown</a> — the dropdown that hosts this entry in the WPF client</li>
|
||||
<li><a class="xref" href="../shell/preference-menu.html">Preference Menu Dropdown</a> — the sibling entries of the same dropdown</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
@@ -205,36 +205,6 @@ carrying no title of its own still reads as its localized display name.</p>
|
||||
pane. The draggable vertical divider on screen belongs to the Execution page, between the left dock
|
||||
— the Control Tree over the editor panel — and the central area; a second divider inside that dock
|
||||
drags the height between the tree and the editor.</p>
|
||||
<h2 id="the-wpf-clients-list-panel">The WPF Client's List Panel</h2>
|
||||
<p>The WPF panel edits the <strong>root</strong> list only. It binds the project's player command as a list, its Add
|
||||
menu offers no List item, and its content switch has no List arm, so a nested list entry selected
|
||||
there renders the literal text “No editor available for ListCommand”. Nesting is a web surface.</p>
|
||||
<ul>
|
||||
<li>Two columns: a 400px entry column, a <code>GridSplitter</code>, and the selected command's content column,
|
||||
both columns floored at 300px.</li>
|
||||
<li>One toolbar over the list — Add, Remove, Move Up, Move Down — acting on the list selection. There
|
||||
is no duplicate.</li>
|
||||
<li>Add is a plain button that pops a fixed six-item context menu built in its click handler:
|
||||
“Pre-Setting Command”, “NC Opt Option Command”, “NC File Command”, “NC Code Command”,
|
||||
“Script Command” and “Post Execution Command”.</li>
|
||||
<li>The list box is extended-select. Remove takes every selected entry, prompting with a count when
|
||||
more than one is selected, and a drag can carry a whole selection; Move Up and Move Down stay
|
||||
disabled unless exactly one entry is selected.</li>
|
||||
<li>Each entry box carries a labelled Enable checkbox at its left, the command's title in bold, and a
|
||||
pin icon with a “Pin at beginning” / “Pin at end” label — shown on the first entry when it is a
|
||||
General Config command, and on the last when it is a Post-Execution command.</li>
|
||||
<li>Insertion works around the ends: a new entry lands before a trailing Post-Execution when that is
|
||||
the list's only one, and a General Config lands at the top unless the list already starts with
|
||||
one. A drag that would move a pinned entry — or drop another entry onto it — is refused, the guard
|
||||
testing that the entry is the only command of its kind and sits at that end. The Move Up / Move
|
||||
Down buttons are not covered by that guard.</li>
|
||||
<li>The content panel is greyed and made read-only while the selected entry's Enable box is clear.</li>
|
||||
<li>Files dropped from the file explorer onto the entry list create one enabled NC File command per
|
||||
file, taking a project-relative path when the file sits under the project directory.</li>
|
||||
<li>The entry label falls back to the raw class name for a command that composes no title of its
|
||||
own — <code>GeomDiffCommand</code>, <code>OptimizeToFilesCommand</code>, <code>WriteStepFilesCommand</code> and
|
||||
<code>WriteShotFilesCommand</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>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
|
||||
@@ -118,9 +118,8 @@ mission row.</li>
|
||||
<li>NC Code Editor Area
|
||||
<ul>
|
||||
<li>The model is <a class="xref" href="../../../api/Hi.SessionCommands.NcCodeCommand.html#Hi_SessionCommands_NcCodeCommand_NcText">NcText</a>.</li>
|
||||
<li>A plain monospace text area: on the web an 18-row field with a 360 px floor, on WPF a Consolas
|
||||
text box in an NC Code group box that takes the panel's remaining height.</li>
|
||||
<li>No line-number gutter and no syntax highlighting on either client. The rich editor in this
|
||||
<li>A plain monospace text area: an 18-row field with a 360 px floor.</li>
|
||||
<li>No line-number gutter and no syntax highlighting. The rich editor in this
|
||||
folder is the <a class="xref" href="script-command-panel.html">Script command</a>'s — that command ships
|
||||
CodeMirror with a C# grammar, this one ships a text area.</li>
|
||||
</ul>
|
||||
|
||||
@@ -97,9 +97,8 @@ into the project itself.</p>
|
||||
and an absolute path on the server is accepted just as well. No base directory is stored with the
|
||||
command: at play time <a class="xref" href="../../../api/Hi.MachiningProcs.SessionShell.html#Hi_MachiningProcs_SessionShell_RunNcFile_">RunNcFile</a> hands the stored path
|
||||
together with the project's own base directory to the local project service, and that is where a
|
||||
relative path acquires its root. The WPF panel's <code>BaseDirectory</code> is the code-behind assistant
|
||||
property the <a class="xref" href="../../conventions/gui-file-path-assignment.html">Load Pattern</a> asks a file-assigning GUI to carry,
|
||||
assigned to the panel by its parent — a panel member, not a model member.</p>
|
||||
relative path acquires its root; the convention behind it is the
|
||||
<a class="xref" href="../../conventions/gui-file-path-assignment.html">Load Pattern</a>.</p>
|
||||
<p>The panel renders on the command's own node in the Mission branch of the Execution page's Control
|
||||
Tree, below the move / duplicate / delete control bar. This command has no title of its own, so the
|
||||
row and tree label read <code>Program File [path]</code>, the path being the detail the label brackets.</p>
|
||||
@@ -124,8 +123,7 @@ as CSV, and every other extension as brand NC).</p>
|
||||
the project folder.</li>
|
||||
<li>Every keystroke saves the path. Leaving the field or pressing Enter additionally refreshes
|
||||
the file-info banner.</li>
|
||||
<li>The web field flexes to fill the row beside the Browse button at any panel width; the WPF
|
||||
field is a fixed 200 px column carrying its own label.</li>
|
||||
<li>The field flexes to fill the row beside the Browse button at any panel width.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Browse Button
|
||||
@@ -140,8 +138,6 @@ field is a fixed 200 px column carrying its own label.</li>
|
||||
<li>The model is <a class="xref" href="../../../api/Hi.SessionCommands.NcFileCommand.html#Hi_SessionCommands_NcFileCommand_NcKind">NcKind</a>.</li>
|
||||
<li>Four choices: Auto (by extension), Brand NC, CL (CLSF) and CSV. The hint restates what Auto
|
||||
detects, so the runner can be pinned when the extension would route the file elsewhere.</li>
|
||||
<li>This control is the web client's. The WPF panel ships no kind control, so a project edited
|
||||
there keeps the kind it already holds — Auto until something else sets it.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>File Info Banner
|
||||
@@ -180,9 +176,6 @@ browser to preserve. It is the backstop for a brand extension the NC group does
|
||||
</ul>
|
||||
<p>CL and CSV are split out because they are closed extension sets: those are exactly the extensions
|
||||
Auto routes to the CL and CSV runners, and everything else falls through to brand NC.</p>
|
||||
<p>The WPF Browse button opens an <code>OpenFileDialog</code> with the panel's file-filter resource, starting at
|
||||
the project directory or at the current file's own directory. A pick under the project directory is
|
||||
stored as a relative path, and a pick outside it as an absolute one.</p>
|
||||
<h2 id="multi-pick-fan-out">Multi-Pick Fan-Out</h2>
|
||||
<p>The dialog is multi-select, and this is the one command editor that grows the mission. The first
|
||||
picked file lands on this command. Each further pick becomes a <strong>new</strong> Program File command, added
|
||||
@@ -191,18 +184,9 @@ list, so a command inside a nested list fans out inside that nested list. The pa
|
||||
structure change, which rebuilds the owning list's branch around the new rows and leaves the
|
||||
selection on this command.</p>
|
||||
<h2 id="where-the-program-text-is-edited">Where the Program Text Is Edited</h2>
|
||||
<p>The two clients part company here, and the command is the same either way: it stores a path.</p>
|
||||
<ul>
|
||||
<li><strong>Web</strong> — the panel does not edit the file. It assigns the path, picks the runner, reports what
|
||||
the server knows about the file, and previews its first 100 lines read-only. Nothing in the
|
||||
browser writes NC bytes back; the two file endpoints this panel calls are both reads.</li>
|
||||
<li><strong>WPF</strong> — the panel opens the file. A non-text file, or one the panel cannot find, disables the
|
||||
editor and states why in the Head Message Place above it. A text file within 20000 lines opens for
|
||||
editing, with its line count in the group-box header; a longer one shows its first 20000 lines
|
||||
read-only and warns in the Head Message Place. Two seconds after the last keystroke the editor
|
||||
writes the file back, and reports the save in that same message place. The editor is AvalonEdit
|
||||
with line numbers where that assembly resolves, and a plain Consolas text box otherwise.</li>
|
||||
</ul>
|
||||
<p>The command stores a path, and the panel does not edit the file. It assigns the path, picks the
|
||||
runner, reports what the server knows about the file, and previews its first 100 lines read-only.
|
||||
Nothing in the browser writes NC bytes back; the two file endpoints this panel calls are both reads.</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>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
|
||||
@@ -94,7 +94,7 @@ preference. <code>Run</code> assigns the command's option object onto the sessio
|
||||
<code>sessionShell.NcOptOption = NcOptOption</code> — so the settings take effect at the point the entry sits
|
||||
in the list. Everything played below it optimizes under them, and a second NC Optimization Config
|
||||
further down the list re-points them mid-mission.</p>
|
||||
<p>The command carries no title on either client. Its row and its tree label always read
|
||||
<p>The command carries no title. Its row and its tree label always read
|
||||
<code>NC Optimization Config</code>: <code>GetCommandTitle</code> returns that fixed name and takes nothing from the user.</p>
|
||||
<h2 id="where-it-renders">Where It Renders</h2>
|
||||
<p>The web client has one editor component for this command and mounts it once per tree node, each
|
||||
@@ -126,7 +126,6 @@ command — a disabled command is skipped during play and stays fully editable.<
|
||||
<li>Enable Depth Splition CheckBox
|
||||
<ul>
|
||||
<li>The model is <a class="xref" href="../../../api/Hi.NcOpt.NcOptOption.html#Hi_NcOpt_NcOptOption_EnableDepthSplition">EnableDepthSplition</a>.</li>
|
||||
<li>The desktop client labels the same switch “Enable Depth Splitting”.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Enable Interpolation CheckBox
|
||||
@@ -327,11 +326,6 @@ feed per tooth or preferred force survives a project save and reload.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="the-two-clients">The Two Clients</h2>
|
||||
<p>The desktop client edits the same command in one scrolling panel of six group boxes, and it names 17
|
||||
of the model's options — the four enable switches, the two distances, the three feedrates,
|
||||
acceleration and jerk, Preferred Force with the two spindle safety factors, and the three
|
||||
compensation switches.</p>
|
||||
<p>The web client edits five more, and that is the whole difference between the two editors: Min Feed
|
||||
Per Tooth, Max Feed Per Tooth and Feedrate Assignment Ratio in the Feedrate section, and Yielding
|
||||
Safety Factor and Thermal Yield Safety Factor in Force & Safety.</p>
|
||||
|
||||
+3
-14
@@ -87,8 +87,7 @@
|
||||
<article data-uid="Anatomy-PostExecutionCommandPanel">
|
||||
<h1 id="postexecutioncommand-panel-post-execution">PostExecutionCommand Panel (Post-Execution)</h1>
|
||||
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.SessionCommands.PostExecutionCommand.html">PostExecutionCommand</a>, the command both clients label
|
||||
<strong>Post-Execution</strong>. It is the Output category's first catalog entry, and it carries five outputs
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.SessionCommands.PostExecutionCommand.html">PostExecutionCommand</a>, labelled <strong>Post-Execution</strong>. It is the Output category's first catalog entry, and it carries five outputs
|
||||
derived from what the session has played: step files, shot files, optimization files, a CL → NC
|
||||
writeback, and a geometry-difference detection.</p>
|
||||
<h2 id="when-it-runs-and-what-it-covers">When It Runs, and What It Covers</h2>
|
||||
@@ -103,9 +102,7 @@ command before this command — and it re-serializes every control file the sess
|
||||
play is written back too. Read this together with
|
||||
<a class="xref" href="PreSettingCommand-panel.html">General Config</a>, the other half of the pair: those settings
|
||||
apply from their position forward, these outputs cover everything up to this position.</p>
|
||||
<p>The web client places the command anywhere in the list, like any other. The WPF client pins it to
|
||||
the end: a new command is inserted before a trailing Post-Execution while that is the list's only
|
||||
one, and the drag guard refuses to move it off the last position.</p>
|
||||
<p>The command sits anywhere in the list, like any other; nothing pins it to the end.</p>
|
||||
<p><code>Run</code> executes the enabled outputs in an order of its own, which is <strong>not</strong> the order the tree and
|
||||
the list below show them in: shot files, then step files, then optimization, then the CL → NC
|
||||
writeback, then the geometry difference. Output timestamps follow that order rather than the layout.</p>
|
||||
@@ -218,14 +215,6 @@ carries the catalog attribute, so they load from a project file but are not offe
|
||||
Command dialog. Post-Execution is the catalogued carrier of these outputs, which is why they are
|
||||
edited as its sections.</p>
|
||||
</div>
|
||||
<h2 id="the-wpf-clients-panel">The WPF Client's Panel</h2>
|
||||
<p>There four of the outputs are group boxes on one panel, each an enable checkbox over a grid that is
|
||||
disabled until the box is ticked: Step Files Output, Shot Files Output, Optimization Output and
|
||||
Geometry Difference Detection. The physics condition collapses the Shot Files and Optimization group
|
||||
boxes rather than omitting tree nodes.</p>
|
||||
<p>CL → NC Writeback is the one output the web client has and this panel does not. Its two properties
|
||||
live on the same engine command, and the web section and its two endpoints are where they are
|
||||
edited.</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>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
@@ -251,7 +240,7 @@ overview caption and the writeback paragraph.</li>
|
||||
<li><code>wwwroot-src/src/stores/appState.ts</code> — the physics preference and licence flags the tree builder
|
||||
reads.</li>
|
||||
<li><code>Environments/PreferenceController.cs</code> — serves the physics preference already combined with the
|
||||
advanced-physics licence, the same condition the WPF panel evaluates.</li>
|
||||
advanced-physics licence.</li>
|
||||
<li><code>Missions/MissionController.cs</code> — the <code>commands/{path}/postexecution/*</code> endpoints: the five enable
|
||||
flags, the four templates, the shot-file time resolution and the geom-diff detect radius.</li>
|
||||
</ul>
|
||||
|
||||
@@ -87,18 +87,12 @@
|
||||
<article data-uid="Anatomy-PreSettingCommandPanel">
|
||||
<h1 id="presettingcommand-panel-general-config">PreSettingCommand Panel (General Config)</h1>
|
||||
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.SessionCommands.PreSettingCommand.html">PreSettingCommand</a>, the command both clients label
|
||||
<strong>General Config</strong>. It is one command carrying a bundle of session settings — the machining
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.SessionCommands.PreSettingCommand.html">PreSettingCommand</a>, labelled <strong>General Config</strong>. It is one command carrying a bundle of session settings — the machining
|
||||
resolution, the machining motion resolution, collision detection, pause on failure, physics — plus
|
||||
an optional read of a meshed-geometry file.</p>
|
||||
<h2 id="where-a-general-config-comes-from">Where a General Config Comes From</h2>
|
||||
<p>The two clients differ on how a mission acquires these settings, and that difference is the first
|
||||
thing to know about this panel.</p>
|
||||
<p>The WPF client creates the bundle. Its Add menu carries a hard-coded item that constructs a
|
||||
<code>PreSettingCommand</code>, and the insert rule pins it to the top of the list: a new General Config lands
|
||||
at index 0 unless the list already starts with one, and while it is the list's only General Config
|
||||
the drag guard refuses to move it off that position.</p>
|
||||
<p>The web client's Add Command dialog is served by the server's command catalog, which reflects every
|
||||
<p>How a mission acquires these settings is the first thing to know about this panel.</p>
|
||||
<p>The Add Command dialog is served by the server's command catalog, which reflects every
|
||||
engine command carrying <code>[CommandCatalog]</code>. <code>PreSettingCommand</code> carries no such attribute, so the
|
||||
dialog cannot produce one — the catalog keeps <code>presetting</code> only as a readable kind key, and creating
|
||||
a command looks the kind up in the addable set alone. What the web offers instead is the same
|
||||
@@ -212,21 +206,6 @@ project is loaded or assigned — not on a runtime reset and not when the workpi
|
||||
an explicit setting survives both. This command carries its own value, and overwrites the
|
||||
session's with it at the moment the command runs.</p>
|
||||
</div>
|
||||
<h2 id="the-wpf-clients-panel">The WPF Client's Panel</h2>
|
||||
<p>There the whole bundle is one panel, in two group boxes.</p>
|
||||
<ul>
|
||||
<li><strong>Meshed Geometry Settings</strong> — an Enable Read Meshed Geometry checkbox over a Geometry File text
|
||||
box and a Browse button; the grid beneath the checkbox is disabled until it is ticked. Browse is
|
||||
an <code>OpenFileDialog</code> filtered to <code>*.wct;*.stl</code>, storing a pick under the project directory as a
|
||||
relative path and one outside it as an absolute path.</li>
|
||||
<li><strong>Machining Settings</strong> — the Machining Resolution control is an editable ComboBox pre-filled with
|
||||
fifteen powers of two, from 0.0009765625 up to 16 in doublings, and a typed value outside that
|
||||
list is accepted. Beside the Motion Resolution ComboBox a content presenter holds the fixed
|
||||
fields, built at runtime and labelled Linear Resolution (mm) and Angle Resolution (deg) — Angle
|
||||
Resolution being this client's wording for the same <code>RotaryResolution_deg</code> the web labels Rotary
|
||||
Resolution. The three checkboxes sit loose in the same grid, and the Enable Physics one carries no
|
||||
licence gate.</li>
|
||||
</ul>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
|
||||
@@ -108,7 +108,7 @@ fully usable.</p>
|
||||
<li>Script Title Text Field
|
||||
<ul>
|
||||
<li>The model is <a class="xref" href="../../../api/Hi.SessionCommands.ScriptCommand.html#Hi_SessionCommands_ScriptCommand_ScriptTitle">ScriptTitle</a>.</li>
|
||||
<li>Labelled “Title (optional)” on the web, “Script Title” on WPF.</li>
|
||||
<li>Labelled "Title (optional)".</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Autosave Indicator (web)
|
||||
@@ -183,11 +183,6 @@ the evaluator uses — and refuses to start when any of them has an error, namin
|
||||
title, path, diagnostic id, message and line. The SPA's Start sends nothing to bypass that check, so
|
||||
the refusal is what a user sees. The same check is also an endpoint of its own, per command and for
|
||||
the whole mission.</p>
|
||||
<h2 id="the-two-clients">The Two Clients</h2>
|
||||
<p>The desktop client edits the same command in AvalonEdit: a bold Script Title label with its text
|
||||
box, a Script Text label, and the editor with C# syntax highlighting and a line-number gutter,
|
||||
bound to the command through an attached behaviour. There is no completion popup and no autosave —
|
||||
the binding writes straight into the command as the text changes.</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>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
|
||||
@@ -89,7 +89,6 @@
|
||||
|
||||
<h2 id="shipped-surface">Shipped Surface</h2>
|
||||
<p>The dialog has no route and no Control-Tree node. It is a modal on the Execution page (<code>/execution</code>), opened by the <code>tune</code> icon button on the Step Properties panel's title bar in the Step Info column — so it is reachable only while that column and that panel are shown. The button sits next to the list it configures.</p>
|
||||
<p>In the WPF application the same editor is a window opened from the <a class="xref" href="../shell/preference-menu.html">Preference Menu Dropdown</a>.</p>
|
||||
<p>The dialog's own view models are the two fetched values, <code>categories</code> and <code>displayedKeys</code>. The server models they mirror are <code>UserService.CandidateStepPresentKeyList</code> plus <code>UserService.StepPresentAccessDictionary</code> (the candidates) and <code>UserConfig.DisplayedStepPresentKeyList</code> (the ordered displayed list). The dialog's only prop is its open/closed flag.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<ul>
|
||||
@@ -144,10 +143,9 @@
|
||||
<li><code>custom</code> — “Custom”, the catch-all for every key the mapping does not place, including the keys registered at run time through <code>UserService.AdditionalStepPresentAccess</code>.</li>
|
||||
</ol>
|
||||
<p>All seven are always returned; nothing gates any of them, and the candidate list is read from <code>UserService.CandidateStepPresentKeyList</code> rather than from <a class="xref" href="../../api/Hi.MachiningSteps.MachiningStep.html">MachiningStep</a> directly, so runtime-registered keys are included.</p>
|
||||
<p>Each client carries its own copy of the key → category mapping: <code>ResolveStepPresentCategory</code> on the webservice, <code>GetKeyCategory</code> in the WPF window. The two are kept in step by hand, with the seven category codes as the shared contract — adding a property means editing both.</p>
|
||||
<p>The key → category mapping is <code>ResolveStepPresentCategory</code> on the webservice, with the seven category codes as its contract.</p>
|
||||
<h3 id="labels-and-localization">Labels and Localization</h3>
|
||||
<p>The web app resolves <code>name</code> and <code>shortName</code> server-side for the requested language from the shipped step-present catalog, laid over the live <a class="xref" href="../../api/Hi.MachiningSteps.PresentAttribute.html">PresentAttribute</a>.<a class="xref" href="../../api/Hi.MachiningSteps.PresentAttribute.html#Hi_MachiningSteps_PresentAttribute_Name">Name</a> and <a class="xref" href="../../api/Hi.MachiningSteps.PresentAttribute.html#Hi_MachiningSteps_PresentAttribute_ShortName">ShortName</a> values — those are the English truth and the fallback for a missing catalog file or key. <a class="xref" href="../../api/Hi.MachiningSteps.PresentAttribute.html#Hi_MachiningSteps_PresentAttribute_Unit">Unit</a> is sent as-is and does not localize. The dialog pins the language with a <code>?lang=</code> argument on the request and re-pulls when the UI locale changes.</p>
|
||||
<p>The WPF window resolves the same labels locally, through a resource manager over <a class="xref" href="../../api/Hi.MachiningSteps.MachiningStep.html">MachiningStep</a>; a key with no translation keeps its original value.</p>
|
||||
<p>Refer to the code to apply <a class="xref" href="../../api/Hi.MachiningSteps.PresentAttribute.html">PresentAttribute</a>:</p>
|
||||
<pre><code class="lang-csharp" name="SampleCode-ShowStepPresent">internal static void ShowStepPresent(
|
||||
UserService userEnv, MachiningStep machiningStep)
|
||||
@@ -162,7 +160,7 @@
|
||||
</code></pre><h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="selected-step-info-panel.html">Selected-Step Info Panel</a> — the panel whose property list this page configures</li>
|
||||
<li><a class="xref" href="../shell/preference-menu.html">Preference Menu Dropdown</a> — the dropdown that hosts this entry in the WPF client</li>
|
||||
<li><a class="xref" href="../shell/preference-menu.html">Preference Menu Dropdown</a> — the preference surface this editor sits beside</li>
|
||||
<li><a href="../../manual/run/inspecting-a-step.html">Inspecting a Step</a> — the task this dialog serves, as a procedure</li>
|
||||
</ul>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
|
||||
@@ -103,12 +103,6 @@ leaf)</li>
|
||||
</ul>
|
||||
<p>Key Model: <a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html">SetupEquipment</a> (+ its
|
||||
<a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html#Hi_Machining_MachiningEquipmentUtils_SetupEquipment_CoolantHeatCondition">CoolantHeatCondition</a>).</p>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p>The WPF desktop app has no surface for either value — no page, no panel, and no handler for the
|
||||
<code>.CoolantHeatCondition</code> extension. There, both are whatever the project XML carries on the
|
||||
equipment face, or the class defaults when the XML says nothing.</p>
|
||||
</div>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<ul>
|
||||
<li>Background leaf — <code>equipment/background</code>, item type <code>ThermalCondition</code>
|
||||
|
||||
+1
-2
@@ -252,8 +252,7 @@ decides which axis consumes which position table, is <em>shown</em> on
|
||||
written here as an <strong>Axis parameters (integer)</strong> row; the REST surface carries no assignment writer
|
||||
at all. The equidistant definition — the numerator <code>MD30501</code> and the offset <code>MD30503</code> as axis
|
||||
parameters, the denominator <code>MD30502</code> as an integer axis parameter — has no endpoint that reads or
|
||||
writes it and no panel that offers a cell for it: on the web surface it is three ordinary rows on
|
||||
this leaf. The engine is its reader: an axis whose <code>MD30500</code> is 3 resolves its station spacing from
|
||||
writes it and no panel that offers a cell for it: it is three ordinary rows on this leaf. The engine is its reader: an axis whose <code>MD30500</code> is 3 resolves its station spacing from
|
||||
the trio, and Indexing Position Tables prints that axis' assignment as <em>Equidistant
|
||||
(MD30501–MD30503)</em>, naming the three numbers it offers no cell for. The two position lists
|
||||
themselves are the mirror image, stored as list properties outside all three dictionaries and so
|
||||
|
||||
@@ -93,18 +93,16 @@ surfaces:</p>
|
||||
<ul>
|
||||
<li>the <code>equipment/fixture</code> branch of the General Setup page's Control Tree
|
||||
(<code>/general-setup?tree=equipment/fixture</code>), an equipment child of the General Setup group between
|
||||
Coolant and Workpiece. <code>/fixture</code> and anything below it redirects there;</li>
|
||||
<li>in the WPF client, a sub-window opened from the <a class="xref" href="../shell/main-panel.html">Main Panel</a>.</li>
|
||||
Coolant and Workpiece. <code>/fixture</code> and anything below it redirects there.</li>
|
||||
</ul>
|
||||
<p>Both edit the one fixture the project owns.</p>
|
||||
<p>It edits the one fixture the project owns.</p>
|
||||
<ul>
|
||||
<li>Key Model:
|
||||
<ul>
|
||||
<li><a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html">Fixture</a>
|
||||
On the web it is addressed by an IndexService key handed to the
|
||||
It is addressed by an IndexService key handed to the
|
||||
<a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a> and installed back onto
|
||||
the project through the controller's UpdateFixture. On the WPF client the same button is wired
|
||||
with a TargetObjectGetter / TargetObjectSetter pair (see that page for the design pattern).</li>
|
||||
the project through the controller's UpdateFixture.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Assistant Model:
|
||||
@@ -114,14 +112,11 @@ with a TargetObjectGetter / TargetObjectSetter pair (see that page for the desig
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The displayee differs by client. The web branch has no fixture-only canvas: it shares the General
|
||||
Setup canvas, whose displayee is the equipment-setup displayee (<code>Disp/EquipmentSetupDisplayee.cs</code>) —
|
||||
the merged fixture + workpiece scene with the anchor, buckle and controller-coordinate overlays. Its
|
||||
option set is the equipment-setup config (<code>Disp/EquipmentSetupDisplayeeConfig.cs</code>), carried on
|
||||
<code>UserService.UserConfig</code> as its <code>EquipmentSetupDisplayeeConfig</code> property. The WPF sub-window has a
|
||||
canvas of its own, whose displayee is <a class="xref" href="../../api/Hi.NcMech.Fixtures.FixtureEditorDisplayee.html">FixtureEditorDisplayee</a> configured by
|
||||
<a class="xref" href="../../api/Hi.NcMech.Fixtures.FixtureEditorDisplayeeConfig.html">FixtureEditorDisplayeeConfig</a>, taken from <code>UserService.UserConfig</code> as its
|
||||
<code>FixtureSetupDisplayeeConfig</code> property.</p>
|
||||
<p>There is no fixture-only canvas: the branch shares the General Setup canvas, whose displayee is the
|
||||
equipment-setup displayee (<code>Disp/EquipmentSetupDisplayee.cs</code>) — the merged fixture + workpiece scene
|
||||
with the anchor, buckle and controller-coordinate overlays. Its option set is the equipment-setup
|
||||
config (<code>Disp/EquipmentSetupDisplayeeConfig.cs</code>), carried on <code>UserService.UserConfig</code> as its
|
||||
<code>EquipmentSetupDisplayeeConfig</code> property.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="control-tree-branch">Control Tree Branch</h3>
|
||||
<p>The root panel is rendered inline by the dock's primary editor pane, so it has no title label of its
|
||||
@@ -164,53 +159,10 @@ Display Options dropdown carries this branch's share of the scene — the <stron
|
||||
Solid / Edge / Hide radio group, and the Fixture Geom Anchor, Workpiece Buckle and Table Buckle
|
||||
flags in the Anchors group.</li>
|
||||
</ul>
|
||||
<h3 id="wpf-page">WPF Page</h3>
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a> — file extension
|
||||
<code>.Fixture</code>, load type <a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html">Fixture</a>, rel file <code>Fixture.xml</code>. The pointed
|
||||
Editor Panel is the Management Tabs Panel, a ContentPresenter the button swaps between the tab
|
||||
stack and XML mode.</li>
|
||||
<li>Title Label</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Management Tabs Panel — the same content the tree renders as nodes, stacked as tabs:
|
||||
<ul>
|
||||
<li>Geometry Tab — <a class="xref" href="../geom/geom-manage-control.html">Geometry Management Control</a> over
|
||||
<a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html#Hi_NcMech_Fixtures_Fixture_Geom">Geom</a>.</li>
|
||||
<li>Anchor Tab — a nested tab stack, each tab a
|
||||
<a class="xref" href="../geom/transformer-panel.html">Transformer Manage Panel</a>:
|
||||
<ul>
|
||||
<li>Geom To Workpiece Tab</li>
|
||||
<li>Geom To Table Tab</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Viewer Panel
|
||||
<ul>
|
||||
<li>Viewer ToolBar
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/renderingcanvas-tool-bar.html">RenderingCanvas Tool Bar</a></li>
|
||||
<li>Display Options menu — the Show Geom Anchor, Show Workpiece Buckle and Show Table Buckle
|
||||
checkboxes and the Solid / Edge / Hide rendering-mode radio group, all writing
|
||||
<a class="xref" href="../../api/Hi.NcMech.Fixtures.FixtureEditorDisplayeeConfig.html">FixtureEditorDisplayeeConfig</a>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>RenderingCanvas — its <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_Displayee">Displayee</a> is
|
||||
<a class="xref" href="../../api/Hi.NcMech.Fixtures.FixtureEditorDisplayee.html">FixtureEditorDisplayee</a>.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Both clients put a draggable divider between the editor column and the canvas: a GridSplitter in the
|
||||
WPF page, nested draggable splitters on the web page (dock / content column / canvas), plus the
|
||||
dock's own height divider between the tree row and the editor row.</p>
|
||||
<h2 id="behavior">Behavior</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html#Hi_NcMech_Fixtures_Fixture_ClearGeomCache">ClearGeomCache()</a> runs after any change at or below the branch. On
|
||||
the web each node's afterChange chain ends in the controller's ClearGeometryCache, which calls it;
|
||||
in WPF the page calls it directly from the geometry control's setter and update callbacks.</li>
|
||||
<li><a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html#Hi_NcMech_Fixtures_Fixture_ClearGeomCache">ClearGeomCache()</a> runs after any change at or below the branch:
|
||||
each node's afterChange chain ends in the controller's ClearGeometryCache, which calls it.</li>
|
||||
<li>The two anchor slots re-commit their swap-in <em>before</em> clearing the cache: an inner-value edit
|
||||
re-posts UpdateGeomToWorkpieceTransformer / UpdateGeomToTableTransformer, so the object the
|
||||
switchboard produced is always the one installed on the owning field when the redraw happens.</li>
|
||||
@@ -222,10 +174,7 @@ once.</li>
|
||||
<li>Kind pickers are parent-aware. Picking a geometry kind calls CreateGeometry, which installs the
|
||||
new object on <a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html#Hi_NcMech_Fixtures_Fixture_Geom">Geom</a> server-side and maps the literal <code>None</code> to
|
||||
null; picking a transformer kind creates the object and then rebinds the owning field.</li>
|
||||
<li>View snapping differs by client. The WPF page snaps its canvas to the isometric view when the
|
||||
displayee is bound, and again whenever a new geometry object is set, on the assumption that a
|
||||
shape swap changes the scene more than an edit within one shape does. The shared web canvas snaps
|
||||
once, when its displayee is bound — the display controller's initialize does it server-side.
|
||||
<li>The shared canvas snaps to the isometric view once, when its displayee is bound — the display controller's initialize does it server-side.
|
||||
Afterwards a geometry set only clears the cache, and the operator re-frames from the
|
||||
<a class="xref" href="../widget/renderingcanvas-tool-bar.html">RenderingCanvas Tool Bar</a>'s view picker.</li>
|
||||
<li>Both canvases draw the live model, so an edit shows on the next frame with no further calls.</li>
|
||||
@@ -287,13 +236,11 @@ fixture + workpiece scene with the anchor, buckle and controller-coordinate over
|
||||
<ul>
|
||||
<li><code>HiMech/NcMech/Fixtures/Fixture.cs</code> — the key model: the geometry, the table and workpiece
|
||||
buckles, the geom anchor, the two anchor transformers and ClearGeomCache.</li>
|
||||
<li><code>HiMech/NcMech/Fixtures/FixtureEditorDisplayee.cs</code> — the WPF fixture canvas's displayee.</li>
|
||||
<li><code>HiMech/NcMech/Fixtures/FixtureEditorDisplayeeConfig.cs</code> — its option set: ShowGeomAnchor,
|
||||
ShowWorkpieceBuckle, ShowTableBuckle and the rendering mode.</li>
|
||||
</ul>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../util/mech-builder.html">Mechanism Builder Page</a> — reuses this page’s parent-aware transformer rebind pattern</li>
|
||||
<li><a class="xref" href="../tool-house/holder/freeform-holder-panel.html">Freeform Holder Panel</a> — the other surface built from the same generic Geometry and Transformer slots</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
@@ -97,18 +97,16 @@ group and a <strong>leaf</strong>: chain structure belongs to the
|
||||
<li>the <code>/machine-tool</code> route, a standalone surface pairing a chain-only canvas with a load button
|
||||
and a GUI / XML view of what is loaded. Its fields are read-only, but the route is not: its Load
|
||||
installs the picked chain file onto the project. It carries no Page-menu entry and is reached by
|
||||
URL;</li>
|
||||
<li>in the WPF client, a sub-window opened from the <a class="xref" href="../shell/main-panel.html">Main Panel</a>.</li>
|
||||
URL.</li>
|
||||
</ul>
|
||||
<p>All three edit the one chain the project owns.</p>
|
||||
<p>Both edit the one chain the project owns.</p>
|
||||
<ul>
|
||||
<li>Key Model:
|
||||
<ul>
|
||||
<li><a class="xref" href="../../api/Hi.Mech.IMachiningChain.html">IMachiningChain</a>
|
||||
On the web the chain is addressed by an IndexService key handed to the
|
||||
The chain is addressed by an IndexService key handed to the
|
||||
<a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a> and installed back onto
|
||||
the project through the controller's Update. On the WPF client the same button is wired with a
|
||||
TargetObjectGetter / TargetObjectSetter pair (see that page for the design pattern).</li>
|
||||
the project through the controller's Update.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Assistant Model:
|
||||
@@ -184,43 +182,6 @@ fetched lazily on the first switch to XML and re-fetched after a load while XML
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="wpf-page">WPF Page</h3>
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a>
|
||||
<ul>
|
||||
<li>file extension is <code>mt</code>; the load type is <a class="xref" href="../../api/Hi.Mech.IMachiningChain.html">IMachiningChain</a>.</li>
|
||||
<li>The pointed Editor Panel is Management Panel — a ContentPresenter the button swaps between the
|
||||
built GUI panel and an AvalonEdit text editor for XML mode.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Title Label “Machine Tool”</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Management Panel
|
||||
<ul>
|
||||
<li>If the key model inherits <a class="xref" href="../../api/Hi.Common.INameNote.html">INameNote</a>:
|
||||
<ul>
|
||||
<li>Name Setting Line
|
||||
<ul>
|
||||
<li>Name Label</li>
|
||||
<li>Name TextField — its TextChanged writes straight onto the chain.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Note Setting Line
|
||||
<ul>
|
||||
<li>Note Label</li>
|
||||
<li>Note TextField — multi-line, same write-through.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Type Line — italic <code>Type: {chain type}</code>.</li>
|
||||
<li>Empty-state label when no chain is loaded.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="behavior">Behavior</h2>
|
||||
<ul>
|
||||
<li>Load / Paste / XML-Apply only swap the IndexService entry. The tree root then installs the result
|
||||
|
||||
@@ -109,13 +109,6 @@ side-file reference
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p>The WPF desktop app has no spindle-capability surface: no page, no panel, and no handler for the
|
||||
<code>.SpindleCapability</code> extension. There, the value is whatever the project XML carries on the
|
||||
equipment face, or the class defaults when the XML says nothing. The <code>.SpindleCapability</code> object
|
||||
management menu ships on the web only, on this branch's root panel.</p>
|
||||
</div>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<p>The branch is one root plus five children, six selectable nodes in all. Each node's editor occupies
|
||||
the dock's PRIMARY row, and all six — the root included — register the <em>same</em> CONTENT-column view,
|
||||
|
||||
@@ -87,16 +87,14 @@
|
||||
<article data-uid="Anatomy-Workpiece">
|
||||
<h1 id="workpiece">Workpiece</h1>
|
||||
|
||||
<p>The Workpiece editor is the <code>equipment/workpiece</code> branch of the General Setup page's Control Tree (<code>/general-setup?tree=equipment/workpiece</code>); the old <code>/workpiece</code> route redirects there. In the WPF client it is a sub-window opened from the <a class="xref" href="../shell/main-panel.html">Main Panel</a>.</p>
|
||||
<p>The Workpiece editor is the <code>equipment/workpiece</code> branch of the General Setup page's Control Tree (<code>/general-setup?tree=equipment/workpiece</code>); the old <code>/workpiece</code> route redirects there.</p>
|
||||
<p>The key model is <a class="xref" href="../../api/Hi.NcMech.Workpieces.Workpiece.html">Workpiece</a>, taken from the Main Panel's
|
||||
<a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_Workpiece">Workpiece</a>. The cached solids it is drawn from belong to
|
||||
<a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceService.html">WorkpieceService</a>, which both clients share.</p>
|
||||
<p>The display config differs by client. The web branch has none of its own: it shares the General Setup
|
||||
canvas, gated by the equipment-setup config (<code>Disp/EquipmentSetupDisplayeeConfig.cs</code>), which carries
|
||||
<a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceService.html">WorkpieceService</a>.</p>
|
||||
<p>The branch has no display config of its own: it shares the General Setup canvas, gated by the equipment-setup config (<code>Disp/EquipmentSetupDisplayeeConfig.cs</code>), which carries
|
||||
the fixture and workpiece flags together — the fixture and workpiece geometry anchors keep separate
|
||||
flags, while the fixture↔workpiece buckle pair, being one attached identity at one location, is a
|
||||
single flag. The WPF page takes its own <a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceEditorDisplayeeConfig.html">WorkpieceEditorDisplayeeConfig</a>
|
||||
from <code>UserService.UserConfig</code>.</p>
|
||||
single flag.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="control-tree-branch">Control Tree Branch</h3>
|
||||
<ul>
|
||||
@@ -205,120 +203,6 @@ fixture↔workpiece pair), Table Buckle, <strong>Workpiece Geometry Anchor</stro
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="wpf-page">WPF Page</h3>
|
||||
<ul>
|
||||
<li>Workpiece Page
|
||||
<ul>
|
||||
<li>Management Panel
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a>
|
||||
<ul>
|
||||
<li>file extension is <code>.Workpiece</code>; the load type is <a class="xref" href="../../api/Hi.NcMech.Workpieces.Workpiece.html">Workpiece</a></li>
|
||||
<li>The pointed Editor Panel is Management Tabs Panel</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Title Label</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Management Tabs Panel
|
||||
<ul>
|
||||
<li>Raw Shape Tab
|
||||
<ul>
|
||||
<li>Raw Geometry Source DropDown (Common Geometry and Meshed Geometry are EXCLUSIVE)
|
||||
<ul>
|
||||
<li>Common Geometry
|
||||
Apply <a class="xref" href="../geom/geom-manage-control.html">Geometry Management Control</a></li>
|
||||
<li>Meshed Geometry
|
||||
Apply <a class="xref" href="../geom/meshed-geom-panel.html">Meshed Geometry Panel</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Target Shape Tab
|
||||
<ul>
|
||||
<li>Geometry Management Control</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Anchor Tab
|
||||
<ul>
|
||||
<li>Geom To Fixture Tab
|
||||
<ul>
|
||||
<li><a class="xref" href="../geom/transformer-panel.html">Transformer Manage Panel</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Geom To Program-Zero Tab
|
||||
<ul>
|
||||
<li>Transformer Manage Panel</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Runtime Tab
|
||||
<ul>
|
||||
<li>Initial Resolution Dropdown — the same powers-of-two ladder as the Mesh item above.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Material Tab
|
||||
Visible if <code>UserService.EnablePhysics</code> is true.
|
||||
<ul>
|
||||
<li>Workpiece Material File Selector
|
||||
<ul>
|
||||
<li>Browse Button
|
||||
The initial directory is the project directory.</li>
|
||||
<li>Browse Resource Button
|
||||
The directory is the Default Resource directory.</li>
|
||||
<li>Readonly File Path TextBox</li>
|
||||
<li>Readonly Name TextBox (<a class="xref" href="../../api/Hi.Common.INameNote.html#Hi_Common_INameNote_Name">Name</a>)
|
||||
<ul>
|
||||
<li>ToolTip: <a class="xref" href="../../api/Hi.Common.INameNote.html#Hi_Common_INameNote_Note">Note</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cutting Parameter File Selector
|
||||
<ul>
|
||||
<li>Browse Button
|
||||
The initial directory is the project directory.</li>
|
||||
<li>Browse Resource Button
|
||||
The directory is the Default Resource directory.</li>
|
||||
<li>Readonly File Path TextBox</li>
|
||||
<li>Readonly Name TextBox (<a class="xref" href="../../api/Hi.Common.INameNote.html#Hi_Common_INameNote_Name">Name</a>)
|
||||
<ul>
|
||||
<li>ToolTip: <a class="xref" href="../../api/Hi.Common.INameNote.html#Hi_Common_INameNote_Note">Note</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Viewer Panel
|
||||
<ul>
|
||||
<li>Viewer ToolBar
|
||||
<ul>
|
||||
<li><a class="xref" href="../widget/renderingcanvas-tool-bar.html">RenderingCanvas Tool Bar</a></li>
|
||||
<li>SetupDisplayee Options ToolBar
|
||||
<ul>
|
||||
<li>Options of <a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceEditorDisplayee.html">WorkpieceEditorDisplayee</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>RenderingCanvas
|
||||
<ul>
|
||||
<li>The <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_Displayee">Displayee</a> is <a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceEditorDisplayee.html">WorkpieceEditorDisplayee</a> (Apply the model <a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceEditorDisplayeeConfig.html">WorkpieceEditorDisplayeeConfig</a>).</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="default-resource">Default Resource</h2>
|
||||
<p>The default resources of Workpiece Material and Cutting Parameter exist in <code>Resource</code> folder under application folder (Not project folder). Both clients seed their file pickers at the matching <code>Resource</code> sub folder:</p>
|
||||
<ul>
|
||||
@@ -336,9 +220,7 @@ None leaves the old object indexed, and re-committing would resurrect it.</p>
|
||||
</li>
|
||||
<li><p>Call <a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceService.html">WorkpieceService</a>.<a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceService.html#Hi_NcMech_Workpieces_WorkpieceService_ClearIdealGeomCache">ClearIdealGeomCache()</a> on Target Shape set or changed.</p>
|
||||
</li>
|
||||
<li><p>Both clients reach that one service by different routes: the web branch posts the controller's
|
||||
cache-clear endpoints, and the WPF page calls
|
||||
<a class="xref" href="../../api/Hi.NcMech.Workpieces.WorkpieceEditorDisplayee.html">WorkpieceEditorDisplayee</a>, which forwards to the same service.</p>
|
||||
<li><p>The branch reaches that service by posting the controller's cache-clear endpoints.</p>
|
||||
</li>
|
||||
<li><p>Anchor edits re-commit their transformer and deliberately do <strong>not</strong> clear the geometry cache, so
|
||||
a placement change forces no <code>CubeTreeFile</code> re-mesh.</p>
|
||||
@@ -348,10 +230,7 @@ cache chain runs after a change.</p>
|
||||
</li>
|
||||
<li><p>The equipment canvas snaps to the isometric view when its displayee is bound to a rendering
|
||||
connection; a shape edit on the branch re-commits and clears the cache so the next frame
|
||||
re-solidifies, and leaves the view alone. The WPF page snaps its own canvas to isometric when a
|
||||
Raw or Target shape is <em>set</em> to a different object, and whenever its meshed-geometry panel updates
|
||||
its content — the assumption being that setting a shape changes the viewer more than changing its
|
||||
content does, so only the setter event adjusts the view.</p>
|
||||
re-solidifies, and leaves the view alone.</p>
|
||||
</li>
|
||||
<li><p>Keep <a href="../conventions/gui-file-path-assignment.html#portability">Portability</a> of the Material properties.</p>
|
||||
</li>
|
||||
|
||||
@@ -94,9 +94,8 @@ 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 “Min / Max”, “Min + Dimension” and “Center + Dimension”,
|
||||
the desktop client “Min and Max”, “Min and Dimension” and “Center and Dimension”.</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
|
||||
<code>CenterDimension</code>, labelled “Min / Max”, “Min + Dimension” and “Center + Dimension”.</li>
|
||||
<li><strong>Min</strong>, <strong>Max</strong>, <strong>Dimension</strong>, <strong>Center</strong> — four vector rows, one X / Y / Z input each. The editor
|
||||
captions Dimension “Dimension (Max − Min)” and Center "Center ((Max + Min) / 2)"; the Min and Max
|
||||
captions come from the shared label set rather than the geometry one.</li>
|
||||
</ul>
|
||||
@@ -107,18 +106,14 @@ in anything but Center + Dimension.</p>
|
||||
<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>
|
||||
shape — and 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>This editor has no read-only variant.</strong> A host that needs one draws its own rows instead — the
|
||||
STL file editor's read-only bounding-box rows are not this editor.</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>
|
||||
|
||||
@@ -101,16 +101,12 @@ 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>The floor is two pairs, and both ends enforce it.</strong> The remove button is disabled at two and
|
||||
the controller refuses the call below two.</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>,
|
||||
@@ -119,12 +115,10 @@ warning dialog.</li>
|
||||
<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>
|
||||
carries only a static default.</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>
|
||||
cylindroid holder carries a <strong>Resolution</strong> tree node beside its Geometry one, 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>
|
||||
|
||||
@@ -89,13 +89,12 @@
|
||||
|
||||
<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>
|
||||
it 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
|
||||
@@ -113,19 +112,15 @@ minimum — its minimum is inclusive — so a value exactly equal to the bound p
|
||||
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>The field commits on blur or Enter</strong>, and the range guard runs on both the field and the backend.</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
|
||||
<p>This kind is restricted to the cutter's upper beam, and the mechanism is absence rather than a flag:
|
||||
<strong>no Geometry slot offers it 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
|
||||
|
||||
@@ -87,10 +87,10 @@
|
||||
<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>
|
||||
<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</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. There is no selection model on either — every
|
||||
child carries its own remove button.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="the-inline-editor">The inline editor</h3>
|
||||
<ul>
|
||||
@@ -103,33 +103,23 @@ editable at once.</li>
|
||||
<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>Pick the kind first, then Add; the request carries the kind.</p>
|
||||
<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>
|
||||
accepted by neither 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>
|
||||
both 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>
|
||||
<li><strong>Clear all is posted directly, with no confirmation.</strong></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>
|
||||
@@ -175,7 +165,7 @@ cache.</li>
|
||||
<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>
|
||||
the panel each child card embeds</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
@@ -88,21 +88,17 @@
|
||||
<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
|
||||
the host asked for the picker alone — the picked kind's editor beneath it. 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>
|
||||
<code>onCreate</code> hook, so switching the kind rebinds the host's field rather than just the key.</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
|
||||
@@ -117,7 +113,7 @@ host that wires that source, the cutter's upper beam.</p>
|
||||
<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>
|
||||
Nothing is hidden by a flag.</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>
|
||||
@@ -151,17 +147,13 @@ shipped surface renders the default at all, and the whitelist is what really dec
|
||||
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>
|
||||
kind <code>None</code>, which the container-aware endpoints map to null.</p>
|
||||
<h2 id="there-is-no-way-to-wrap-an-existing-geometry">There Is No Way to Wrap an Existing Geometry</h2>
|
||||
<p>Wrapping a geometry that is already in a slot into a <a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a> — and
|
||||
extracting it back out — is not offered anywhere in the application, and the difference from what
|
||||
the picker looks like it does is not cosmetic. <strong>Picking <code>TransformationGeom</code> creates a new, empty
|
||||
one and discards the geometry that was there.</strong> The same holds for a combination: there is no
|
||||
operation that takes a geometry and puts a container around it in place.</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
|
||||
@@ -219,8 +211,8 @@ editor</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="transformation-geom-control.html">Transformation Geometry Control</a> — one of the container kinds
|
||||
this panel offers, and why picking it replaces rather than wraps</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>
|
||||
|
||||
@@ -105,18 +105,14 @@ 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 [<path>]</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>
|
||||
<p>There is no separate geometry-source 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>
|
||||
|
||||
@@ -89,19 +89,17 @@
|
||||
|
||||
<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
|
||||
loaded. 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>
|
||||
<li><strong>The picker</strong> — 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>. There is no reload action.</li>
|
||||
<li><strong>STL info</strong> — behind an info icon, opening a dialog that shows the triangle count and the
|
||||
bounding box as read-only vector rows, and states an empty case when nothing is loaded.</li>
|
||||
</ol>
|
||||
<h2 id="behavior">Behavior</h2>
|
||||
<ul>
|
||||
@@ -115,8 +113,8 @@ re-homed path, not the one that was chosen.</li>
|
||||
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
|
||||
panel to a 3D preview of that file before the pick is confirmed. 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>
|
||||
|
||||
@@ -88,16 +88,16 @@
|
||||
<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,
|
||||
editor is those two things side by side. It has two faces: 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>
|
||||
there. There is no operation anywhere that wraps an existing geometry into a transformation
|
||||
geometry, or extracts it back out — see
|
||||
<a href="geom-manage-control.html">Geometry Management Panel</a>.</p>
|
||||
</div>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="the-embedded-editor">The embedded editor</h3>
|
||||
@@ -117,22 +117,14 @@ its own default of <strong>all seven</strong> transformer kinds applies.</li>
|
||||
<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>The identity transformer is the floor.</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.</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
|
||||
<li><strong>The control does not preview.</strong> There is no viewport on it. 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
|
||||
|
||||
@@ -88,10 +88,8 @@
|
||||
<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
|
||||
occupies a transformer-valued slot and edits the one that is there. 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
|
||||
@@ -158,13 +156,10 @@ hook, in which case that hook runs instead so the owning domain object is reboun
|
||||
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>
|
||||
appear there.</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>
|
||||
editor. The out-of-list transformer is not rendered.</p>
|
||||
<h2 id="transformer-kinds">Transformer Kinds</h2>
|
||||
<p>The web client offers seven kinds, one editor each.</p>
|
||||
<table>
|
||||
@@ -213,11 +208,7 @@ way — <code>UpdateUI()</code> leaves the combo unselected when no item matches
|
||||
</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>
|
||||
<p>The picker offers no null entry: 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,
|
||||
@@ -226,9 +217,7 @@ embedded in their own bordered cards, titled <em>Rotation sub-transformer</em> a
|
||||
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>
|
||||
<code>T × R × scale × I</code>.</p>
|
||||
</div>
|
||||
<h2 id="key-model">Key Model</h2>
|
||||
<ul>
|
||||
|
||||
@@ -94,11 +94,10 @@
|
||||
<li>The <code>Brief Message Text Field</code> content is updated</li>
|
||||
<li>The message is appended to the daily log file at <code>logs/log-{DateTime.Now:yyyy-MM-dd}.txt</code></li>
|
||||
</ol>
|
||||
<p>The second step belongs to the logging path rather than to the bar, and only one client shares it.
|
||||
The WPF brief field is fed by a logger provider, so a message that reaches the field has already
|
||||
gone to the file sink. The web footer is fed by the routine-progress store instead: what lands there
|
||||
is client-side, and it reaches the server's daily log only when the server logged it too — no part
|
||||
of the shell posts a message to the log-append endpoint.</p>
|
||||
<p>The second step belongs to the logging path rather than to the bar, and the footer does not share
|
||||
it. The footer is fed by the routine-progress store: what lands there is client-side, and it reaches
|
||||
the server's daily log only when the server logged it too — no part of the shell posts a message to
|
||||
the log-append endpoint.</p>
|
||||
<h3 id="message-types">Message Types</h3>
|
||||
<p>The <a class="xref" href="../../api/Hi.Common.Messages.MessageFlag.html">MessageFlag</a> determines the display behavior:</p>
|
||||
<table>
|
||||
@@ -128,16 +127,6 @@ of the shell posts a message to the log-append endpoint.</p>
|
||||
<p>When the message is an <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception">Exception</a>, the brief message shows <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.message">Message</a> while the full exception details are logged to file.</p>
|
||||
</div>
|
||||
<h2 id="platform-specific-layouts">Platform-Specific Layouts</h2>
|
||||
<h3 id="wpf-application">WPF Application</h3>
|
||||
<p>The WPF version uses a fixed bottom bar:</p>
|
||||
<ul>
|
||||
<li><strong>Message Section Bottom Bar</strong>
|
||||
<ul>
|
||||
<li>Brief Message Text Field (selectable for copy)</li>
|
||||
<li>Show Log Button</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
<p>The web version docks a single dense bar along the bottom of the layout — <code>AppFooter.vue</code>, not a
|
||||
stack of toasts:</p>
|
||||
@@ -159,16 +148,11 @@ Quasar notifications, anchored bottom-right and auto-hiding on a timeout that do
|
||||
severity. A boot patch mirrors every one of them into the footer's foreground history, which is what
|
||||
keeps a toast reviewable after it fades.</p>
|
||||
<h2 id="show-log-button">Show Log Button</h2>
|
||||
<p>The <code>Show Log</code> button is the only entrance to the log screen, and the two clients answer it
|
||||
differently.</p>
|
||||
<p>In the web application it is a router link in the menu bar's right-hand group — not on this bar —
|
||||
and it opens the Log Viewer as a full page inside the shell. See
|
||||
<a class="xref" href="../platform/log-viewer.html">Log Viewer Page</a> for that screen's toolbar, its auto-refresh interval, its
|
||||
copy and download actions and the states of its text area.</p>
|
||||
<p>In the WPF client the button sits at the right end of this bar. It looks for the current day's file
|
||||
under the client's own <code>logs</code> folder and, when it is there, opens it with whatever application the
|
||||
operating system associates with the file type; when it is not, it reports that in a message box
|
||||
instead of opening anything.</p>
|
||||
<p>The <code>Show Log</code> button is the only entrance to the log screen.</p>
|
||||
<p>It is a router link in the menu bar's right-hand group — not on this bar — and it opens the Log
|
||||
Viewer as a full page inside the shell. See <a class="xref" href="../platform/log-viewer.html">Log Viewer Page</a> for that
|
||||
screen's toolbar, its auto-refresh interval, its copy and download actions and the states of its
|
||||
text area.</p>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="main-panel.html">Main Panel</a> — the window frame this bar is docked in</li>
|
||||
|
||||
@@ -88,28 +88,18 @@
|
||||
<h1 id="language-selection-submenu">Language Selection SubMenu</h1>
|
||||
|
||||
<p>The submenu locates on the <a class="xref" href="preference-menu.html">Preference Menu Dropdown</a>. It is the only
|
||||
place either client offers for changing the interface language. What that choice sets in motion in
|
||||
the web client — the message bundles, the locale applied before the first frame, the single switch
|
||||
place the application offers for changing the interface language. What that choice sets in motion —
|
||||
the message bundles, the locale applied before the first frame, the single switch
|
||||
function and everything that re-renders behind it — is
|
||||
<a class="xref" href="../platform/i18n.html">Internationalization</a>; this page covers the gesture.</p>
|
||||
<p>The web submenu's model is the application-state store rather than a service handed down by the
|
||||
<p>The submenu's model is the application-state store rather than a service handed down by the
|
||||
parent component: it reads the current code and the available-code list from that store and calls
|
||||
the store's language action. Both values are hydrated by the store's server-preferences load, which
|
||||
the shell layout runs on mount — a separate path from the one that decides which locale the first
|
||||
painted frame uses. The WPF client resolves its language manager during start-up, and the manager
|
||||
reads the persisted code out of the user configuration as it is constructed.</p>
|
||||
painted frame uses.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<p>The two clients draw the submenu differently.</p>
|
||||
<ul>
|
||||
<li><p>Language Selection SubMenu — WPF application</p>
|
||||
<ul>
|
||||
<li>English RadioButton</li>
|
||||
<li>Simplified Chinese RadioButton</li>
|
||||
<li>Traditional Chinese RadioButton</li>
|
||||
</ul>
|
||||
<p>Three fixed rows in one radio group, ticked at start-up to match the current language.</p>
|
||||
</li>
|
||||
<li><p>Language Selection SubMenu — web application</p>
|
||||
<li><p>Language Selection SubMenu</p>
|
||||
<ul>
|
||||
<li>Language Row — one plain row per code in the store's available-code list, so the rows are
|
||||
whatever the server reports rather than a fixed set of three. Each carries the language's own
|
||||
@@ -120,13 +110,11 @@ the active state. No row carries a radio button or a checkbox.</li>
|
||||
<p>The parent entry captions the current language, so it reads without opening the submenu.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Choosing a row in the web client closes the popup and makes one call, the store's language action.
|
||||
<p>Choosing a row closes the popup and makes one call, the store's language action.
|
||||
The store writes the new code optimistically, POSTs it, adopts the current and available lists the
|
||||
server echoes back, and only then switches the live catalogue — so the interface text flips after
|
||||
the server has accepted the value, and the confirmation toast already reads in the language just
|
||||
picked. A rejected write rolls the store back and changes no interface text at all. In the WPF
|
||||
client picking a radio swaps the merged string dictionary in place and saves the code to the user
|
||||
configuration, and the labels follow without a restart.</p>
|
||||
picked. A rejected write rolls the store back and changes no interface text at all.</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>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
|
||||
@@ -90,19 +90,14 @@
|
||||
<p>The Main Panel is the primary window of the HiNC application, providing navigation and access to all major features.</p>
|
||||
<h2 id="key-models">Key Models</h2>
|
||||
<ul>
|
||||
<li>Project Service
|
||||
<ul>
|
||||
<li><strong>WPF Single-User Desktop Application</strong>: Uses self-hosted <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html">LocalProjectService</a></li>
|
||||
<li><strong>Web Service Application</strong>: injects <a class="xref" href="../../api/Hi.MachiningProcs.ProxyProjectService.html">ProxyProjectService</a>, the <a class="xref" href="../../api/Hi.MachiningProcs.IProjectService.html">IProjectService</a> implementation that reaches the session's project across the connection</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><strong>Project Service</strong>: injects <a class="xref" href="../../api/Hi.MachiningProcs.ProxyProjectService.html">ProxyProjectService</a>, the <a class="xref" href="../../api/Hi.MachiningProcs.IProjectService.html">IProjectService</a> implementation that reaches the session's project across the connection</li>
|
||||
<li><strong>User Service</strong>: <code>UserService</code></li>
|
||||
</ul>
|
||||
<h2 id="layout-structure">Layout Structure</h2>
|
||||
<ul>
|
||||
<li>Top <code>Navigation Menu</code>
|
||||
<ul>
|
||||
<li><p>Brand logo, and in the web application the HiAPI version as an outlined badge beside it. The
|
||||
<li><p>Brand logo, and the HiAPI version as an outlined badge beside it. The
|
||||
badge carries the HiNc assembly version reported by the anonymous authentication-status probe
|
||||
the router runs before the first route resolves, so it needs neither a loaded project nor a
|
||||
signed-in session; it is omitted only while that probe has reported no version.</p>
|
||||
@@ -112,33 +107,14 @@ signed-in session; it is omitted only while that probe has reported no version.<
|
||||
<li><code>Project Path Text Field</code> — readonly; reads “No Project Loaded” until a project is loaded</li>
|
||||
<li><code>New MenuItem</code></li>
|
||||
<li><code>Load MenuItem</code></li>
|
||||
<li><code>ReLoad MenuItem</code> (web application only)</li>
|
||||
<li><code>ReLoad MenuItem</code></li>
|
||||
<li><code>Save MenuItem</code></li>
|
||||
<li><code>Save As MenuItem</code></li>
|
||||
<li><code>Close Project MenuItem</code> (web application only, below a separator)</li>
|
||||
<li><code>Close Project MenuItem</code> (below a separator)</li>
|
||||
</ul>
|
||||
<p>In the web application ReLoad, Save, Save As and Close Project are disabled until a project is loaded, and New, Load and Save As open the shared file-picker dialog with a <code>.hincproj</code> filter. The picker is allowed the Admin and Project roots and is denied the Resource root, which holds read-only templates the project endpoints cannot save through; it asks for the Admin root by name, so that is where it opens, and it seeds its path box with the directory holding the loaded project, or with the admin root itself when there is none. The Project root is one of the two only while a project is loaded: the roots endpoint lists a root only when its directory resolves, and the project directory resolves to nothing until a project is open, so with no project the picker offers Admin alone. The WPF client's dropdown stops at Save As.</p>
|
||||
<p>ReLoad, Save, Save As and Close Project are disabled until a project is loaded, and New, Load and Save As open the shared file-picker dialog with a <code>.hincproj</code> filter. The picker is allowed the Admin and Project roots and is denied the Resource root, which holds read-only templates the project endpoints cannot save through; it asks for the Admin root by name, so that is where it opens, and it seeds its path box with the directory holding the loaded project, or with the admin root itself when there is none. The Project root is one of the two only while a project is loaded: the roots endpoint lists a root only when its directory resolves, and the project directory resolves to nothing until a project is open, so with no project the picker offers Admin alone.</p>
|
||||
</li>
|
||||
<li><p><code>Environment Menu Dropdown</code> (WPF application only — the web application has no such dropdown; see below)</p>
|
||||
<ul>
|
||||
<li>Machine Tool MenuItem
|
||||
Open <a class="xref" href="../general-setup/machine-tool.html">Machine Tool Page</a>
|
||||
Sole window in WPF app.
|
||||
The page manages <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_MachiningEquipment">MachiningEquipment</a>.<a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html#Hi_Machining_MachiningEquipmentUtils_MachiningEquipment_MachiningChain">MachiningChain</a>.</li>
|
||||
<li>Controller MenuItem
|
||||
Open <a class="xref" href="../legacy-controller.html">Legacy Controller Page</a></li>
|
||||
<li>Tool House MenuItem</li>
|
||||
<li>Fixture MenuItem
|
||||
Open <a class="xref" href="../general-setup/fixture.html">Fixture Page</a></li>
|
||||
<li>Workpiece MenuItem
|
||||
Open <a class="xref" href="../general-setup/workpiece.html">Workpiece Page</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><p>Mission MenuItem
|
||||
Open <a class="xref" href="../execution/mission/mission-root-panel.html">Mission Page</a>
|
||||
In the web application the Mission editor is a branch of the Execution page's Control Tree; <code>/mission</code> redirects there.</p>
|
||||
</li>
|
||||
<li><p><code>Page Menu Dropdown</code> (web application only) — the three workflow pages in setup order (fill the tool house, set up the equipment, run), then the utilities.</p>
|
||||
<li><p><code>Page Menu Dropdown</code> — the three workflow pages in setup order (fill the tool house, set up the equipment, run), then the utilities.</p>
|
||||
<ul>
|
||||
<li>Tool House MenuItem
|
||||
Open <a class="xref" href="../tool-house/index.html">Tool House Page</a></li>
|
||||
@@ -156,18 +132,9 @@ Open <a class="xref" href="../legacy-controller.html">Legacy Controller Page</a>
|
||||
</li>
|
||||
<li><p><a class="xref" href="preference-menu.html">Preference Menu Dropdown</a></p>
|
||||
</li>
|
||||
<li><p><code>Debug Menu Dropdown</code> (WPF application only) — Transformers and Geometry Management, visible only while the client runs in debug mode</p>
|
||||
</li>
|
||||
<li><p>Help MenuItem</p>
|
||||
<ul>
|
||||
<li>HiAPI Version label
|
||||
A label to show the HiNc library version.
|
||||
The web application shows this as a version badge next to the brand logo, with no Help dropdown.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><code>Show Log</code> Button — a button on both clients, not a menu item. In the web application it sits on the menu bar's right side and routes to the Log Viewer page; in the WPF client it sits at the right end of the bottom message bar.
|
||||
<li><code>Show Log</code> Button — a button, not a menu item. It sits on the menu bar's right side and routes to the Log Viewer page.
|
||||
The Log Viewer presents the server's application log for the current day, with a manual refresh, a selectable auto-refresh interval, copy to the clipboard, and download of the day's log file for offline analysis.</li>
|
||||
<li>Central <code>Page Panel</code> — one router outlet wrapped in a keep-alive cache keyed on a project epoch: an
|
||||
integer the layout owns, raised by two watchers and read by nothing else. The first watches the project
|
||||
@@ -183,7 +150,7 @@ A bump discards every cached page and rebuilds it, so each page initializes on i
|
||||
watching for project changes itself.</li>
|
||||
<li>Bottom footer — the routine-progress bar: the latest foreground message with a recent-messages history menu on the left, the live session status in the middle, and in-flight background job progress on the right. See <a class="xref" href="bottom-message-bar.html">Message Section on Main Panel</a>.</li>
|
||||
</ul>
|
||||
<p>In the WPF application the run tool bars belong to the menu shell and appear only while the central panel is the player. The web application does not carry them on the menu bar at all: the transport controls ride the <a class="xref" href="../execution/index.html">Execution Page</a>‘s primary panel header and the view controls ride its canvas panel header. What the menu bar keeps instead is the page's set of column quick-toggles, the connection badge, the active page's title, the <code>Show Log</code> button and — when authentication is on — the logout button. The toggles follow whichever tree page is current: four on the Execution page (control dock, canvas, strip charts, step info) and three on General Setup (control dock, content, canvas); the Tool House page lays itself out with plain splitters and gets none. The connection badge is Execution-only — the other pages’ canvases carry their own in-panel badges.</p>
|
||||
<p>The menu bar carries no run tool bars at all: the transport controls ride the <a class="xref" href="../execution/index.html">Execution Page</a>‘s primary panel header and the view controls ride its canvas panel header. What the menu bar keeps instead is the page's set of column quick-toggles, the connection badge, the active page's title, the <code>Show Log</code> button and — when authentication is on — the logout button. The toggles follow whichever tree page is current: four on the Execution page (control dock, canvas, strip charts, step info) and three on General Setup (control dock, content, canvas); the Tool House page lays itself out with plain splitters and gets none. The connection badge is Execution-only — the other pages’ canvases carry their own in-panel badges.</p>
|
||||
<h2 id="project-menu-behavior">Project Menu Behavior</h2>
|
||||
<p>The <code>Project Path Text Field</code> displays the current project path when a project is loaded. It is implemented as a pure text field (not a button) that allows users to select and copy the path.</p>
|
||||
<p>The <code>Project</code> Menu manages <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a> with the following operations:</p>
|
||||
@@ -228,17 +195,12 @@ watching for project changes itself.</li>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>In the web application every Project action reports through two channels: a background progress line on the footer while it runs, then a toast when it lands — positive on success, a “busy” warning when a concurrent action has already claimed the service (HTTP 409), negative otherwise. In the WPF client the operations log through <code>ILogger</code> and, after a load, set the player panel's DispEngine to the isometric view. What a project change drives in the web shell is the layout's keep-alive epoch, not a canvas view: every cached page is discarded and rebuilt.</p>
|
||||
<p>Every Project action reports through two channels: a background progress line on the footer while it runs, then a toast when it lands — positive on success, a “busy” warning when a concurrent action has already claimed the service (HTTP 409), negative otherwise. What a project change drives in the shell is the layout's keep-alive epoch, not a canvas view: every cached page is discarded and rebuilt.</p>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p>The web implementation reports through the toast helper and the routine-progress footer store; the WPF client reports through <code>ILogger</code>. Neither routes project messages through MessageUtil. Project I/O is asynchronous on both clients, so the shell stays responsive during file I/O.</p>
|
||||
<p>Project actions report through the toast helper and the routine-progress footer store, and none of them routes a message through MessageUtil. Project I/O is asynchronous, so the shell stays responsive during file I/O.</p>
|
||||
</div>
|
||||
<h2 id="platform-specific-differences">Platform-Specific Differences</h2>
|
||||
<h3 id="wpf-application">WPF Application</h3>
|
||||
<ul>
|
||||
<li>Only a single instance of each sub-window (Mission, Workpiece, Fixture) can exist at a time</li>
|
||||
<li>There is no menu entry for the run cockpit: the Main Panel itself is the player</li>
|
||||
</ul>
|
||||
<h3 id="web-application">Web Application</h3>
|
||||
<ul>
|
||||
<li>The <a class="xref" href="../execution/index.html">Execution Page</a> is the landing route — <code>/</code> redirects to <code>/execution</code></li>
|
||||
|
||||
@@ -88,20 +88,18 @@
|
||||
<h1 id="preference-menu-dropdown">Preference Menu Dropdown</h1>
|
||||
|
||||
<p>The Preference dropdown holds the application's display settings, and it is on the <a class="xref" href="main-panel.html">Main Panel</a>. The server-backed ones are service-wide rather than per-account: one <code>UserService</code> singleton holds one <code>UserConfig</code>, saved to a single <code>UserConfig.xml</code> resolved against the process working directory, so every browser signed in to that service reads and writes the same values. The sign-in cookie carries a user-name claim that nothing outside the authentication endpoints reads, and no preference endpoint is keyed on an account.</p>
|
||||
<p>In the WPF application the menu binds <code>UserService</code>, whose <code>UserConfig</code> holds the persisted values. In the web application the dropdown has two models: Language and Show Physics Options bind the <code>appState</code> store, hydrated from and written back through <code>/api/preference/*</code>, where the server keeps them on <code>UserConfig</code>; the CSV / CL Controller checkboxes bind the device-local <code>useViewPrefs</code> singleton, persisted in the browser's <code>localStorage</code> and never sent to the server.</p>
|
||||
<p>The dropdown has two models: Language and Show Physics Options bind the <code>appState</code> store, hydrated from and written back through <code>/api/preference/*</code>, where the server keeps them on <code>UserConfig</code>; the CSV / CL Controller checkboxes bind the device-local <code>useViewPrefs</code> singleton, persisted in the browser's <code>localStorage</code> and never sent to the server.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<ul>
|
||||
<li>Preference Menu Dropdown
|
||||
<ul>
|
||||
<li><a class="xref" href="../execution/step-present-dialog.html">Step Present Preference</a> Button
|
||||
<ul>
|
||||
<li>WPF application: the first entry of the menu, opening the Step Present window.</li>
|
||||
<li>Web application: the editor belongs to the Execution page's Step Info column, where a small icon button in the Step Properties panel header opens it as a modal next to the list it configures.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="xref" href="../execution/graphic-cache-menu.html">Graphic-Cache Dropdown</a>
|
||||
<ul>
|
||||
<li>WPF application: a nested menu of cache fields inside the dropdown.</li>
|
||||
<li>Web application: an entry of the Execution page's <a class="xref" href="../execution/execution-extended-renderingcanvas-tool-bar.html">extended tool bar</a>, under <code>Meshed Geom ▾</code>, which gathers the workpiece rendering-cache settings.</li>
|
||||
<li>Its write is the one preference write that does not persist. <code>POST /api/preference/graphic-cache</code> clamps the requested size between the stored limits, assigns the three fields on the live <code>UserConfig</code> and returns, without calling <code>UserService.SaveUserConfig()</code>. The new value is service-wide and takes effect at once, but it reaches the file only when some later preference save writes the config out.</li>
|
||||
</ul>
|
||||
@@ -133,7 +131,7 @@
|
||||
<li>Show Log Button
|
||||
<ul>
|
||||
<li>See <a class="xref" href="bottom-message-bar.html">Message Section</a>.</li>
|
||||
<li>It is not a Preference-dropdown entry on either platform: the WPF application puts it on the bottom message bar, and the web application puts it on the menu bar's right side as an always-visible button that opens the Log Viewer page.</li>
|
||||
<li>It is not a Preference-dropdown entry: it sits on the menu bar's right side as an always-visible button that opens the Log Viewer page.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -165,10 +165,6 @@
|
||||
}
|
||||
</code></pre>
|
||||
<p>Add the update-table event per sink: <a class="xref" href="../../api/Hi.MachiningProcs.StepDiagnosticProgress.html#Hi_MachiningProcs_StepDiagnosticProgress_MessageAdded">MessageAdded</a> / <a class="xref" href="../../api/Hi.NcParsers.NcDiagnosticProgress.html#Hi_NcParsers_NcDiagnosticProgress_MessageAdded">MessageAdded</a>, and for the session-scoped shell sink the app-lifetime bridge <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_OnShellMessageAdded">OnShellMessageAdded</a> (with the matching <code>Cleared</code> events). The updating process has to be called by <a class="xref" href="../conventions/index.html">Loose Manner</a> for user experience.</p>
|
||||
<div class="TIP">
|
||||
<h5>Tip</h5>
|
||||
<p>On window desktop application (WPF), consider use textarea instead of datagrid to MessageTable for better performance. Use padding to show the different columns. And use the font in the textarea that with consistent width.</p>
|
||||
</div>
|
||||
<div class="NOTE">
|
||||
<h5>Note</h5>
|
||||
<p>The message display should be real-time.</p>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
<p>The main model is <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a> and its property <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a>.<a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a>.</p>
|
||||
<p>See <a class="xref" href="../../../technique/milling-physics/cutter-geometry.html">Cutter Geometry</a>. <a class="xref" href="../../../api/Hi.Milling.Apts.GeneralApt.html">GeneralApt</a> is the generalization of the other <a class="xref" href="../../../api/Hi.Milling.Apts.IAptBased.html">IAptBased</a> types.</p>
|
||||
<p>On the web client these fields have no panel of their own: they are rendered inline by the Flute Profile section of the cutter, the Control-Tree node whose role path is <code>toolhouse/tool-<id>/cutter/profile</code>, reached at <code>/tool-house/:toolId/cutter/profile</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. That same section carries the Profile Type selector above the fields. In the WPF client the APT fields are a component of their own, hosted by the Milling Cutter panel's Flute-Profile tab.</p>
|
||||
<p>These fields have no panel of their own: they are rendered inline by the Flute Profile section of the cutter, the Control-Tree node whose role path is <code>toolhouse/tool-<id>/cutter/profile</code>, reached at <code>/tool-house/:toolId/cutter/profile</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. That same section carries the Profile Type selector above the fields.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
@@ -155,29 +155,6 @@
|
||||
</table>
|
||||
<p>The interface casts live one layer down, on the read side: the cutter DTO builder fills <code>rc_mm</code>, <code>rr_mm</code>, <code>rz_mm</code>, <code>alpha_deg</code> and <code>beta_deg</code> by casting the APT to <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRc.html">IAptRc</a>, <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRr.html">IAptRr</a>, <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRz.html">IAptRz</a>, <a class="xref" href="../../../api/Hi.Milling.Apts.IAptAlpha.html">IAptAlpha</a> and <a class="xref" href="../../../api/Hi.Milling.Apts.IAptBeta.html">IAptBeta</a>, and emits null for a cast that fails.</p>
|
||||
<p>Taper APT is where the panel's table and the engine's types disagree. <a class="xref" href="../../../api/Hi.Milling.Apts.TaperApt.html">TaperApt</a> is declared over <code>IAptBased</code>, <code>IAptRz</code>, <code>IAptAlpha</code> and <code>IAptBeta</code> and carries no round radius, so the table's Rc entry gives a Taper profile a Round Radius box that the DTO fills with null — the field reads 0 — and the value the panel sends back is not read by the server's Taper branch, which builds the APT from Diameter, Rz, Alpha, Beta and Flute Height alone. Rc on a Taper APT is therefore inert in both directions.</p>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>APT Profile Panel
|
||||
<ul>
|
||||
<li>Diameter Input Field (mm)</li>
|
||||
<li>Round Radius Input Field (mm)
|
||||
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRc.html">IAptRc</a></li>
|
||||
<li>Round Ring Radius Input Field (mm)
|
||||
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRr.html">IAptRr</a></li>
|
||||
<li>Round Ring Height Input Field (mm)
|
||||
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptRz.html">IAptRz</a></li>
|
||||
<li>Bottom Cone Angle Input Field (deg)
|
||||
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptAlpha.html">IAptAlpha</a></li>
|
||||
<li>Top Cone Angle Input Field (deg)
|
||||
Visible if <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> is <a class="xref" href="../../../api/Hi.Milling.Apts.IAptBeta.html">IAptBeta</a></li>
|
||||
<li>Length of Cut Input Field (mm)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="TIP">
|
||||
<h5>Tip</h5>
|
||||
<p>Keep field format <code>G4</code> on this client. The web fields apply no format: they show the value as stored and commit on blur or Enter.</p>
|
||||
</div>
|
||||
<h2 id="features">Features</h2>
|
||||
<p>Every edit re-sends the whole profile. Changing the type, or any one field, builds a fresh shaper-profile request carrying the type, Diameter, Length of Cut and only those of Rc / Rr / Rz / Alpha / Beta that the chosen type's table lists, and the server replaces the cutter's <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a> with a newly constructed APT of that type. The panel then clears the tool cache so the canvas redraws.</p>
|
||||
<p>Clearing a field is ignored. The shared numeric input emits null for an empty box, and the panel returns on null instead of committing, so a blanked box keeps the previous value rather than writing 0.</p>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
|
||||
<h2 id="overview">Overview</h2>
|
||||
<p>The key component is <a class="xref" href="../../../api/Hi.Machining.ICutter.html">ICutter</a>. A tool carries at most one cutter, and two concrete types answer to that interface: <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html">MillingCutter</a> and <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html">FreeformRemover</a>. This panel is where the type is chosen, and it holds the cutter's own General fields.</p>
|
||||
<p>On the web client it is the Cutter tab of the <a class="xref" href="../index.html">Tool House Page</a>, reached at <code>/tool-house/:toolId/cutter</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. It is the panel of the Control-Tree Cutter node under the selected tool — the node whose role path is <code>toolhouse/tool-<id>/cutter</code>. In the WPF client the same surface is the Cutter Management Panel embedded in the tool's editor.</p>
|
||||
<p>It is the Cutter tab of the <a class="xref" href="../index.html">Tool House Page</a>, reached at <code>/tool-house/:toolId/cutter</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. It is the panel of the Control-Tree Cutter node under the selected tool — the node whose role path is <code>toolhouse/tool-<id>/cutter</code>.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
@@ -105,7 +105,7 @@
|
||||
<li>Sections Hint Caption — points at the section tabs below</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Freeform Remover branch — one caption, <code>toolhouse.cutter.freeformRemoverUnavailable</code>, sending the reader to the WPF client or HiNcRcl</li>
|
||||
<li>Freeform Remover branch — one caption, <code>toolhouse.cutter.freeformRemoverUnavailable</code>, saying the editor is not available here</li>
|
||||
<li>No-cutter branch — one hint, <code>toolhouse.cutter.noCutterHint</code>, inviting the reader to pick Milling Cutter</li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -113,39 +113,8 @@
|
||||
<p>The three numeric fields are the cutter's General fields, and they sit here under the Metadata-on-container convention — a container's own General fields are edited on the container's panel instead of in a General child. They are plain, always-editable inputs: one label each, no label switching and no auto-computed mode, and all three commit together through the general endpoint, which accepts exactly <code>shankMass_g</code>, <code>honeRadius_um</code> and <code>reliefAngle_deg</code>. A blanked box commits nothing, so clearing a field never writes a zero.</p>
|
||||
<p>The type also decides what grows below the node. A Milling Cutter grows the cutter's section tabs — Material, Flute Profile, Flute Contours, Upper Beam, Optimization — as the nodes whose role paths end in <code>.../cutter/material</code>, <code>.../cutter/profile</code>, <code>.../cutter/contours</code>, <code>.../cutter/upper-beam</code> and <code>.../cutter/opt</code>; Material is the one gated behind the Advanced Physics preference. Selecting one replaces this panel with that section's own panel; see <a class="xref" href="milling-cutter-panel.html">Milling Cutter Panel</a>. A Freeform Remover or no cutter grows nothing, so the Cutter node is a leaf and the caption or hint is the whole surface; see <a class="xref" href="freeform-remover-panel.html">Freeform Remover Panel</a>.</p>
|
||||
<p>This panel carries no object management of its own. Object management for the tool library sits on the tool-house root node, where the <a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a> is bound to the whole <code>.MachiningToolHouse</code> file rather than to a per-cutter file.</p>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Cutter Management Panel
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li><a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a>
|
||||
<ul>
|
||||
<li>File extension is <code>.Cutter</code>, load type <a class="xref" href="../../../api/Hi.Machining.ICutter.html">ICutter</a></li>
|
||||
<li>The pointed Editor Panel is the cutter content presenter below</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Title Label</li>
|
||||
<li>Cutter Type Selection Dropdown
|
||||
<ul>
|
||||
<li>Options: Milling Cutter, Freeform Remover, Unset</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Cutter Content Presenter
|
||||
Varies by the Cutter Type. It can be:
|
||||
<ul>
|
||||
<li><a class="xref" href="milling-cutter-panel.html">Milling Cutter Panel</a></li>
|
||||
<li><a class="xref" href="freeform-remover-panel.html">Freeform Remover Panel</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The per-cutter <code>.Cutter</code> file is this client's, and so is the third option's Unset wording; the web selector's third option reads None.</p>
|
||||
<h2 id="features">Features</h2>
|
||||
<p>Committing a type on the web is one server call plus a cache clear. Milling Cutter calls <code>EnsureCutter</code>, which keeps the tool's existing MillingCutter and only creates one when the tool has none; None calls <code>ClearCutter</code>, which drops the tool's cutter altogether. The panel then clears the tool cache, re-reads the tool and emits a structure change for its own node, which is how the section tabs appear or disappear with the type.</p>
|
||||
<p>Committing a type is one server call plus a cache clear. Milling Cutter calls <code>EnsureCutter</code>, which keeps the tool's existing MillingCutter and only creates one when the tool has none; None calls <code>ClearCutter</code>, which drops the tool's cutter altogether. The panel then clears the tool cache, re-reads the tool and emits a structure change for its own node, which is how the section tabs appear or disappear with the type.</p>
|
||||
<p>Cache clearing is not a step the user performs. <a class="xref" href="../../../api/Hi.Machining.ICutter.html">ICutter</a> implements <a class="xref" href="../../../api/Hi.Common.IClearCache.html">IClearCache</a>, and every cutter endpoint that changes a field or a geometry clears the cache server-side before it answers: the field endpoints call <code>ClearCache()</code> on the milling cutter directly, while the ones that change flute or beam geometry go through the controller's resync hook, which clears the cache <em>and</em> re-aligns the tool's holder-to-cutter anchor transformer so the cutter is re-placed under the holder at its new height. On top of that the panels call <code>clearToolCache(toolId)</code>, which clears the tool's cached solids and the holder's, so the tool canvas redraws.</p>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
|
||||
@@ -88,76 +88,18 @@
|
||||
<h1 id="freeform-remover-panel">Freeform Remover Panel</h1>
|
||||
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html">FreeformRemover</a>: a cutter whose removal volume comes from two referenced geometries — a non-cutting strut and a cutting shaper — anchored to the holder buckle.</p>
|
||||
<p>The two clients divide this cutter between them. The WPF client owns the editing surface: both geometries, the anchor, the spinning flag and the identity fields. The web client offers the type in the Cutter Type selector and nothing more; there is no Freeform Remover editor on the web, and no freeform-remover endpoint in the backend, so a freeform remover is built and edited on the WPF client or through HiNcRcl.</p>
|
||||
<p>This cutter is offered in the Cutter Type selector and nowhere else. There is no Freeform Remover editor here and no freeform-remover endpoint in the backend, so nothing on this surface can create or change one — the shipped caption says as much, naming the WPF client and HiNcRcl.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Freeform Remover Panel
|
||||
<ul>
|
||||
<li>Tabs
|
||||
<ul>
|
||||
<li>Strut Geometry Tab
|
||||
<ul>
|
||||
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Panel</a>
|
||||
<ul>
|
||||
<li>Manages <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_StrutGeom">StrutGeom</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Shaper Geometry Tab
|
||||
<ul>
|
||||
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Panel</a>
|
||||
<ul>
|
||||
<li>Manages <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_ShaperGeom">ShaperGeom</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Anchor Tab
|
||||
<ul>
|
||||
<li>Label: Geometry Anchor To Holder Buckle</li>
|
||||
<li><a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_KeepHolderBuckleOnTop">KeepHolderBuckleOnTop</a> Checkbox</li>
|
||||
<li><a class="xref" href="../../geom/transformer-panel.html">Transformer Manage Panel</a>
|
||||
<ul>
|
||||
<li>Model is <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_GeomToHolderTransformer">GeomToHolderTransformer</a></li>
|
||||
<li>Enabled if <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_KeepHolderBuckleOnTop">KeepHolderBuckleOnTop</a> is true.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Property Tab
|
||||
<ul>
|
||||
<li>Is Spinning Cutter Checkbox
|
||||
<ul>
|
||||
<li>Controls <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_IsSpinningCutter">IsSpinningCutter</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Info Tab
|
||||
<ul>
|
||||
<li>Name TextField (editable)</li>
|
||||
<li>AbstractNote TextField (readonly)</li>
|
||||
<li>Note TextField (editable)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>This panel calls <a class="xref" href="../../../api/Hi.Machining.FreeformRemover.html#Hi_Machining_FreeformRemover_ClearCache">ClearCache()</a> itself after a geometry or anchor change, so the cached solids are dropped before the tool is redrawn.</p>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
<li>Cutter Node Panel, the Cutter tab of the <a class="xref" href="../index.html">Tool House Page</a> at <code>/tool-house/:toolId/cutter</code> — the Control-Tree node <code>toolhouse/tool-<id>/cutter</code>
|
||||
<ul>
|
||||
<li>Cutter Type Selector — its second option, Freeform Remover, is this cutter</li>
|
||||
<li>Freeform Remover Caption (<code>toolhouse.cutter.freeformRemoverUnavailable</code>) — the panel's whole body while that option is showing, directing the reader to the WPF client or HiNcRcl</li>
|
||||
<li>Freeform Remover Caption (<code>toolhouse.cutter.freeformRemoverUnavailable</code>) — the panel's whole body while that option is showing</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Nothing else on the web belongs to this cutter. The Shank Mass / Hone Radius / Relief Angle fields on that panel are gated to the Milling Cutter branch, and the cutter's child builder grows section tabs only for a MillingCutter, so the Cutter node is a leaf here: no Material, Flute Profile, Flute Contours, Upper Beam or Optimization section appears. See <a class="xref" href="cutter-panel.html">Cutter Panel</a> for the panel these live on.</p>
|
||||
<p>Nothing else on this surface belongs to this cutter. The Shank Mass / Hone Radius / Relief Angle fields on that panel are gated to the Milling Cutter branch, and the cutter's child builder grows section tabs only for a MillingCutter, so the Cutter node is a leaf here: no Material, Flute Profile, Flute Contours, Upper Beam or Optimization section appears. See <a class="xref" href="cutter-panel.html">Cutter Panel</a> for the panel these live on.</p>
|
||||
<h2 id="geometry-definitions">Geometry Definitions</h2>
|
||||
<ul>
|
||||
<li><strong>Strut Geometry</strong> — The non-cutting portion (holder/shank)
|
||||
@@ -173,10 +115,10 @@
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="features">Features</h2>
|
||||
<p>Picking Freeform Remover on the web is a no-op that does not stick. The panel makes no API call for that option — it sets the selector locally, clears the tool cache, then re-reads the tool, and the re-read is what puts the selector back to Milling Cutter or None. The model on the tool is left exactly as it was.</p>
|
||||
<p>Picking Freeform Remover is a no-op that does not stick. The panel makes no API call for that option — it sets the selector locally, clears the tool cache, then re-reads the tool, and the re-read is what puts the selector back to Milling Cutter or None. The model on the tool is left exactly as it was.</p>
|
||||
<p>A tool that already carries a freeform remover reads as None. The tool detail casts the tool's cutter to a MillingCutter and reports both <code>hasCutter</code> and the embedded cutter DTO from that one cast, so a non-milling cutter comes back as no cutter at all, and the selector — which derives its value from those two fields — shows None. The Freeform Remover option is therefore reachable by the user's click but never by a load.</p>
|
||||
<p>That makes one sequence worth knowing before using the web page on such a tool: picking Milling Cutter calls <code>EnsureCutter</code>, which returns the tool's existing cutter only when it is already a MillingCutter and otherwise assigns a new one — so on a tool holding a freeform remover, that choice replaces it. Leaving the selector alone leaves the freeform remover intact, which is what a round trip through the web page does by default.</p>
|
||||
<p>Cache clearing needs no user action on either client. The WPF panel clears the remover's cache after each geometry or anchor edit; on the web there is nothing to clear for this cutter, since no endpoint mutates it, and the tool-cache clear the selector performs only drops the tool's and the holder's cached solids so the canvas redraws.</p>
|
||||
<p>Cache clearing needs no user action: there is nothing to clear for this cutter, since no endpoint mutates it, and the tool-cache clear the selector performs only drops the tool's and the holder's cached solids so the canvas redraws.</p>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
|
||||
|
||||
@@ -87,8 +87,8 @@
|
||||
<article data-uid="Anatomy-MillingCutterPanel">
|
||||
<h1 id="milling-cutter-panel">Milling Cutter Panel</h1>
|
||||
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html">MillingCutter</a>, the cutter type both clients edit in full.</p>
|
||||
<p>On the web client this cutter is not one panel but the section tabs the <a class="xref" href="cutter-panel.html">Cutter Panel</a> grows once a Milling Cutter is assigned: the Control-Tree nodes under <code>toolhouse/tool-<id>/cutter</code>, reached at <code>/tool-house/:toolId/cutter/:subtab</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. The five <code>:subtab</code> values are <code>material</code>, <code>profile</code>, <code>contours</code>, <code>upper-beam</code> and <code>opt</code>. The cutter's General fields — Shank Mass, Hone Radius, Relief Angle — are not among them: they sit on the Cutter node's own panel. In the WPF client the same cutter is one tab control, and it carries several groups the web does not offer.</p>
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html">MillingCutter</a>, the one cutter type edited here in full.</p>
|
||||
<p>This cutter is not one panel but the section tabs the <a class="xref" href="cutter-panel.html">Cutter Panel</a> grows once a Milling Cutter is assigned: the Control-Tree nodes under <code>toolhouse/tool-<id>/cutter</code>, reached at <code>/tool-house/:toolId/cutter/:subtab</code> under the page route <code>/tool-house/:toolId?/:tab?/:subtab?</code>. The five <code>:subtab</code> values are <code>material</code>, <code>profile</code>, <code>contours</code>, <code>upper-beam</code> and <code>opt</code>. The cutter's General fields — Shank Mass, Hone Radius, Relief Angle — are not among them: they sit on the Cutter node's own panel.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
@@ -102,8 +102,8 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Material is the only physics-gated section. Flute Profile, Flute Contours, Upper Beam and Optimization grow for every Milling Cutter. The preference behind the gate is the SPA's Advanced Physics option, held as <code>isShowPhysicsOptions</code> in the app-state store and read from the server's preference endpoint, which reports it as on only while the physics feature is licensed. <code>UserService.EnablePhysics</code> is the WPF client's name for the same preference.</p>
|
||||
<p>Integral mode is read-only on the web. The cutter DTO reports it, and the Material section reads it to decide whether the Shank Material picker applies, but no endpoint sets it; it is chosen on the WPF client's Property tab.</p>
|
||||
<p>Material is the only physics-gated section. Flute Profile, Flute Contours, Upper Beam and Optimization grow for every Milling Cutter. The preference behind the gate is the SPA's Advanced Physics option, held as <code>isShowPhysicsOptions</code> in the app-state store and read from the server's preference endpoint, which reports it as on only while the physics feature is licensed.</p>
|
||||
<p>Integral mode is read-only. The cutter DTO reports it, and the Material section reads it to decide whether the Shank Material picker applies, but no endpoint sets it.</p>
|
||||
<h4 id="material-section">Material Section</h4>
|
||||
<ul>
|
||||
<li>Material Section (<code>.../cutter/material</code>)
|
||||
@@ -180,7 +180,7 @@ Manages <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html
|
||||
</ul>
|
||||
<p>The five types are all wrapped by <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html">AptProfile</a>, with a different <a class="xref" href="../../../api/Hi.Milling.Cutters.AptProfile.html#Hi_Milling_Cutters_AptProfile_Apt">Apt</a> assigned; which fields appear depends on the type. See <a class="xref" href="apt-profile-panel.html">APT Profile Panel</a> for the field list and the per-type table that drives it.</p>
|
||||
<p>See the <code>DemoBuildMachiningProject</code> sample in the <a class="xref" href="../../../technique/api-foundations/packages-and-samples.html">Hi.Sample repository</a> for creating the APT profile and setting it on the cutter.</p>
|
||||
<p><code>CustomSpinningProfile</code> is the WPF client's sixth profile type; the web offers the five APT types only.</p>
|
||||
<p><code>CustomSpinningProfile</code> is not offered here; the five APT types are.</p>
|
||||
<h4 id="flute-contours-section">Flute Contours Section</h4>
|
||||
<p>This part manages <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_Fluting">Fluting</a>. It is a stem, not a leaf: the section node carries only the type selector, and the fluting itself is a sub-tree of nodes below it.</p>
|
||||
<ul>
|
||||
@@ -277,58 +277,7 @@ Manages <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html
|
||||
</li>
|
||||
</ul>
|
||||
<p>Both checkboxes are plain labelled checkboxes — neither displays a computed value. The server's defaults when a limit set is written without them are a Yielding Safety Factor of 3 (a utilization factor of about 0.33), a Max Feed Per Tooth of 999, and both limit flags on.</p>
|
||||
<p>The minimum uncut chip thickness itself is not on this surface: no cutter endpoint returns it, and no field displays it. It is the WPF client's Optimization panel that computes it from the cutter and the project workpiece's cutting parameter and shows it beside the checkbox.</p>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Milling Cutter Panel
|
||||
<ul>
|
||||
<li>Tabs
|
||||
<ul>
|
||||
<li>Flute-Profile Tab — the profile type dropdown plus the APT panel, and the <code>CustomSpinningProfile</code> option with its own geometry-management panel</li>
|
||||
<li>Upper-Beam Tab
|
||||
<ul>
|
||||
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Control</a>, with the <a class="xref" href="../../../api/Hi.Geom.ExtendedCylinder.html">ExtendedCylinder</a> option enabled</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Property Tab
|
||||
<ul>
|
||||
<li>Integral Mode Selection Dropdown — Solid End / Insert End</li>
|
||||
<li>Cutter/Shank Mass Input Field (g), with an Auto Update CheckBox driven by <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_ShankMassAssignmentMode">ShankMassAssignmentMode</a>: when enabled the field turns readonly and shows the mass computed from the inner-beam and upper-beam volume and the density</li>
|
||||
<li>Hone Radius (um) and Relief Angle (deg) Input Fields</li>
|
||||
<li>Minimum Available Cutting Thickness (um), readonly, from <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_GetMinimumUncutChipThickness_um_Hi_MillingForces_Fittings_ICuttingPara_">GetMinimumUncutChipThickness_um(ICuttingPara)</a> with the project workpiece's <a class="xref" href="../../../api/Hi.NcMech.Workpieces.Workpiece.html#Hi_NcMech_Workpieces_Workpiece_CuttingPara">CuttingPara</a>, and a note label naming that cutting parameter</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Insert-Cutter Tab
|
||||
<ul>
|
||||
<li>Insert Number, Insert Mass (g) and Insert Thickness (mm) Input Fields; the thickness feeds heat transfer</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Material Tab</li>
|
||||
<li>Flute-Contours Tab</li>
|
||||
<li>Flute-Inner-Beam Tab
|
||||
<ul>
|
||||
<li>Profile Type Selection Dropdown for <a class="xref" href="../../../api/Hi.Milling.Cutters.MillingCutter.html#Hi_Milling_Cutters_MillingCutter_InnerBeamProfile">InnerBeamProfile</a> — Flute Dependent Ratio (<a class="xref" href="../../../api/Hi.Milling.Cutters.FluteDependentRatioProfile.html">FluteDependentRatioProfile</a>), Const Ratio (<a class="xref" href="../../../api/Hi.Milling.Cutters.ConstRatioProfile.html">ConstRatioProfile</a>), Custom Spinning (<a class="xref" href="../../../api/Hi.Milling.Cutters.CustomSpinningProfile.html">CustomSpinningProfile</a>)</li>
|
||||
<li>For Flute Dependent Ratio: a readonly Radius Ratio field whose label also names the flute number it depends on</li>
|
||||
<li>For Const Ratio: an editable Radius Ratio field</li>
|
||||
<li>For Custom Spinning: a <a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Control</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Optimization Tab — the same limits as the web section, plus the computed minimum uncut chip thickness beside the minimum-feed checkbox</li>
|
||||
<li>Info Tab
|
||||
<ul>
|
||||
<li>Name TextField (editable)</li>
|
||||
<li>AbstractNote TextField (readonly)</li>
|
||||
<li>Note TextField (editable)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p><code>UserService.EnablePhysics</code> gates the Property, Material, Flute-Contours, Flute-Inner-Beam and Optimization tabs on this client; the Insert-Cutter tab additionally requires Insert End. Flute-Profile, Upper-Beam and Info are always visible. On the web only the Material section is gated, and the same preference is named <code>isShowPhysicsOptions</code>.</p>
|
||||
<p>Numeric fields on this client are formatted <code>G4</code>. The web's numeric field applies no format: it shows the value as stored and commits on blur or Enter.</p>
|
||||
<p>The cutter has no identity fields on the web. Tool ID, Note and the auto-derived Abstract Note belong to the tool, one level up, and are edited on the tool's own General tab; see <a class="xref" href="../index.html">Tool House Page</a>.</p>
|
||||
<p>The minimum uncut chip thickness itself is not on this surface: no cutter endpoint returns it, and no field displays it.</p>
|
||||
<h2 id="features">Features</h2>
|
||||
<p>Every web edit is a whole-object commit followed by a cache clear. The Flute Profile panel re-sends the entire shaper profile on any field change — only the fields the selected APT type carries are included — then clears the tool cache. The contour panels re-send the whole flute contour. The optimization panel re-sends the whole limit set. The material and coating endpoints each answer with the full cutter DTO, which the panels re-render from.</p>
|
||||
<p>A blanked numeric box commits nothing. The shared numeric field emits null for an empty entry, and every cutter panel returns on null rather than writing a zero, so clearing a field leaves the stored value alone.</p>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<h1 id="cylindroid-holder-panel">Cylindroid Holder Panel</h1>
|
||||
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html">CylindroidHolder</a>: a holder revolved from a Z-R profile, carrying its own name and note and its own STL tessellation resolution.</p>
|
||||
<p>On the web client the holder occupies two child sections of the Holder node under the selected tool — Geometry and Resolution, the nodes whose role paths end in <code>.../holder/geometry</code> and <code>.../holder/resolution</code>, reached at <code>/tool-house/:toolId/holder/geometry</code> and <code>/tool-house/:toolId/holder/resolution</code>. Its Name, readonly Abstract Note and Note are edited one level up, on the <a class="xref" href="holder-panel.html">Holder Panel</a> itself, under the Metadata-on-container convention. Every field ships on both clients; what differs is the surface hosting them — the WPF client gives the same three fields a tab of their own.</p>
|
||||
<p>The holder occupies two child sections of the Holder node under the selected tool — Geometry and Resolution, the nodes whose role paths end in <code>.../holder/geometry</code> and <code>.../holder/resolution</code>, reached at <code>/tool-house/:toolId/holder/geometry</code> and <code>/tool-house/:toolId/holder/resolution</code>. Its Name, readonly Abstract Note and Note are edited one level up, on the <a class="xref" href="holder-panel.html">Holder Panel</a> itself, under the Metadata-on-container convention.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
@@ -106,38 +106,6 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Cylindroid Holder Panel
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li>Title Label</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Tabs
|
||||
<ul>
|
||||
<li>Geometry Tab
|
||||
<ul>
|
||||
<li><a class="xref" href="../../geom/cylindroid-control.html">Cylindroid Panel</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Resolution Tab
|
||||
Model: <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_PolarResolution2d">PolarResolution2d</a>
|
||||
<a class="xref" href="../../widget/polar-resolution-2d-panel.html">Polar Resolution 2d</a></li>
|
||||
<li>Info Tab
|
||||
<ul>
|
||||
<li>Name TextField (editable)</li>
|
||||
<li>AbstractNote TextField (readonly)</li>
|
||||
<li>Note TextField (editable)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Remember to call <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_UpdateByCylindroid">UpdateByCylindroid()</a> after geometry reference or content changed.</p>
|
||||
<h2 id="feature">Feature</h2>
|
||||
<p>The two web sections reach the model by different routes, and that difference is why the holder resync belongs to one of them and not the other.</p>
|
||||
<p><strong>Geometry.</strong> The section mounts the reusable Cylindroid editor on a key. <code>Get</code> publishes the holder's own <a class="xref" href="../../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_Cylindroid">Cylindroid</a> in the index service under a per-session <code>-HolderCylindroid</code> key and hands that key back — but only when the caller supplies its session key; with no session key the response carries a null key and the section shows its initializing caption in the editor's place. The key names the same object the holder holds, so an edit lands on the holder's geometry directly. Because that generic editor mutates the bare geometry and holds no reference back to the holder, the section issues the holder resync itself after each geometry edit: <code>UpdateGeometryContent</code> runs <code>UpdateByCylindroid()</code> and then <code>ClearCache()</code>, recomputing the holder topology before regenerating the solid — clearing the cache alone would skip the recompute. The slave column mounts only the selected node's panel, so at most one holder-geometry panel is alive at a time and the shared key never collides.</p>
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<h1 id="freeform-holder-panel">Freeform Holder Panel</h1>
|
||||
|
||||
<p>The key model is <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a>: a holder whose shape comes from a referenced geometry, typically an STL, positioned by two anchor transformers — one to the spindle, one to the cutter.</p>
|
||||
<p>On the web client the holder occupies four child sections of the Holder node under the selected tool — Geometry, Geom To Spindle, Geom To Cutter and Resolution, the nodes whose role paths end in <code>.../holder/geometry</code>, <code>.../holder/geom-to-spindle</code>, <code>.../holder/geom-to-cutter</code> and <code>.../holder/resolution</code>, reached at <code>/tool-house/:toolId/holder/:subtab</code>. Its Name, readonly Abstract Note and Note are edited one level up, on the <a class="xref" href="holder-panel.html">Holder Panel</a> itself, under the Metadata-on-container convention. Every field ships on both clients; what differs is the surface hosting them — the WPF client gives the same fields a tab strip of its own.</p>
|
||||
<p>The holder occupies four child sections of the Holder node under the selected tool — Geometry, Geom To Spindle, Geom To Cutter and Resolution, the nodes whose role paths end in <code>.../holder/geometry</code>, <code>.../holder/geom-to-spindle</code>, <code>.../holder/geom-to-cutter</code> and <code>.../holder/resolution</code>, reached at <code>/tool-house/:toolId/holder/:subtab</code>. Its Name, readonly Abstract Note and Note are edited one level up, on the <a class="xref" href="holder-panel.html">Holder Panel</a> itself, under the Metadata-on-container convention.</p>
|
||||
<p>The three shape sections are not holder-specific editors. They are the same generic Geometry and Transformer slots the <a class="xref" href="../../general-setup/fixture.html">Fixture</a> branch of the General Setup page is built from: a kind picker on the section node, and the chosen kind's own editor on the child node below it. So an STL holder is picked as <code>StlFile</code> and its source file set through the shared StlFile editor, a <code>TransformationGeom</code> holder grows Inner Geometry and Inner Transformer nodes, a <code>GeomCombination</code> holder grows one node per item, and each placement grows the chosen transformer kind's editor — Static Translation for the usual <code>(0, 0, h)</code> offset.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
@@ -118,52 +118,13 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Freeform Holder Panel
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li>Title Label</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Tabs
|
||||
<ul>
|
||||
<li>Geometry Tab
|
||||
<ul>
|
||||
<li><a class="xref" href="../../geom/geom-manage-control.html">Geometry Management Panel</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Anchor Tab
|
||||
(Apply <a class="xref" href="../../geom/transformer-panel.html">Transformer Manage Panel</a> to set the following tabs)
|
||||
<ul>
|
||||
<li>Geom To Spindle Tab</li>
|
||||
<li>Geom To Cutter Tab</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Resolution Tab
|
||||
Model: <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_PolarResolution2d">PolarResolution2d</a>
|
||||
<a class="xref" href="../../widget/polar-resolution-2d-panel.html">Polar Resolution 2d</a></li>
|
||||
<li>Info Tab
|
||||
<ul>
|
||||
<li>Name TextField (editable)</li>
|
||||
<li>AbstractNote TextField (readonly)</li>
|
||||
<li>Note TextField (editable)</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Remember to call <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_UpdateByGeom">UpdateByGeom()</a> after geometry reference or content changed.</p>
|
||||
<h2 id="feature">Feature</h2>
|
||||
<p>The generic editors reach the holder's own members, and that is what makes the split work. When the Holder node's children are built, the page calls <code>FreeformHolderController</code>'s <code>Get</code> with its session key; the server publishes the holder's <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_Geom">Geom</a>, <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_GeomToSpindleTransformer">GeomToSpindleTransformer</a> and <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html#Hi_NcMech_Holders_FreeformHolder_GeomToCutterTransformer">GeomToCutterTransformer</a> in the index service under three per-session keys (<code>-HolderGeom</code>, <code>-HolderGeomToSpindle</code>, <code>-HolderGeomToCutter</code>) and hands the keys back. The keys name the very objects the holder holds, so an edit through a kind editor lands on the holder directly. The keys are returned even when a member is empty — nothing is published then, the section's picker reads an empty slot, and picking a kind fills that same key — which is how a freshly switched-to Freeform holder, whose geometry starts empty, gets its first shape.</p>
|
||||
<p>Picking a kind is a container-aware create, not a bare <code>New</code>. The Geometry picker calls <code>CreateGeometry</code>, which builds the geometry, sets it as the holder's <code>Geom</code> and publishes it under the section's key (None clears the geometry). A placement picker first creates the transformer through the kind's own <code>New</code> endpoint and then attaches it with <code>UpdateGeomToSpindleTransformer</code> or <code>UpdateGeomToCutterTransformer</code>. Without the attach, only the index-service entry would change and the holder would keep pointing at its old transformer.</p>
|
||||
<p>Because the generic editors hold no reference back to the holder, every edit at or below a section ends in the holder resync the page wires onto the section: a geometry edit calls <code>UpdateGeometryContent</code>, a placement edit re-attaches the transformer under its key. Both run <code>UpdateByGeom()</code> to regenerate the solid, <code>ClearCache()</code>, and <code>AlignAnchorByExposedCutterHeight()</code> to re-place the cutter under the holder — clearing the cache alone would leave the cutter where it was. The page then refreshes the tool list and the canvas.</p>
|
||||
<p>The Resolution section writes the polar resolution straight onto the holder: <code>SetPolarResolution</code> assigns a fresh <a class="xref" href="../../../api/Hi.Geom.Resolution.PolarResolution2d.html">PolarResolution2d</a> and the holder swaps its solid for one born with the new value, keeping the geometry. <code>Get</code> also returns the current pair, which is how the two fields are seeded.</p>
|
||||
<p>Guards sit on both sides. Every action on the controller answers Not Found for an unknown tool id and Bad Request when the tool's holder is not a <code>FreeformHolder</code>; <code>SetPolarResolution</code> rejects a linear or angle value that is not greater than zero, and the Resolution section refuses to send one. Fields commit on blur or Enter.</p>
|
||||
<p>Switching a tool to Freeform is a committing choice. <code>SetHolderType</code> assigns a new <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a> only when the tool does not already carry one, so a holder authored on the WPF client or through HiNcRcl survives a round trip through the web page with its geometry, anchors and resolution intact.</p>
|
||||
<p>Switching a tool to Freeform is a committing choice. <code>SetHolderType</code> assigns a new <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a> only when the tool does not already carry one, so a holder authored elsewhere — through HiNcRcl, say — survives a round trip through this page with its geometry, anchors and resolution intact.</p>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<p>See <a class="xref" href="../../index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<p>HiNC-2025-webservice (Quasar CLI SPA):</p>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
<li><strong><a class="xref" href="freeform-holder-panel.html">Freeform Holder</a></strong>: Represents holders with more complex, freeform geometry, often defined by STL files. See <a class="xref" href="../../../api/Hi.NcMech.Holders.FreeformHolder.html">FreeformHolder</a>.</li>
|
||||
</ul>
|
||||
<p>Each holder type has its own user interface elements for defining its geometry and properties.</p>
|
||||
<p>On the web client this panel is the Holder tab of the <a class="xref" href="../index.html">Tool House Page</a>, reached at <code>/tool-house/:toolId/holder</code>. It is the panel of the Control-Tree Holder node under the selected tool — the node whose role path ends in <code>.../holder</code>.</p>
|
||||
<p>This panel is the Holder tab of the <a class="xref" href="../index.html">Tool House Page</a>, reached at <code>/tool-house/:toolId/holder</code>. It is the panel of the Control-Tree Holder node under the selected tool — the node whose role path ends in <code>.../holder</code>.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
@@ -121,33 +121,8 @@
|
||||
<p>The three identity fields belong to whichever holder the tool carries. They sit on this panel under the Metadata-on-container convention — a container's own General fields are edited on the container's panel instead of in a General child — and they commit through the per-type holder controller's <code>SetName</code> and <code>SetNote</code> (<code>CylindroidHolderController</code> or <code>FreeformHolderController</code>), not through <code>ToolHouseController</code>. No holder leaves the panel without them.</p>
|
||||
<p>The type also decides what grows below the node. A Cylindroid holder grows two child sections, Geometry and Resolution — the nodes whose role paths end in <code>.../holder/geometry</code> and <code>.../holder/resolution</code>; see <a class="xref" href="cylindroid-holder-panel.html">Cylindroid Holder Panel</a>. A Freeform holder grows four — Geometry, Geom To Spindle, Geom To Cutter and Resolution; see <a class="xref" href="freeform-holder-panel.html">Freeform Holder Panel</a>. Selecting a section replaces this panel in the slave column with that section's own panel. None grows no children, so the Holder node is a leaf and the hint is the whole surface.</p>
|
||||
<p>This panel carries no object management of its own. Object management for the tool library sits on the tool-house root node, where the <a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a> is bound to the whole <code>.MachiningToolHouse</code> file rather than to a per-holder file.</p>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Holder Panel
|
||||
<ul>
|
||||
<li>Head Line
|
||||
<ul>
|
||||
<li><a class="xref" href="../../widget/object-management-menu-button.html">Object Management Menu Button</a>
|
||||
<ul>
|
||||
<li>File extension is <code>.Holder</code>, load type <a class="xref" href="../../../api/Hi.NcMech.Holders.IHolder.html">IHolder</a></li>
|
||||
<li>The pointed Editor Panel is the Holder Sub Management Panel.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Title Label</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Holder Management Panel
|
||||
<ul>
|
||||
<li>Holder Type Selection Bar — None / Cylindroid / Freeform</li>
|
||||
<li>Holder Sub Management Panel
|
||||
A ContentPresenter whose content varies by the Holder Type: the <a class="xref" href="cylindroid-holder-panel.html">Cylindroid Holder Panel</a>, the <a class="xref" href="freeform-holder-panel.html">Freeform Holder Panel</a>, or nothing for None.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="feature">Feature</h2>
|
||||
<p>Committing a type on the web is one server call plus a cache clear. <code>SetHolderType</code> maps the selector value onto the holder classes: none clears the tool's holder, while cylindroid and freeform each assign a new holder <strong>only when the tool does not already carry one of that class</strong> — so re-picking the type a tool already has keeps the holder it has, and the edits on it, rather than replacing it. When the caller passes its session key the server re-indexes the resulting holder under that session's holder key, and removes that entry for None, so the session key keeps pointing at the tool's current holder. The response carries the holder's class name and its abstract note.</p>
|
||||
<p>Committing a type is one server call plus a cache clear. <code>SetHolderType</code> maps the selector value onto the holder classes: none clears the tool's holder, while cylindroid and freeform each assign a new holder <strong>only when the tool does not already carry one of that class</strong> — so re-picking the type a tool already has keeps the holder it has, and the edits on it, rather than replacing it. When the caller passes its session key the server re-indexes the resulting holder under that session's holder key, and removes that entry for None, so the session key keeps pointing at the tool's current holder. The response carries the holder's class name and its abstract note.</p>
|
||||
<p>The panel then calls <code>ClearToolCache</code>, which clears the tool's cached solids and, when the holder implements <a class="xref" href="../../../api/Hi.Common.IClearCache.html">IClearCache</a>, the holder's own cache as well, so the tool canvas redraws against the new holder. Finally it emits a structure change for its own node, which is how the Geometry and Resolution sections appear or disappear with the type.</p>
|
||||
<p><code>GetHolder</code> reports the same pair — class name and abstract note — and is what the panel reads on mount to seed the selector; an unknown tool id answers Not Found. The panel then reads the per-type controller's <code>Get</code> (<code>CylindroidHolderController</code> or <code>FreeformHolderController</code>) to fill the three identity fields; for a Freeform holder that same call also publishes the holder's geometry and two placements under the session's keys for the sections below.</p>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
|
||||
@@ -87,9 +87,9 @@
|
||||
<article data-uid="Anatomy-ToolHousePage">
|
||||
<h1 id="tool-house-page">Tool House Page</h1>
|
||||
|
||||
<p>The Tool House is a page of its own at <code>/tool-house/:toolId?/:tab?/:subtab?</code>, reached from the menu bar's <code>Page ▾</code> dropdown. In the WPF client it is a sub-window opened from the <a class="xref" href="../shell/main-panel.html">Main Panel</a>.</p>
|
||||
<p>The Tool House is a page of its own at <code>/tool-house/:toolId?/:tab?/:subtab?</code>, reached from the menu bar's <code>Page ▾</code> dropdown.</p>
|
||||
<p>The key model is MachiningToolHouse.
|
||||
The model <code>UserService</code> is per-client. On the web it is the server-side <code>Environments/UserService.cs</code>, which <code>Mech/ToolHouseDisplayController.cs</code> reads <code>EnablePhysics</code> from; the WPF client resolves its own <code>UserService</code> from the application's service provider.</p>
|
||||
The model <code>UserService</code> is the server-side <code>Environments/UserService.cs</code>, which <code>Mech/ToolHouseDisplayController.cs</code> reads <code>EnablePhysics</code> from.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<p>Three columns, left to right, in two nested resizable splitters — the tool house and its tool list, the selected tool's editor tabs, and the tool canvas. Creating a tool opens no window of its own: <strong>New Tool</strong> adds a default tool and the user sets it up in the editor tabs.</p>
|
||||
<ul>
|
||||
@@ -164,8 +164,8 @@ The model <code>UserService</code> is per-client. On the web it is the server-si
|
||||
</li>
|
||||
</ul>
|
||||
<p>The three anchor-and-buckle flags of <a class="xref" href="../../api/Hi.NcMech.Holders.HolderEditorDisplayee.html">HolderEditorDisplayee</a> and the Holder Rendering Mode radios are all disabled while Show Holder is off, so a child option is reachable only when its parent is on. The menu is one flat list of labelled groups rather than nested submenus, which is what keeps it one click deep.</p>
|
||||
<p>The cutter's shape mode is not a control here. The server picks it when the canvas binds: <code>InitializeDisplay</code> sets <a class="xref" href="../../api/Hi.Milling.Cutters.MillingCutterEditorDisplayee.html#Hi_Milling_Cutters_MillingCutterEditorDisplayee_ShapeMode">ShapeMode</a> to Solid Bounding Shape whenever <code>UserService.EnablePhysics</code> is false, and the web Display Options dropdown offers no switch for it. The WPF page is the client whose Editor Displayee Options menu carries the Solid Bounding Shape / Detail Physics Shape radio submenu.</p>
|
||||
<p>The left column is the other place the two clients differ. The WPF Tool House page lists its tools in a DataGrid with a checkbox column, an editable Tool ID column and a read-only Note column, and puts a Batch Actions menu above it — Select All, De-Select All, then Batch Duplicate and Batch Delete — with Duplicate and Delete also on the grid's context menu. On the web page Tool ID and Note are edited on the selected tool's General tab, where Duplicate and Delete are per-tool icon buttons, so the list itself stays a plain navigation column of router links.</p>
|
||||
<p>The cutter's shape mode is not a control here. The server picks it when the canvas binds: <code>InitializeDisplay</code> sets <a class="xref" href="../../api/Hi.Milling.Cutters.MillingCutterEditorDisplayee.html#Hi_Milling_Cutters_MillingCutterEditorDisplayee_ShapeMode">ShapeMode</a> to Solid Bounding Shape whenever <code>UserService.EnablePhysics</code> is false, and the Display Options dropdown offers no switch for it.</p>
|
||||
<p>The left column carries no editing of its own. Tool ID and Note are edited on the selected tool's General tab, where Duplicate and Delete are per-tool icon buttons, so the list stays a plain navigation column of router links. There is no batch selection and no batch action.</p>
|
||||
<p>The Tool ID can not be repeated. Create Tool takes the largest existing ID plus 1 (or 1 in an empty house), Duplicate Tool inserts the clone at the first free ID past both the source and the largest existing ID, and renaming a tool onto an ID the house already holds is refused as a conflict.</p>
|
||||
<p>When the canvas first binds, <code>InitializeDisplay</code> attaches the <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingToolEditorDisplayee.html">MillingToolEditorDisplayee</a> and snaps the camera to the isometric view. Each later tool selection re-points that displayee's <code>MillingToolGetter</code> at the chosen tool and calls the renderingCanvas.<a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.<a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_SetViewToHomeView">SetViewToHomeView()</a>.</p>
|
||||
<h3 id="duplication-button">Duplication Button</h3>
|
||||
@@ -211,8 +211,8 @@ The model <code>UserService</code> is per-client. On the web it is the server-si
|
||||
<h5>Note</h5>
|
||||
<p>The fluting type is named loosely on the wire, and every spelling resolves. <code>PUT /{id}/fluting</code> accepts <code>UniformFluting</code> / <code>uniform</code> and <code>FreeFluting</code> / <code>free</code>, and equally <code>UniformContourTray</code> / <code>FreeContourTray</code>. A Control-Tree id whose cutter branch reads <code>…/contours/tray…</code> resolves to the <code>…/contours/fluting…</code> node.</p>
|
||||
</div>
|
||||
<p>One editor lives on the WPF client only, and the app says so where the type is chosen: the <strong>FreeformRemover</strong> cutter. Selecting that type on the web page keeps the existing model intact and shows a note pointing at the WPF client or HiNcRcl.</p>
|
||||
<p>Three smaller surfaces are likewise the WPF client's: the InsertCutter and FluteInnerBeam physics groups, and the <code>CustomSpinningProfile</code> shaper-profile type — the web profile tab offers the five APT types (General / Ball / Column / Cone / Taper).</p>
|
||||
<p>One cutter type has no editor here, and the app says so where the type is chosen: the <strong>FreeformRemover</strong>. Selecting it keeps the existing model intact and shows a note — <em>FreeformRemover editor is not yet available in the web frontend. Use the WPF client or HiNcRcl for now.</em></p>
|
||||
<p>Three smaller surfaces are absent for the same reason: the InsertCutter and FluteInnerBeam physics groups, and the <code>CustomSpinningProfile</code> shaper-profile type — the profile tab offers the five APT types (General / Ball / Column / Cone / Taper).</p>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a href="cutter/index.html">Cutter Tab</a> — the cutter half of a tool, and the editors each cutter type grows</li>
|
||||
|
||||
@@ -91,9 +91,7 @@
|
||||
<p>On the shipped web client the Stick Tool Panel is the <code>toolhouse/tool-<n></code> node of the
|
||||
<a class="xref" href="index.html">Tool House Page</a>: picking a tool in that page's left list mounts it, and
|
||||
its editor is the tab strip filling the page's middle column.</p>
|
||||
<p>The key model is <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingTool.html">MillingTool</a>.
|
||||
Other model: <code>UserService</code> — the WPF client reads its <code>EnablePhysics</code> to decide whether its
|
||||
Intelligent Holder tab is shown.</p>
|
||||
<p>The key model is <a class="xref" href="../../api/Hi.Milling.MillingTools.MillingTool.html">MillingTool</a>.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<ul>
|
||||
<li>Tool Node (<code>toolhouse/tool-<n></code>)
|
||||
@@ -136,19 +134,14 @@ Intelligent Holder tab is shown.</p>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>All five tabs ship unconditionally on the web page: the Int. Holder tab is one of the five
|
||||
<code>TOOL_TABS</code>, and the tool node always grows its <code>…/intelligent</code> child. The WPF Stick Tool Panel is
|
||||
the client that hides its Intelligent Holder tab when <code>UserService.EnablePhysics</code> is false, from
|
||||
<code>UpdateIntelligentHolderTabVisibility</code> in <code>Mech/ToolHouse/StickToolPanel.xaml.cs</code>.</p>
|
||||
<p>Object Management on the web page is house-level rather than per-tool: the
|
||||
<p>All five tabs ship unconditionally: the Int. Holder tab is one of the five <code>TOOL_TABS</code>, and the tool
|
||||
node always grows its <code>…/intelligent</code> child. Nothing gates it on <code>UserService.EnablePhysics</code>.</p>
|
||||
<p>Object Management is house-level rather than per-tool: the
|
||||
<a class="xref" href="../widget/object-management-menu-button.html">Object Management Menu Button</a> sits on the Tool House root
|
||||
panel with file extension <code>.MachiningToolHouse</code> (load type <code>Hi.Machining.MachiningToolHouse, HiMech</code>)
|
||||
and covers the whole house, while the tool node offers Duplicate and Delete for the single tool. The
|
||||
WPF Stick Tool Panel is the client that carries a per-tool Object Management Menu Button on its head
|
||||
line, with file extension <code>.MillingTool</code> and the Stick Tool Management Panel as its pointed editor
|
||||
panel. That client also gives the identity fields a tab of their own — <strong>Info</strong>, a read-only Abstract
|
||||
Note TextBox over an editable Note TextBox; on the web page those two fields are the General tab,
|
||||
alongside Tool ID and the Duplicate / Delete buttons.</p>
|
||||
and covers the whole house, while the tool node offers Duplicate and Delete for the single tool.
|
||||
There is no per-tool object-management button, and no separate tab for the identity fields — the
|
||||
Abstract Note and Note sit on the General tab, alongside Tool ID and the Duplicate / Delete buttons.</p>
|
||||
<h2 id="tabs-and-the-url">Tabs and the URL</h2>
|
||||
<p>The tabs are <code>TOOL_TABS</code> — <strong>General</strong>, <strong>Cutter</strong>, <strong>Holder</strong>, <strong>Clamping</strong>, <strong>Int. Holder</strong> —
|
||||
declared in <code>wwwroot-src/src/router/treeRoutes.ts</code>, and those same five names are the <code>:tab?</code> segment
|
||||
|
||||
@@ -121,8 +121,7 @@ that tree has no editor for.</li>
|
||||
<ul>
|
||||
<li><strong>Cutter editor</strong> — a Tool House Control-Tree branch, not a util page:
|
||||
<code>wwwroot-src/src/components/controlTree/toolhouse/ToolCutterPanel.vue</code> with its section, contour
|
||||
and flute panels, over <code>Mech/CutterController.cs</code>, reached through the <code>tool-house</code> route. The
|
||||
WPF client has <code>Mech/ToolHouse/CutterManagementPanel.xaml</code> and <code>Mech/ToolHouse/MillingCutterPanel.xaml</code>.</li>
|
||||
and flute panels, over <code>Mech/CutterController.cs</code>, reached through the <code>tool-house</code> route. The</li>
|
||||
<li><strong>Rake-face angles</strong> — plain cutter fields: <code>radialRakeAngle_deg</code> in
|
||||
<code>wwwroot-src/src/components/controlTree/toolhouse/FluteSideContourPanel.vue</code> and
|
||||
<code>axialRakeAngle_deg</code> in
|
||||
@@ -131,7 +130,7 @@ or <code>.mp</code> file opens as XML in the File Explorer's editor panel.</li>
|
||||
<li><strong>Color Index Time Chart</strong> — a strip chart on the Execution page:
|
||||
<code>wwwroot-src/src/components/execution/charts/StripIndividualChart.vue</code>, mounted by
|
||||
<code>wwwroot-src/src/pages/ExecutionPage.vue</code> under the <code>colorIndexTimeChart</code> panel flag that
|
||||
<code>Environments/ExecutionDivConfig.cs</code> persists (<code>Environments/PlayerDivConfig.cs</code> on the WPF side).
|
||||
<code>Environments/ExecutionDivConfig.cs</code> persists.
|
||||
It plots the user-picked inspecting key live per step.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -88,11 +88,11 @@
|
||||
<h1 id="widgets">Widgets</h1>
|
||||
|
||||
<p>The reusable controls that pages embed rather than own. Each page here documents one control — most
|
||||
of them under the SPA's <code>components/widgets/</code> directory — together with its WPF counterpart where one
|
||||
exists, so a reader who meets the same control on four screens reads about it once.</p>
|
||||
of them under the SPA's <code>components/widgets/</code> directory — so a reader who meets the same control on
|
||||
four screens reads about it once.</p>
|
||||
<p>A control earns a page here when more than one screen embeds it. A control that only ever appears
|
||||
on one screen is documented on that screen's page instead.</p>
|
||||
<p>Ordered by how widely each control is embedded across the two clients, most-embedded first.</p>
|
||||
<p>Ordered by how widely each control is embedded, most-embedded first.</p>
|
||||
<h2 id="pages">Pages</h2>
|
||||
<ul>
|
||||
<li><a href="numeric-input.html">Numeric Input</a> — The single-value numeric field every editor embeds: blur-and-Enter commit, inclusive bounds, and the Infinity and NaN spellings; the most widely embedded control in the app</li>
|
||||
|
||||
@@ -87,32 +87,8 @@
|
||||
<article data-uid="Anatomy-PolarResolution2dPanel">
|
||||
<h1 id="polar-resolution-2d-panel">Polar Resolution 2D Panel</h1>
|
||||
|
||||
<p>The model is <a class="xref" href="../../api/Hi.Geom.Resolution.PolarResolution2d.html">PolarResolution2d</a>: a linear step in millimetres plus an angular step, carried in radians and edited in degrees, that together tessellate a revolved shape into an STL mesh. Both clients edit it on a tool holder and nowhere else — the WPF client through this widget, the web client through the Cylindroid holder's Resolution section.</p>
|
||||
<p>The model is <a class="xref" href="../../api/Hi.Geom.Resolution.PolarResolution2d.html">PolarResolution2d</a>: a linear step in millimetres plus an angular step, carried in radians and edited in degrees, that together tessellate a revolved shape into an STL mesh. It is edited on a tool holder and nowhere else, through the Cylindroid holder's Resolution section.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<h3 id="wpf-layout">WPF Layout</h3>
|
||||
<ul>
|
||||
<li>Polar Resolution 2D Panel
|
||||
<ul>
|
||||
<li>Enable Custom Resolution CheckBox
|
||||
<ul>
|
||||
<li>checked if the host model is not null; the checkbox itself is always clickable.</li>
|
||||
<li>unchecking sets the host model to null; checking a null model publishes a fresh <a class="xref" href="../../api/Hi.Geom.Resolution.PolarResolution2d.html">PolarResolution2d</a> of 0.5 mm / 5 deg through the setter.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Linear Resolution Input Field, with an <code>mm</code> suffix label
|
||||
<ul>
|
||||
<li>enabled if model not null</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Angle Resolution Input Field, with a degree-sign suffix label
|
||||
<ul>
|
||||
<li>enabled if model not null</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 id="web-layout">Web Layout</h3>
|
||||
<ul>
|
||||
<li>Holder Resolution Section
|
||||
<ul>
|
||||
@@ -122,14 +98,13 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>There is no enable checkbox and no null state on the web: both fields are always editable, and each commits on blur or Enter, and only when both values are greater than zero.</p>
|
||||
<p>There is no enable checkbox and no null state: both fields are always editable, and each commits on blur or Enter, and only when both values are greater than zero.</p>
|
||||
<h2 id="feature">Feature</h2>
|
||||
<p>The Enable CheckBox is always shown. The host drives the WPF widget only through <code>GetterFunc</code> / <code>SetterFunc</code>; it calls <code>UpdateUI()</code> after its own model changes and subscribes to <code>OnModelChanged</code> to react to an edit.</p>
|
||||
<p>An edit republishes a whole new carrier through the setter instead of mutating the current one, in either client. A holder's <a class="xref" href="../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_PolarResolution2d">PolarResolution2d</a> setter swaps the holder's solid for one born with the new value and disposes the old one, and skips a value-equal reassignment — which is what makes the WPF widget's per-keystroke setting affordable. The web client performs the same swap server-side inside <code>SetPolarResolution</code>, then clears the holder's cache.</p>
|
||||
<p>If the host model is null, it may mean the resolution applied the default value: <a class="xref" href="../../api/Hi.NcMech.Solids.Solid.html#Hi_NcMech_Solids_Solid_PolarResolution2d">PolarResolution2d</a> is a snapshot of the solid's identity, and a null carrier lets a parametric geometry apply its own default. Only the WPF client can reach that state. The service reports a null resolution as 0 mm / 0 deg, the two web fields display those zeros, and the commit guard then blocks any write until real numbers are typed.</p>
|
||||
<p>An edit republishes a whole new carrier instead of mutating the current one. A holder's <a class="xref" href="../../api/Hi.NcMech.Holders.CylindroidHolder.html#Hi_NcMech_Holders_CylindroidHolder_PolarResolution2d">PolarResolution2d</a> setter swaps the holder's solid for one born with the new value and disposes the old one, and skips a value-equal reassignment; the same swap happens server-side inside <code>SetPolarResolution</code>, which then clears the holder's cache.</p>
|
||||
<p>A null host model means the resolution applied the default value: <a class="xref" href="../../api/Hi.NcMech.Solids.Solid.html#Hi_NcMech_Solids_Solid_PolarResolution2d">PolarResolution2d</a> is a snapshot of the solid's identity, and a null carrier lets a parametric geometry apply its own default. Nothing on this surface can produce that state. The service reports a null resolution as 0 mm / 0 deg, the two fields display those zeros, and the commit guard then blocks any write until real numbers are typed.</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): no standalone widget. The resolution is edited on the Cylindroid holder's Resolution section, at the Control-Tree id <code>toolhouse/tool-{id}/holder/resolution</code> and the route <code>/tool-house/:toolId/holder/resolution</code>. A Freeform holder grows no sections in the web client; its Holder panel shows a hint pointing at the WPF client instead.</p>
|
||||
<p>HiNC-2025-webservice (Quasar CLI SPA): no standalone widget. The resolution is edited on the Cylindroid holder's Resolution section, at the Control-Tree id <code>toolhouse/tool-{id}/holder/resolution</code> and the route <code>/tool-house/:toolId/holder/resolution</code>. A Freeform holder grows no sections here; its Holder panel shows a hint saying the geometry is edited elsewhere.</p>
|
||||
<ul>
|
||||
<li><code>wwwroot-src/src/components/controlTree/toolhouse/HolderSectionPanel.vue</code> — the <code>section === 'resolution'</code> branch: the two number fields, seeded from <code>Get</code> and committed on blur / Enter.</li>
|
||||
<li><code>wwwroot-src/src/components/controlTree/toolHouseItemTypes.ts</code> — registers that panel as the <code>HolderSection</code> item type and grows the Resolution node only for a <code>CylindroidHolder</code>.</li>
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<article data-uid="Anatomy-RenderingCanvasToolBar">
|
||||
<h1 id="renderingcanvas-tool-bar">RenderingCanvas Tool Bar</h1>
|
||||
|
||||
<p>The RenderingCanvas Tool Bar is the camera-preset menu that every 3D canvas in the app carries. In the WPF client the control holds a <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a> and drives it directly from each menu click. On the web it holds no engine: it takes a <code>canvas</code> prop and calls that component's exposed <code>setView(name)</code>, which invokes the <code>SetView</code> hub method, and the hub is what drives the per-connection <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.</p>
|
||||
<p>The RenderingCanvas Tool Bar is the camera-preset menu that every 3D canvas in the app carries. It holds no engine of its own: it takes a <code>canvas</code> prop and calls that component's exposed <code>setView(name)</code>, which invokes the <code>SetView</code> hub method, and the hub is what drives the per-connection <a class="xref" href="../../api/Hi.Disp.DispEngine.html">DispEngine</a>.</p>
|
||||
<h2 id="view-menu">View Menu</h2>
|
||||
<p>The bar is a single <code>View ▾</code> menu. Its seven entries, in shipped order, are Isometric, Front, Back, Right, Left, Top and Bottom. The engine also understands a <code>home</code> view and <code>RenderingCanvas.vue</code> exposes <code>setViewToHomeView</code>, but this menu does not offer it.</p>
|
||||
<table>
|
||||
@@ -129,9 +129,9 @@
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="back-view-implementation">Back View Implementation</h3>
|
||||
<p>Back / Left / Bottom views are composed by first calling the corresponding forward-view method (<code>SetViewToFrontView</code> / <code>SetViewToRightView</code> / <code>SetViewToTopView</code>) and then invoking <a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TurnBackView">TurnBackView()</a> to flip the camera about the view plane. Both clients compose them the same way — the web in the hub's <code>SetView</code> switch, WPF in the tool bar's click handlers.</p>
|
||||
<p>Back / Left / Bottom views are composed by first calling the corresponding forward-view method (<code>SetViewToFrontView</code> / <code>SetViewToRightView</code> / <code>SetViewToTopView</code>) and then invoking <a class="xref" href="../../api/Hi.Disp.DispEngine.html#Hi_Disp_DispEngine_TurnBackView">TurnBackView()</a> to flip the camera about the view plane, composed in the hub's <code>SetView</code> switch.</p>
|
||||
<h3 id="canvas-binding">Canvas Binding</h3>
|
||||
<p>On the web the tool bar declares exactly one prop, a nullable <code>canvas</code>, typed structurally as an object exposing <code>setView(v: string): Promise<void></code> rather than as the <code>RenderingCanvas</code> component type. Every entry calls it optionally, so a tool bar with no canvas bound still opens and each entry is a no-op. The preset names travel to the hub untranslated; only the row labels are localized, from the <code>widgets.canvas.*</code> keys.</p>
|
||||
<p>The tool bar declares exactly one prop, a nullable <code>canvas</code>, typed structurally as an object exposing <code>setView(v: string): Promise<void></code> rather than as the <code>RenderingCanvas</code> component type. Every entry calls it optionally, so a tool bar with no canvas bound still opens and each entry is a no-op. The preset names travel to the hub untranslated; only the row labels are localized, from the <code>widgets.canvas.*</code> keys.</p>
|
||||
<h2 id="scene-menu">Scene Menu</h2>
|
||||
<p>Pages that sit next to a <code>RenderingCanvas</code> surface a per-page <code>Scene ▾</code> menu button — the <code>DisplayOptionsMenu</code> component, labelled from <code>widgets.canvas.scene</code> because no caller overrides the label. It chooses what the 3D scene draws (solids, coordinates, display aids), as distinct from the camera-oriented <code>View ▾</code> menu beside it. The layout (header + checkboxes + radio rows) is shared across four callers — the Execution page's extended tool bar, the General Setup equipment panel, the Tool House setup panel and the STL preview pane — so it is implemented once as a generic, schema-driven component.</p>
|
||||
<h3 id="schema">Schema</h3>
|
||||
@@ -154,10 +154,6 @@
|
||||
</li>
|
||||
<li>Backends — one per caller, each a different surface: <code>ExecutionExtendedToolBar.vue</code> reaches <code>/api/rendering-flags</code> (<code>Common/RenderingFlagsController.cs</code>), which flips bits in <code>ExecutionDisplayee.RenderingFlagBitArray</code>; <code>EquipmentSetupPanel.vue</code> reaches <code>/api/mech/equipment-setup-display/*</code> (<code>Mech/EquipmentSetupDisplayController.cs</code>); <code>ToolHouseSetupPanel.vue</code> reaches <code>/api/mech/tool-house-display/*</code> (<code>Mech/ToolHouseDisplayController.cs</code>); <code>StlPreviewPane.vue</code> reaches <code>/api/stl-preview/set-coordinate/*</code> (<code>Disp/StlPreviewController.cs</code>). Those last three route each POST by the caller's <code>renderingConnectionId</code>, so the toggle lands on that canvas's own engine; the rendering-flags surface carries no connection id and acts on the project-wide <code>ExecutionDisplayee</code> instead. <code>DisplayOptionsMenu.vue</code> is UI-only; it does no REST work itself — the caller owns the <code>onUpdate</code> handlers, so optimistic update and error reversion stay page-local.</li>
|
||||
</ul>
|
||||
<h3 id="wpf">WPF</h3>
|
||||
<ul>
|
||||
<li><code>Play/RenderingFlagSubmenu.xaml</code> — the shared flag submenu, wrapped per surface by <code>Numerical/Controller/ControllerExtendedRenderingCanvasToolBar.xaml</code> and <code>Play/PlayerExtendedRenderingCanvasToolBar.xaml</code>. Behaviour parity with the web <code>Scene ▾</code> menu; no schema-driven composition.</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>
|
||||
|
||||
@@ -91,21 +91,17 @@
|
||||
and no Control-Tree node of its own, reached only through the editors that host it.</p>
|
||||
<h2 id="key-model">Key Model</h2>
|
||||
<p>The persisted model is <a class="xref" href="../../api/Hi.Geom.Vec3d.html">Vec3d</a>, exposed over <code>/api/Vec3d</code> by <code>Widget/Vec3dController.cs</code>.</p>
|
||||
<p>In the web application the widget's own model is the plain <code>{ x, y, z }</code> number triple exported as
|
||||
<p>The widget's own model is the plain <code>{ x, y, z }</code> number triple exported as
|
||||
<code>interface Vec3</code> from <code>wwwroot-src/src/components/widgets/Vec3Input.vue</code>. The widget carries no key
|
||||
and calls no endpoint: the host binds it with <code>v-model</code> plus an <code>@update:model-value</code> handler, and
|
||||
that handler does the persisting, each host on its own terms. The four transformer editors call
|
||||
<code>updateVec3d</code> from <code>wwwroot-src/src/api/geometry.ts</code>, which posts all three axes together to
|
||||
<code>/api/Vec3d/Update</code>, while <code>wwwroot-src/src/components/geom/Box3dEditor.vue</code> folds the edited triple
|
||||
back into a min and max pair and posts that to <code>/api/Box3d/Update</code>.</p>
|
||||
<p>The WPF control likewise holds no value of its own. <code>GetterFunc</code> returns the live
|
||||
<a class="xref" href="../../api/Hi.Geom.Vec3d.html">Vec3d</a> instance, the text handlers write the parsed numbers straight onto it, and
|
||||
<code>UpdateByContentFunc</code> is awaited afterwards so the host can push the change on.</p>
|
||||
<p>The web props are <code>modelValue</code>, <code>disable</code>, <code>readonly</code>, <code>normalize</code>, <code>labels</code> and <code>textMode</code>, and the
|
||||
<p>The props are <code>modelValue</code>, <code>disable</code>, <code>readonly</code>, <code>normalize</code>, <code>labels</code> and <code>textMode</code>, and the
|
||||
emits are <code>update:modelValue</code> and <code>normalize</code>. <code>labels</code> is a three-tuple defaulting to
|
||||
<code>['X', 'Y', 'Z']</code>, and carries units where the host has them, as in <code>['X (mm)', 'Y (mm)', 'Z (mm)']</code>.
|
||||
<code>textMode</code> sets the initial mode only and defaults to false. The corresponding WPF properties are
|
||||
<code>ShowNormalizeButton</code>, <code>IsTextMode</code> and <code>IsReadOnly</code>.</p>
|
||||
<code>textMode</code> sets the initial mode only and defaults to false.</p>
|
||||
<h2 id="layout">Layout</h2>
|
||||
<ul>
|
||||
<li>Vec3dControl
|
||||
@@ -119,496 +115,28 @@ control is disabled or readonly</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>In the WPF client the two forms are two panels, <code>StandardModePanel</code> and <code>TextModePanel</code>, of which
|
||||
exactly one is visible; each panel carries its own mode-toggle and normalize buttons.</p>
|
||||
<h2 id="feature">Feature</h2>
|
||||
<h3 id="per-axis-form">Per-axis form</h3>
|
||||
<p>X, Y and Z in three separate fields. The web widget renders every finite value at full precision;
|
||||
the WPF control renders each axis with a fixed three decimal places.</p>
|
||||
<p>X, Y and Z in three separate fields, each rendering every finite value at full precision.</p>
|
||||
<h3 id="single-field-text-form">Single-field text form</h3>
|
||||
<p>The web form is <code>(x, y, z)</code>. Its parser strips surrounding brackets and splits on comma, semicolon
|
||||
<p>The form is <code>(x, y, z)</code>. Its parser strips surrounding brackets and splits on comma, semicolon
|
||||
or whitespace, requiring at least three parts, and entering the text form re-syncs the field from
|
||||
the current value so a stale in-progress edit is discarded. The WPF text box holds comma-separated
|
||||
<code>x,y,z</code> without brackets and accepts two further shapes: a pasted 4x4 matrix, from which it takes
|
||||
the translation column, and loose text, from which it takes the first three numbers it can read.</p>
|
||||
the current value so a stale in-progress edit is discarded.</p>
|
||||
<h3 id="vector-normalization">Vector normalization</h3>
|
||||
<p>The normalize button is opt-in and off by default in both clients: the <code>normalize</code> prop in the web
|
||||
widget, the <code>ShowNormalizeButton</code> property in the WPF control.</p>
|
||||
<p>In the web widget the button only raises a <code>normalize</code> event, and the embedding editor performs the
|
||||
<p>The normalize button is opt-in and off by default, through the <code>normalize</code> prop.</p>
|
||||
<p>The button only raises a <code>normalize</code> event, and the embedding editor performs the
|
||||
normalization on its own owning object. <code>wwwroot-src/src/components/topo/StaticRotationEditor.vue</code>
|
||||
posts to <code>/api/StaticRotation/NormalizeAxis</code>, while
|
||||
<code>wwwroot-src/src/components/topo/DynamicRotationEditor.vue</code> and
|
||||
<code>wwwroot-src/src/components/topo/DynamicTranslationEditor.vue</code> call <code>normalizeDynamicRotationAxis</code>
|
||||
and <code>normalizeDynamicTranslationAxis</code> from <code>wwwroot-src/src/api/transformer.ts</code>. The WPF control
|
||||
normalizes the vector in place and writes the result back at three decimal places.</p>
|
||||
and <code>normalizeDynamicTranslationAxis</code> from <code>wwwroot-src/src/api/transformer.ts</code>.</p>
|
||||
<h3 id="commit-and-special-values">Commit and special values</h3>
|
||||
<p>Web edits commit on blur or Enter, never per keystroke, and a value is emitted only when it differs
|
||||
<p>Edits commit on blur or Enter, never per keystroke, and a value is emitted only when it differs
|
||||
from the current model. An empty field parses to 0; any other unparseable text reverts the field to
|
||||
the last valid value. Formatting and parsing are local to the component: NaN renders as <code>NaN</code> and
|
||||
the infinities as <code>Infinity</code> and <code>-Infinity</code>, and the parser accepts those spellings
|
||||
case-insensitively as well as the <code>∞</code> and <code>-∞</code> glyphs. The WPF control commits on every keystroke
|
||||
instead, leaving the model untouched while the text is unparseable so that a half-typed number is
|
||||
not treated as an error.</p>
|
||||
<h2 id="refer-sample-code">Refer Sample Code</h2>
|
||||
<pre><code class="lang-csharp" name="SampleCode-xaml"><UserControl x:Class="HiNC_2025_win_desktop.Geom.Vec3dControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="30" d:DesignWidth="200">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Standard Mode Panel -->
|
||||
<StackPanel x:Name="StandardModePanel" Orientation="Horizontal" Grid.ColumnSpan="5">
|
||||
<TextBox x:Name="XTextBox" Width="60" Margin="0,0,2,0" TextChanged="XTextBox_TextChanged" IsReadOnly="{Binding IsReadOnly}"/>
|
||||
<TextBox x:Name="YTextBox" Width="60" Margin="0,0,2,0" TextChanged="YTextBox_TextChanged" IsReadOnly="{Binding IsReadOnly}"/>
|
||||
<TextBox x:Name="ZTextBox" Width="60" Margin="0,0,2,0" TextChanged="ZTextBox_TextChanged" IsReadOnly="{Binding IsReadOnly}"/>
|
||||
<Button Content="{DynamicResource Vec3d_TextMode_Toggle}" Width="20" Click="TextModeToggle_Click" Margin="0,0,2,0" ToolTip="{DynamicResource Vec3d_TextMode_Tooltip}"/>
|
||||
<Button Content="{DynamicResource Vec3d_Normalize}" Width="20" Click="NormalizeButton_Click" Visibility="{Binding ShowNormalizeButton, Converter={StaticResource BooleanToVisibilityConverter}}" ToolTip="{DynamicResource Vec3d_Normalize_Tooltip}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Text Mode Panel -->
|
||||
<StackPanel x:Name="TextModePanel" Orientation="Horizontal" Grid.ColumnSpan="5" Visibility="Collapsed">
|
||||
<TextBox x:Name="VectorTextBox" Width="180" Margin="0,0,2,0" TextChanged="VectorTextBox_TextChanged" IsReadOnly="{Binding IsReadOnly}"
|
||||
ToolTip="{DynamicResource Vec3d_TextMode_Format_Tooltip}"/>
|
||||
<Button Content="{DynamicResource Vec3d_StandardMode_Toggle}" Width="20" Click="StandardModeToggle_Click" Margin="0,0,2,0" ToolTip="{DynamicResource Vec3d_StandardMode_Tooltip}"/>
|
||||
<Button Content="{DynamicResource Vec3d_Normalize}" Width="20" Click="NormalizeButton_Click" Visibility="{Binding ShowNormalizeButton, Converter={StaticResource BooleanToVisibilityConverter}}" ToolTip="{DynamicResource Vec3d_Normalize_Tooltip}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
</code></pre><pre><code class="lang-csharp" name="SampleCode-xaml.cs">using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
using Hi.Geom;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.ComponentModel;
|
||||
using Hi.Common;
|
||||
using Hi.Common.Messages;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HiNC_2025_win_desktop.Geom
|
||||
{
|
||||
/// <summary>
|
||||
/// Vec3dControl.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class Vec3dControl : UserControl, INotifyPropertyChanged
|
||||
{
|
||||
private bool _isUpdating = false;
|
||||
private Func<Vec3d> _getterFunc;
|
||||
private Func<Task> _updateByContentFunc;
|
||||
private bool _showNormalizeButton = false;
|
||||
private bool _isTextMode = false;
|
||||
private bool _isReadOnly = false;
|
||||
private readonly ILogger<Vec3dControl> _logger = App.ServiceProvider.GetRequiredService<ILogger<Vec3dControl>>();
|
||||
|
||||
private static readonly Regex VectorRegex = new Regex(@"^\s*[\(\[\{]?\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*[\)\]\}]?\s*$", RegexOptions.Compiled);
|
||||
private static readonly Regex MatrixRegex = new Regex(@"\{(?:\s*\{?\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*\}?\s*,){3}\s*\{?\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*,\s*(-?\d*\.?\d+)\s*\}?\s*\}", RegexOptions.Compiled);
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public string ControlId { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
public Func<Vec3d> GetterFunc
|
||||
{
|
||||
get => _getterFunc;
|
||||
set
|
||||
{
|
||||
_getterFunc = value;
|
||||
UpdateUI();
|
||||
}
|
||||
}
|
||||
|
||||
public Func<Task> UpdateByContentFunc
|
||||
{
|
||||
get => _updateByContentFunc;
|
||||
set => _updateByContentFunc = value;
|
||||
}
|
||||
|
||||
public bool ShowNormalizeButton
|
||||
{
|
||||
get => _showNormalizeButton;
|
||||
set
|
||||
{
|
||||
if (_showNormalizeButton != value)
|
||||
{
|
||||
_showNormalizeButton = value;
|
||||
OnPropertyChanged(nameof(ShowNormalizeButton));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsTextMode
|
||||
{
|
||||
get => _isTextMode;
|
||||
set
|
||||
{
|
||||
if (_isTextMode != value)
|
||||
{
|
||||
_isTextMode = value;
|
||||
UpdateModeVisibility();
|
||||
OnPropertyChanged(nameof(IsTextMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get => _isReadOnly;
|
||||
set
|
||||
{
|
||||
if (_isReadOnly != value)
|
||||
{
|
||||
_isReadOnly = value;
|
||||
OnPropertyChanged(nameof(IsReadOnly));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public Vec3dControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
private void UpdateModeVisibility()
|
||||
{
|
||||
if (IsTextMode)
|
||||
{
|
||||
StandardModePanel.Visibility = Visibility.Collapsed;
|
||||
TextModePanel.Visibility = Visibility.Visible;
|
||||
UpdateVectorTextFromXYZ();
|
||||
}
|
||||
else
|
||||
{
|
||||
StandardModePanel.Visibility = Visibility.Visible;
|
||||
TextModePanel.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateVectorTextFromXYZ()
|
||||
{
|
||||
if (_isUpdating) return;
|
||||
|
||||
if (double.TryParse(XTextBox.Text, out double x) &&
|
||||
double.TryParse(YTextBox.Text, out double y) &&
|
||||
double.TryParse(ZTextBox.Text, out double z))
|
||||
{
|
||||
VectorTextBox.Text = $"{x},{y},{z}";
|
||||
}
|
||||
}
|
||||
|
||||
private void TextModeToggle_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsTextMode = true;
|
||||
}
|
||||
|
||||
private void StandardModeToggle_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsTextMode = false;
|
||||
}
|
||||
|
||||
private async void NormalizeButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_isUpdating || _getterFunc == null || IsReadOnly)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdating = true;
|
||||
|
||||
var vec = _getterFunc();
|
||||
if (vec != null)
|
||||
{
|
||||
vec.Normalize();
|
||||
|
||||
XTextBox.Text = vec.X.ToString("F3");
|
||||
YTextBox.Text = vec.Y.ToString("F3");
|
||||
ZTextBox.Text = vec.Z.ToString("F3");
|
||||
|
||||
if (IsTextMode)
|
||||
{
|
||||
VectorTextBox.Text = $"{vec.X:F3},{vec.Y:F3},{vec.Z:F3}";
|
||||
}
|
||||
if(_updateByContentFunc != null)
|
||||
await _updateByContentFunc();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(string.Format(Application.Current.FindResource("Vec3d_Update_Error").ToString(), ex.Message));
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdating = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateUI()
|
||||
{
|
||||
if (_isUpdating || _getterFunc == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdating = true;
|
||||
var vec = _getterFunc();
|
||||
if (vec != null)
|
||||
{
|
||||
XTextBox.Text = vec.X.ToString("F3");
|
||||
YTextBox.Text = vec.Y.ToString("F3");
|
||||
ZTextBox.Text = vec.Z.ToString("F3");
|
||||
|
||||
if (IsTextMode)
|
||||
{
|
||||
VectorTextBox.Text = $"{vec.X},{vec.Y},{vec.Z}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
XTextBox.Text = "";
|
||||
YTextBox.Text = "";
|
||||
ZTextBox.Text = "";
|
||||
VectorTextBox.Text = "";
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void XTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
await HandleTextChanged();
|
||||
}
|
||||
|
||||
private async void YTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
await HandleTextChanged();
|
||||
}
|
||||
|
||||
private async void ZTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
await HandleTextChanged();
|
||||
}
|
||||
|
||||
private async void VectorTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (_isUpdating || _getterFunc == null || IsReadOnly)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
string text = VectorTextBox.Text.Trim();
|
||||
|
||||
// 如果文本为空或太短,不做处理
|
||||
if (string.IsNullOrWhiteSpace(text) || text.Length < 3)
|
||||
return;
|
||||
|
||||
_isUpdating = true;
|
||||
|
||||
// 尝试解析为向量格式
|
||||
if (TryParseVector(text, out double x, out double y, out double z))
|
||||
{
|
||||
await UpdateVectorValues(x, y, z);
|
||||
}
|
||||
// 尝试解析为变换矩阵格式(仅提取位移分量)
|
||||
else if (TryParseTransformMatrix(text, out double tx, out double ty, out double tz))
|
||||
{
|
||||
await UpdateVectorValues(tx, ty, tz);
|
||||
}
|
||||
// 尝试作为单值解析每个字段(宽松模式)
|
||||
else if (TryParseLooseVector(text, out double lx, out double ly, out double lz))
|
||||
{
|
||||
await UpdateVectorValues(lx, ly, lz);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(string.Format(Application.Current.FindResource("Vec3d_Update_Error").ToString(), ex.Message));
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryParseVector(string text, out double x, out double y, out double z)
|
||||
{
|
||||
x = y = z = 0;
|
||||
|
||||
// 使用正则表达式匹配向量格式
|
||||
Match match = VectorRegex.Match(text);
|
||||
if (match.Success && match.Groups.Count >= 4)
|
||||
{
|
||||
if (double.TryParse(match.Groups[1].Value, out x) &&
|
||||
double.TryParse(match.Groups[2].Value, out y) &&
|
||||
double.TryParse(match.Groups[3].Value, out z))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryParseTransformMatrix(string text, out double tx, out double ty, out double tz)
|
||||
{
|
||||
tx = ty = tz = 0;
|
||||
|
||||
// 移除所有换行和多余空格,便于匹配
|
||||
text = Regex.Replace(text, @"\s+", " ");
|
||||
|
||||
// 尝试匹配变换矩阵格式
|
||||
Match match = MatrixRegex.Match(text);
|
||||
if (match.Success && match.Groups.Count >= 8)
|
||||
{
|
||||
// 变换矩阵的第4列通常是位移分量
|
||||
if (double.TryParse(match.Groups[4].Value, out tx) &&
|
||||
double.TryParse(match.Groups[8].Value, out ty) &&
|
||||
double.TryParse(match.Groups[12].Value, out tz))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试匹配更宽松的变换矩阵表示(例如从界面复制的数据)
|
||||
var numbers = Regex.Matches(text, @"(-?\d*\.?\d+)");
|
||||
if (numbers.Count >= 16)
|
||||
{
|
||||
// 假设这是一个4x4矩阵,提取位移分量(第4、8、12个数字)
|
||||
if (double.TryParse(numbers[3].Value, out tx) &&
|
||||
double.TryParse(numbers[7].Value, out ty) &&
|
||||
double.TryParse(numbers[11].Value, out tz))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryParseLooseVector(string text, out double x, out double y, out double z)
|
||||
{
|
||||
x = y = z = 0;
|
||||
|
||||
// 移除所有非数字和小数点以外的字符,然后按空白分割
|
||||
string cleanText = Regex.Replace(text, @"[^\d\.\-\s,;]+", " ");
|
||||
string[] parts = Regex.Split(cleanText, @"[\s,;]+");
|
||||
|
||||
// 尝试从分割后的部分获取三个数字
|
||||
var numbers = new System.Collections.Generic.List<double>();
|
||||
foreach (var part in parts)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(part) && double.TryParse(part, out double value))
|
||||
{
|
||||
numbers.Add(value);
|
||||
if (numbers.Count >= 3) break; // 最多取3个数字
|
||||
}
|
||||
}
|
||||
|
||||
// 如果获取到了三个数字,就认为解析成功
|
||||
if (numbers.Count >= 3)
|
||||
{
|
||||
x = numbers[0];
|
||||
y = numbers[1];
|
||||
z = numbers[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task UpdateVectorValues(double x, double y, double z)
|
||||
{
|
||||
XTextBox.Text = x.ToString("F3");
|
||||
YTextBox.Text = y.ToString("F3");
|
||||
ZTextBox.Text = z.ToString("F3");
|
||||
|
||||
var vec = _getterFunc?.Invoke();
|
||||
if (vec != null)
|
||||
{
|
||||
vec.X = x;
|
||||
vec.Y = y;
|
||||
vec.Z = z;
|
||||
|
||||
if (_updateByContentFunc != null)
|
||||
{
|
||||
await _updateByContentFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleTextChanged()
|
||||
{
|
||||
if (_isUpdating || _getterFunc == null || IsReadOnly)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_isUpdating = true;
|
||||
|
||||
// 尝试解析每个文本框的值
|
||||
bool allValid = true;
|
||||
|
||||
allValid &= double.TryParse(XTextBox.Text, out double x);
|
||||
allValid &= double.TryParse(YTextBox.Text, out double y);
|
||||
allValid &= double.TryParse(ZTextBox.Text, out double z);
|
||||
|
||||
if (allValid)
|
||||
{
|
||||
if (IsTextMode)
|
||||
{
|
||||
VectorTextBox.Text = $"{x},{y},{z}";
|
||||
}
|
||||
|
||||
var vec = _getterFunc();
|
||||
if (vec != null)
|
||||
{
|
||||
vec.X = x;
|
||||
vec.Y = y;
|
||||
vec.Z = z;
|
||||
|
||||
if(_updateByContentFunc != null)
|
||||
await _updateByContentFunc();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果有无效输入,不进行更新但也不显示错误
|
||||
// 这允许用户在输入过程中有不完整的状态
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常但不中断用户操作
|
||||
_logger.LogWarning(string.Format(Application.Current.FindResource("Vec3d_Update_Error").ToString(), ex.Message));
|
||||
_logger.LogError(ex, "{Message}", ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isUpdating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre><h2 id="source-code-path">Source Code Path</h2>
|
||||
case-insensitively as well as the <code>∞</code> and <code>-∞</code> glyphs.</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>
|
||||
<ul>
|
||||
<li><code>wwwroot-src/src/components/widgets/Vec3Input.vue</code> — the widget itself: mode toggle, per-axis and
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Class StrokeLimitUtil | HiAPI-C# 2025 </title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Class StrokeLimitUtil | HiAPI-C# 2025 ">
|
||||
|
||||
<meta name="description" content="Load-time audit helpers for : which machine-coordinate axes the chain has, and which of them the stroke limit check cannot judge because no limit is configured. Both checks — the per-block and the per-step — compare only axes that carry a limit, so a machine file without limits passes every position silently while EnableStrokeLimitCheck reads as on. The session begin reports that gap once through these helpers.">
|
||||
<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 "{query}"">
|
||||
<meta name="loc:searchNoResults" content="No results for "{query}"">
|
||||
<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="ManagedReference">
|
||||
<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="Hi.NcParsers.Dependencys.StrokeLimitUtil">
|
||||
|
||||
|
||||
|
||||
<h1 id="Hi_NcParsers_Dependencys_StrokeLimitUtil" data-uid="Hi.NcParsers.Dependencys.StrokeLimitUtil" class="text-break">
|
||||
Class StrokeLimitUtil
|
||||
</h1>
|
||||
|
||||
<div class="facts text-secondary">
|
||||
<dl><dt>Namespace</dt><dd><a class="xref" href="Hi.html">Hi</a>.<a class="xref" href="Hi.NcParsers.html">NcParsers</a>.<a class="xref" href="Hi.NcParsers.Dependencys.html">Dependencys</a></dd></dl>
|
||||
<dl><dt>Assembly</dt><dd>HiMech.dll</dd></dl>
|
||||
</div>
|
||||
|
||||
<div class="markdown summary"><p>Load-time audit helpers for <a class="xref" href="Hi.NcParsers.Dependencys.IStrokeLimitConfig.html">IStrokeLimitConfig</a>: which
|
||||
machine-coordinate axes the chain has, and which of them the stroke limit
|
||||
check cannot judge because no limit is configured. Both checks — the
|
||||
per-block <a class="xref" href="Hi.NcParsers.Semantics.StrokeLimitCheckSemantic.html">StrokeLimitCheckSemantic</a> and the per-step
|
||||
<a class="xref" href="Hi.NcParsers.Dependencys.IStrokeLimitConfig.html#Hi_NcParsers_Dependencys_IStrokeLimitConfig_CheckStrokeLimit_Hi_Geom_DVec3d_System_IProgress_Hi_Common_Messages_IMessage__">CheckStrokeLimit(DVec3d, IProgress<IMessage>)</a> — compare only axes that
|
||||
carry a limit, so a machine file without limits passes every position
|
||||
silently while <code>EnableStrokeLimitCheck</code> reads as on. The session
|
||||
begin reports that gap once through these helpers.</p>
|
||||
</div>
|
||||
<div class="markdown conceptual"></div>
|
||||
|
||||
<div class="codewrapper">
|
||||
<pre><code class="lang-csharp hljs">public static class StrokeLimitUtil</code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<dl class="typelist inheritance">
|
||||
<dt>Inheritance</dt>
|
||||
<dd>
|
||||
<div><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object">object</a></div>
|
||||
<div><span class="xref">StrokeLimitUtil</span></div>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
<dl class="typelist inheritedMembers">
|
||||
<dt>Inherited Members</dt>
|
||||
<dd>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object)</a>
|
||||
</div>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object, object)</a>
|
||||
</div>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a>
|
||||
</div>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>
|
||||
</div>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone">object.MemberwiseClone()</a>
|
||||
</div>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object, object)</a>
|
||||
</div>
|
||||
<div>
|
||||
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>
|
||||
</div>
|
||||
</dd></dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h2 class="section" id="fields">Fields
|
||||
</h2>
|
||||
|
||||
|
||||
|
||||
<h3 id="Hi_NcParsers_Dependencys_StrokeLimitUtil_McAxisNames" data-uid="Hi.NcParsers.Dependencys.StrokeLimitUtil.McAxisNames">
|
||||
McAxisNames
|
||||
|
||||
</h3>
|
||||
|
||||
<div class="markdown level1 summary"><p>Machine-coordinate axis names, linear first then rotary.</p>
|
||||
</div>
|
||||
<div class="markdown level1 conceptual"></div>
|
||||
|
||||
<div class="codewrapper">
|
||||
<pre><code class="lang-csharp hljs">public static readonly string[] McAxisNames</code></pre>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<h4 class="section">Field Value</h4>
|
||||
<dl class="parameters">
|
||||
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>[]</dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<h2 class="section" id="methods">Methods
|
||||
</h2>
|
||||
|
||||
|
||||
<a id="Hi_NcParsers_Dependencys_StrokeLimitUtil_DescribeUnlimitedAxes_" data-uid="Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes*"></a>
|
||||
|
||||
<h3 id="Hi_NcParsers_Dependencys_StrokeLimitUtil_DescribeUnlimitedAxes_System_Collections_Generic_IEnumerable_System_String__System_Func_System_String_System_Nullable_System_Double___System_Func_System_String_System_Nullable_System_Double___" data-uid="Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes(System.Collections.Generic.IEnumerable{System.String},System.Func{System.String,System.Nullable{System.Double}},System.Func{System.String,System.Nullable{System.Double}})">
|
||||
DescribeUnlimitedAxes(IEnumerable<string>, Func<string, double?>, Func<string, double?>)
|
||||
|
||||
</h3>
|
||||
|
||||
<div class="markdown level1 summary"><p>Describes the axes among <code class="paramref">axisNames</code> that the stroke
|
||||
limit check cannot judge: an axis with neither end configured is
|
||||
listed by name, an axis with one end only is listed with the missing
|
||||
end (<code>"Z (no negative limit)"</code>). Empty when every axis has both
|
||||
ends. A limit of NaN or ±infinity counts as not configured (the legacy
|
||||
<code>HardNcEnv</code> boxes default to an infinite box).</p>
|
||||
</div>
|
||||
<div class="markdown level1 conceptual"></div>
|
||||
|
||||
<div class="codewrapper">
|
||||
<pre><code class="lang-csharp hljs">public static List<string> DescribeUnlimitedAxes(IEnumerable<string> axisNames, Func<string, double?> positiveLimit, Func<string, double?> negativeLimit)</code></pre>
|
||||
</div>
|
||||
|
||||
<h4 class="section">Parameters</h4>
|
||||
<dl class="parameters">
|
||||
<dt><code>axisNames</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1">IEnumerable</a><<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>></dt>
|
||||
<dd><p>The axes to audit, normally <a class="xref" href="Hi.NcParsers.Dependencys.StrokeLimitUtil.html#Hi_NcParsers_Dependencys_StrokeLimitUtil_GetChainAxisNames_Hi_Numerical_Xyzabc_IXyzabcChain_System_Boolean_">GetChainAxisNames(IXyzabcChain, bool)</a>.</p>
|
||||
</dd>
|
||||
<dt><code>positiveLimit</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.func-2">Func</a><<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>, <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.double">double</a>?></dt>
|
||||
<dd><p>Positive-end limit per axis; null when not configured.</p>
|
||||
</dd>
|
||||
<dt><code>negativeLimit</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.func-2">Func</a><<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>, <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.double">double</a>?></dt>
|
||||
<dd><p>Negative-end limit per axis; null when not configured.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h4 class="section">Returns</h4>
|
||||
<dl class="parameters">
|
||||
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1">List</a><<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>></dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a id="Hi_NcParsers_Dependencys_StrokeLimitUtil_GetChainAxisNames_" data-uid="Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames*"></a>
|
||||
|
||||
<h3 id="Hi_NcParsers_Dependencys_StrokeLimitUtil_GetChainAxisNames_Hi_Numerical_Xyzabc_IXyzabcChain_System_Boolean_" data-uid="Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames(Hi.Numerical.Xyzabc.IXyzabcChain,System.Boolean)">
|
||||
GetChainAxisNames(IXyzabcChain, bool)
|
||||
|
||||
</h3>
|
||||
|
||||
<div class="markdown level1 summary"><p>The machine-coordinate axes <code class="paramref">chain</code> actually has: an
|
||||
axis counts when a transformer is bound to its name
|
||||
(<a class="xref" href="Hi.Numerical.Xyzabc.IXyzabcChain.html#Hi_Numerical_Xyzabc_IXyzabcChain_GetTransformerX">GetTransformerX()</a> …
|
||||
<a class="xref" href="Hi.Numerical.Xyzabc.IXyzabcChain.html#Hi_Numerical_Xyzabc_IXyzabcChain_GetTransformerC">GetTransformerC()</a>). A three-axis chain yields
|
||||
X, Y, Z only; a null chain yields nothing.</p>
|
||||
</div>
|
||||
<div class="markdown level1 conceptual"></div>
|
||||
|
||||
<div class="codewrapper">
|
||||
<pre><code class="lang-csharp hljs">public static List<string> GetChainAxisNames(IXyzabcChain chain, bool linearOnly = false)</code></pre>
|
||||
</div>
|
||||
|
||||
<h4 class="section">Parameters</h4>
|
||||
<dl class="parameters">
|
||||
<dt><code>chain</code> <a class="xref" href="Hi.Numerical.Xyzabc.IXyzabcChain.html">IXyzabcChain</a></dt>
|
||||
<dd><p>The machine chain, or null.</p>
|
||||
</dd>
|
||||
<dt><code>linearOnly</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
|
||||
<dd><p>When true, only the translation axes (X, Y, Z) are returned. A travel
|
||||
audit wants this: a linear axis always has a finite travel, so a
|
||||
missing limit is unambiguously a gap, while a rotary table that turns
|
||||
continuously legitimately has none and cannot be given one.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h4 class="section">Returns</h4>
|
||||
<dl class="parameters">
|
||||
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1">List</a><<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>></dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</article>
|
||||
|
||||
<div class="contribution d-print-none">
|
||||
</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>
|
||||
@@ -164,6 +164,18 @@ Stored per machine in
|
||||
consumed by <a class="xref" href="Hi.NcParsers.LogicSyntaxs.MCodeExpansionSyntax.html">MCodeExpansionSyntax</a>, which
|
||||
expands the declared code into the canonical ISO flags the regular
|
||||
consumers already understand.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl class="jumplist">
|
||||
<dt><a class="xref" href="Hi.NcParsers.Dependencys.StrokeLimitUtil.html">StrokeLimitUtil</a></dt>
|
||||
<dd><p>Load-time audit helpers for <a class="xref" href="Hi.NcParsers.Dependencys.IStrokeLimitConfig.html">IStrokeLimitConfig</a>: which
|
||||
machine-coordinate axes the chain has, and which of them the stroke limit
|
||||
check cannot judge because no limit is configured. Both checks — the
|
||||
per-block <a class="xref" href="Hi.NcParsers.Semantics.StrokeLimitCheckSemantic.html">StrokeLimitCheckSemantic</a> and the per-step
|
||||
<a class="xref" href="Hi.NcParsers.Dependencys.IStrokeLimitConfig.html#Hi_NcParsers_Dependencys_IStrokeLimitConfig_CheckStrokeLimit_Hi_Geom_DVec3d_System_IProgress_Hi_Common_Messages_IMessage__">CheckStrokeLimit(DVec3d, IProgress<IMessage>)</a> — compare only axes that
|
||||
carry a limit, so a machine file without limits passes every position
|
||||
silently while <code>EnableStrokeLimitCheck</code> reads as on. The session
|
||||
begin reports that gap once through these helpers.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
<h3 id="interfaces">
|
||||
|
||||
@@ -253,6 +253,31 @@ G98/G99 flag on the same block):
|
||||
<pre><code class="lang-csharp">{ "Parsing": { "Flags": ["G80"] } }</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{ "CannedCycle": { "Term": "G80" } }</code></pre>
|
||||
<p>The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section next to a still-active G81, and the block
|
||||
itself has an X word that would have repeated the cycle. This is the
|
||||
reset edge (<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the controller's reset
|
||||
cancels the canned cycle, so no repeat is resolved (the X word stays
|
||||
for the positioning syntaxes) and the G80 sentinel is written
|
||||
explicitly — an authored section, so the modal carry does not clone
|
||||
the active cycle across the edge. No <code>ReturnMode</code>: the G98
|
||||
default applies after reset:
|
||||
#Previous:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "M30" },
|
||||
"CannedCycle": {
|
||||
"Term": "G81",
|
||||
"ReturnMode": "G99",
|
||||
"Params": { "X": 50, "Y": 30, "Z": -10, "R": 2 }
|
||||
}
|
||||
}</code></pre>
|
||||
<p>#BeforeBuild:</p>
|
||||
<pre><code class="lang-csharp">{ "Parsing": { "X": 60 } }</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"Parsing": { "X": 60 },
|
||||
"CannedCycle": { "Term": "G80" }
|
||||
}</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -353,6 +353,36 @@ flag (no parameter object to hang an H on):
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section next to the still-active G43.4, and the
|
||||
block itself swings a rotary axis (as a post-M02 <code>G0 A90.</code> does
|
||||
when a CAM file chains several programs). This is the reset edge
|
||||
(<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the controller's reset cancels
|
||||
tool-center-point control, so the modal is <b>not</b> carried, no
|
||||
<code>Dynamic</code> entry is written (the swing stays a plain McLinear
|
||||
rotary move instead of pinning the tool tip), and the block gets the
|
||||
G49 sentinel with the identity Mat4d — <a class="xref" href="Hi.NcParsers.LogicSyntaxs.ToolHeightOffsetSyntax.html">ToolHeightOffsetSyntax</a>
|
||||
skipped this block because the previous term was not ISO:
|
||||
#Previous:
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "M02" },
|
||||
"MachineCoordinateState": { "X": 0, "Y": 0, "Z": 0, "A": 0, "B": 0 },
|
||||
"ToolHeightCompensation": { "Offset_mm": 10, "Term": "G43.4", "OffsetId": 1 }
|
||||
}</code></pre>
|
||||
#BeforeBuild:
|
||||
<pre><code class="lang-csharp">{ "MachineCoordinateState": { "A": 90, "B": 0 } }</code></pre>
|
||||
#AfterBuild:
|
||||
<pre><code class="lang-csharp">{
|
||||
"MachineCoordinateState": { "A": 90, "B": 0 },
|
||||
"ToolHeightCompensation": { "Offset_mm": 0, "Term": "G49", "OffsetId": 0 },
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "ToolHeightCompensation",
|
||||
"Kind": "Static",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
+29
@@ -324,6 +324,35 @@ identity:
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
<p>The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section (<code>END PGM</code>, M2 or M30) next to the
|
||||
still-active M128. This is the reset edge
|
||||
(<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the TNC resets M128 / FUNCTION
|
||||
TCPM at program end while the TOOL CALL length compensation stays,
|
||||
so the block gets exactly the M129 hand-back:
|
||||
#Previous:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "END PGM" },
|
||||
"ToolHeightCompensation": {
|
||||
"Offset_mm": 120.5, "Term": "M128", "OffsetId": 2,
|
||||
"PriorTerm": "TOOL CALL", "Delta_mm": 0.5, "FeedLimit": 6000
|
||||
}
|
||||
}</code></pre>
|
||||
<p>#BeforeBuild:</p>
|
||||
<pre><code class="lang-csharp">{}</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"ToolHeightCompensation": {
|
||||
"Offset_mm": 120.5, "Term": "TOOL CALL", "OffsetId": 2, "Delta_mm": 0.5
|
||||
},
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "ToolHeightCompensation",
|
||||
"Kind": "Static",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,120.5,1]
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -319,6 +319,32 @@ The <a class="xref" href="Hi.NcParsers.Keywords.TiltTransform.html">TiltTransfor
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section next to the still-active G68.2. This is the
|
||||
reset edge (<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the controller's reset
|
||||
cancels the tilted work plane, so
|
||||
<a class="xref" href="Hi.NcParsers.LogicSyntaxs.TiltTransformUtil.html#Hi_NcParsers_LogicSyntaxs_TiltTransformUtil_CarryForwardFromPrevious_Hi_Common_Collections_LazyLinkedListNode_Hi_NcParsers_Syntaxs_SyntaxPiece__System_Text_Json_Nodes_JsonObject_">CarryForwardFromPrevious(LazyLinkedListNode<SyntaxPiece>, JsonObject)</a> does not
|
||||
carry the tilt and writes the explicit G69 cancel state instead (the
|
||||
same shape as case 0), leaving the unrelated G00 flag alone:
|
||||
#Previous:
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "M30" },
|
||||
"TiltTransform": { "Term": "G68.2", "X": 0, "Y": 0, "Z": 0, "I": 0, "J": 30, "K": 0 }
|
||||
}</code></pre>
|
||||
#BeforeBuild:
|
||||
<pre><code class="lang-csharp">{ "Parsing": { "Flags": ["G00"] } }</code></pre>
|
||||
#AfterBuild:
|
||||
<pre><code class="lang-csharp">{
|
||||
"Parsing": { "Flags": ["G00"] },
|
||||
"TiltTransform": { "Term": "G69" },
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "TiltTransform",
|
||||
"Kind": "Static",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
|
||||
|
||||
<h2 id="Hi_NcParsers_LogicSyntaxs_IsoG68p2TiltSyntax_remarks">Remarks</h2>
|
||||
|
||||
+51
-4
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Class MachineCoordSelectSyntax | HiAPI-C# 2025 ">
|
||||
|
||||
<meta name="description" content="Handles machine coordinate selection — non-modal, one-shot. The axis values (X/Y/Z) in the block are interpreted as machine coordinates, bypassing all work offsets, local coordinates, tool height compensation, and coordinate rotations. If G91 (incremental) is active, the code is ignored per ISO standard. A per-word incremental stamp on the block (block-root entry — Siemens SUPA Y=IC(-10), klartext L IY-10 M91) is a distance in the machine frame: the word is added to the previous machine position of that axis. Defaults to ISO G53. Brands with additional one-shot machine-coordinate codes widen — the Siemens preset adds G153 and SUPA (both suppress every active frame for one block; in this pipeline all of those reduce to "bypass the composed ", which the ProgramXyz back-derivation below already models). The matched code is stamped verbatim into for bidirectional source recovery. Rotary words on the same block (e.g. SUPA G0 B0) are left to — same behavior as ISO G53, where rotary axes flow through the normal rotary path. Must be placed before and in the syntax chain. When a supported code is active, this syntax consumes X/Y/Z from and writes directly, preventing from processing them as program coordinates — and, ahead of the resolve, reading a per-word incremental word raw instead of re-based into the program frame.">
|
||||
<meta name="description" content="Handles machine coordinate selection — non-modal, one-shot. The axis values (X/Y/Z) in the block are interpreted as machine coordinates, bypassing all work offsets, local coordinates, tool height compensation, and coordinate rotations. If G91 (incremental) is active, the code is ignored per ISO standard. A per-word incremental stamp on the block (block-root entry — Siemens SUPA Y=IC(-10), klartext L IY-10 M91) is a distance in the machine frame: the word is added to the previous machine position of that axis. Defaults to ISO G53. Brands with additional one-shot machine-coordinate codes widen — the Siemens preset adds G153 and SUPA (both suppress every active frame for one block; in this pipeline all of those reduce to "bypass the composed ", which the ProgramXyz back-derivation below already models). The matched code is stamped verbatim into for bidirectional source recovery. Rotary words on the same block (e.g. SUPA G0 B0, G53 A0 C0) are consumed by ahead of this syntax — machine and program rotary coincide while no rotary offsets are modeled — and the block is still a machine-coordinate positioning: the linear axes hold their machine position when no X/Y/Z word is given, and the motion is always . A machine-coordinate block never takes the RTCP tool-center-point linkage: on a real controller G53 applies no compensation, so a rotary swing commanded through it turns the axis in place instead of dragging X/Y/Z to pin the tool tip (the tip's post-swing program coordinate is what the back-derivation reports). Must be placed before and in the syntax chain. When a supported code is active, this syntax consumes X/Y/Z from and writes directly, preventing from processing them as program coordinates — and, ahead of the resolve, reading a per-word incremental word raw instead of re-based into the program frame.">
|
||||
<link rel="icon" href="../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../public/main.css">
|
||||
@@ -116,9 +116,18 @@ active frame for one block; in this pipeline all of those reduce to
|
||||
which the ProgramXyz back-derivation below already models). The
|
||||
matched code is stamped verbatim into
|
||||
<a class="xref" href="Hi.NcParsers.Keywords.IMotionEventDef.html#Hi_NcParsers_Keywords_IMotionEventDef_Term">Term</a> for bidirectional source recovery.
|
||||
Rotary words on the same block (e.g. <code>SUPA G0 B0</code>) are left to
|
||||
<a class="xref" href="Hi.NcParsers.LogicSyntaxs.McAbcSyntax.html">McAbcSyntax</a> — same behavior as ISO G53, where rotary
|
||||
axes flow through the normal rotary path.
|
||||
Rotary words on the same block (e.g. <code>SUPA G0 B0</code>,
|
||||
<code>G53 A0 C0</code>) are consumed by <a class="xref" href="Hi.NcParsers.LogicSyntaxs.McAbcSyntax.html">McAbcSyntax</a> ahead of
|
||||
this syntax — machine and program rotary coincide while no rotary
|
||||
offsets are modeled — and the block is still a machine-coordinate
|
||||
positioning: the linear axes <b>hold their machine position</b>
|
||||
when no X/Y/Z word is given, and the motion is always
|
||||
<a class="xref" href="Hi.NcParsers.Keywords.Generic.MotionForm.html#Hi_NcParsers_Keywords_Generic_MotionForm_McLinear">McLinear</a>. A machine-coordinate block never
|
||||
takes the RTCP tool-center-point linkage: on a real controller G53
|
||||
applies no compensation, so a rotary swing commanded through it
|
||||
turns the axis in place instead of dragging X/Y/Z to pin the tool
|
||||
tip (the tip's post-swing program coordinate is what the
|
||||
back-derivation reports).
|
||||
</p>
|
||||
<p>
|
||||
Must be placed <b>before</b> <a class="xref" href="Hi.NcParsers.LogicSyntaxs.IncrementalResolveSyntax.html">IncrementalResolveSyntax</a>
|
||||
@@ -301,6 +310,44 @@ section stays on the block (one-shot, nobody consumes it):
|
||||
"ProgramXyz": { "X": 100, "Y": 40, "Z": -200 },
|
||||
"MotionEvent": { "Form": "McLinear", "IsRapid": true, "Term": "G53" }
|
||||
}</code></pre>
|
||||
<p>Rotary-only machine-coordinate block under RTCP (<code>G0 G53 A0.</code>
|
||||
while <code>G43.4</code> is active) — <code>McAbcSyntax</code> has already
|
||||
consumed the rotary word into <code>MachineCoordinateState</code>, and
|
||||
<code>G43p4RtcpSyntax</code> has tagged the chain <code>Dynamic</code> because
|
||||
the tool orientation changes across the block. The linear axes hold
|
||||
the previous machine position (G53 applies no compensation, so the
|
||||
swing turns the axis in place instead of pinning the tool tip) and
|
||||
the motion is stamped <code>McLinear</code>; <code>ProgramXyz</code> is the tip's
|
||||
program coordinate after the swing — the 10 mm tool-height entry is
|
||||
inverted, MC Z 0 → program Z −10:
|
||||
#Previous:</p>
|
||||
<pre><code class="lang-csharp">{ "MachineCoordinateState": { "X": -1, "Y": -1, "Z": 0, "A": 90 } }</code></pre>
|
||||
<p>#BeforeBuild:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"Parsing": { "Flags": ["G53", "G00"] },
|
||||
"MachineCoordinateState": { "A": 0 },
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "ToolHeightCompensation",
|
||||
"Kind": "Dynamic",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,10,1]
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"MachineCoordinateState": { "A": 0, "X": -1, "Y": -1, "Z": 0 },
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "ToolHeightCompensation",
|
||||
"Kind": "Dynamic",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,10,1]
|
||||
}
|
||||
],
|
||||
"ProgramXyz": { "X": -1, "Y": -1, "Z": -10 },
|
||||
"MotionState": { "Term": "G00" },
|
||||
"MotionEvent": { "Form": "McLinear", "IsRapid": true, "Term": "G53" }
|
||||
}</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="title" content="Class ProgramEndSyntax | HiAPI-C# 2025 ">
|
||||
|
||||
<meta name="description" content="Consumes M02/M30 (program end) from and writes section. Downstream syntaxes that need to reset modal state on program end (e.g. for G52 reset) should read the section rather than scanning for M30 in Flags directly. Must be placed before syntaxes that depend on the ProgramEnd section.">
|
||||
<meta name="description" content="Consumes M02/M30 (program end) from and writes section. Downstream syntaxes that need to reset modal state on program end (e.g. for G52 reset) should read the section rather than scanning for M30 in Flags directly. The program-end edge. On a real controller M02/M30 ends the program and enters the reset state: the modal G codes return to their power-on defaults — tool length compensation is cancelled (G49, which also ends tool-center-point control: Fanuc TCP is cancelled by G49 or reset), the tilted work plane and coordinate rotation are cancelled (G69), cutter radius compensation is cancelled (G40), the canned cycle is cancelled (G80). A simulator that plays a file with several programs chained by M02 must keep playing, so the reset is modelled as an edge between the program-end block and its successor: the program-end block itself keeps the modal state it executed under (its own motion — G0 Z100. M30 — still sees the compensation), and the successor starts from the reset defaults. Each modal owner tests the edge with in its single-step node.Previous lookback and writes its cancel state on the successor instead of carrying: (G43/G44 → G49), (G43.4 → G49), (TRAORI → TRAFOOF, the D compensation itself stays — Siemens retains the active tool on reset), (M128 / TCPM → off, TOOL CALL compensation stays), (every tilt / rotation / frame term → G69), (G41/G42 → G40, the modal D is kept) and (→ G80). Deliberately not reset: G00/G01, G90/G91, G17–G19, G94/G95, the work offset (G54–G59) and the path-smoothing mode — their reset defaults are controller-parameter dependent and they do not enter the program→machine transform chain; G20/G21 is retained by the controller itself. G52 keeps its existing behaviour of clearing on the program-end block (HardNc parity). A block right after the edge that has no words at all (a comment line) is still the edge — every owner handles it before any "no Parsing" early return, or the modal carry would clone the active section across it. Must be placed before syntaxes that depend on the ProgramEnd section.">
|
||||
<link rel="icon" href="../img/HiAPI.favicon.ico">
|
||||
<link rel="stylesheet" href="../public/docfx.min.css">
|
||||
<link rel="stylesheet" href="../public/main.css">
|
||||
@@ -105,6 +105,40 @@ Downstream syntaxes that need to reset modal state on program end
|
||||
should read the <a class="xref" href="Hi.NcParsers.Keywords.ProgramEnd.html">ProgramEnd</a> section rather than
|
||||
scanning for M30 in Flags directly.
|
||||
</p>
|
||||
<p>
|
||||
<b>The program-end edge.</b> On a real controller M02/M30 ends the
|
||||
program and enters the reset state: the modal G codes return to their
|
||||
power-on defaults — tool length compensation is cancelled (G49, which
|
||||
also ends tool-center-point control: Fanuc TCP is cancelled by G49 or
|
||||
reset), the tilted work plane and coordinate rotation are cancelled
|
||||
(G69), cutter radius compensation is cancelled (G40), the canned cycle
|
||||
is cancelled (G80). A simulator that plays a file with several
|
||||
programs chained by M02 must keep playing, so the reset is modelled as
|
||||
an <i>edge</i> between the program-end block and its successor: the
|
||||
program-end block itself keeps the modal state it executed under (its
|
||||
own motion — <code>G0 Z100. M30</code> — still sees the compensation), and
|
||||
the successor starts from the reset defaults. Each modal owner tests
|
||||
the edge with <a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html#Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_Hi_Common_Collections_LazyLinkedListNode_Hi_NcParsers_Syntaxs_SyntaxPiece__">IsResetEdge(LazyLinkedListNode<SyntaxPiece>)</a> in its single-step
|
||||
<code>node.Previous</code> lookback and writes its cancel state on the
|
||||
successor instead of carrying: <a class="xref" href="Hi.NcParsers.LogicSyntaxs.ToolHeightOffsetSyntax.html">ToolHeightOffsetSyntax</a>
|
||||
(G43/G44 → G49), <a class="xref" href="Hi.NcParsers.LogicSyntaxs.G43p4RtcpSyntax.html">G43p4RtcpSyntax</a> (G43.4 → G49),
|
||||
<a class="xref" href="Hi.NcParsers.LogicSyntaxs.Siemens.SiemensTraoriSyntax.html">SiemensTraoriSyntax</a> (TRAORI → TRAFOOF, the
|
||||
D compensation itself stays — Siemens retains the active tool on
|
||||
reset), <a class="xref" href="Hi.NcParsers.LogicSyntaxs.Heidenhain.HeidenhainRtcpSyntax.html">HeidenhainRtcpSyntax</a> (M128 / TCPM
|
||||
→ off, TOOL CALL compensation stays), <a class="xref" href="Hi.NcParsers.LogicSyntaxs.TiltTransformUtil.html">TiltTransformUtil</a>
|
||||
(every tilt / rotation / frame term → G69),
|
||||
<a class="xref" href="Hi.NcParsers.PostLogicSyntaxs.RadiusCompensationSyntax.html">RadiusCompensationSyntax</a> (G41/G42 →
|
||||
G40, the modal D is kept) and <a class="xref" href="Hi.NcParsers.LogicSyntaxs.CannedCycleResolveSyntax.html">CannedCycleResolveSyntax</a>
|
||||
(→ G80). Deliberately not reset: G00/G01, G90/G91, G17–G19, G94/G95,
|
||||
the work offset (G54–G59) and the path-smoothing mode — their reset
|
||||
defaults are controller-parameter dependent and they do not enter the
|
||||
program→machine transform chain; G20/G21 is retained by the controller
|
||||
itself. G52 keeps its existing behaviour of clearing on the
|
||||
program-end block (HardNc parity). A block right after the edge that
|
||||
has no words at all (a comment line) is still the edge — every owner
|
||||
handles it before any "no Parsing" early return, or the modal carry
|
||||
would clone the active section across it.
|
||||
</p>
|
||||
Must be placed before syntaxes that depend on the ProgramEnd section.
|
||||
</div>
|
||||
<div class="markdown conceptual"></div>
|
||||
@@ -377,6 +411,51 @@ Must be placed before syntaxes that depend on the ProgramEnd section.
|
||||
|
||||
|
||||
|
||||
<a id="Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_" data-uid="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge*"></a>
|
||||
|
||||
<h3 id="Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_Hi_Common_Collections_LazyLinkedListNode_Hi_NcParsers_Syntaxs_SyntaxPiece__" data-uid="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge(Hi.Common.Collections.LazyLinkedListNode{Hi.NcParsers.Syntaxs.SyntaxPiece})">
|
||||
IsResetEdge(LazyLinkedListNode<SyntaxPiece>)
|
||||
|
||||
</h3>
|
||||
|
||||
<div class="markdown level1 summary"><p>True when <code class="paramref">node</code> is the first block after a
|
||||
program end — its predecessor carries the <a class="xref" href="Hi.NcParsers.Keywords.ProgramEnd.html">ProgramEnd</a>
|
||||
section (M02 / M30, or a brand equivalent such as klartext
|
||||
<code>END PGM</code>). Modal owners call this in their
|
||||
<code>node.Previous</code> lookback and, when true, write their reset
|
||||
(cancel) state on <code class="paramref">node</code> instead of carrying the
|
||||
predecessor's modal forward — see the class summary for the set.
|
||||
The section is one-shot (never carried), so the edge is exactly one
|
||||
block wide.</p>
|
||||
</div>
|
||||
<div class="markdown level1 conceptual"></div>
|
||||
|
||||
<div class="codewrapper">
|
||||
<pre><code class="lang-csharp hljs">public static bool IsResetEdge(LazyLinkedListNode<SyntaxPiece> node)</code></pre>
|
||||
</div>
|
||||
|
||||
<h4 class="section">Parameters</h4>
|
||||
<dl class="parameters">
|
||||
<dt><code>node</code> <a class="xref" href="Hi.Common.Collections.LazyLinkedListNode-1.html">LazyLinkedListNode</a><<a class="xref" href="Hi.NcParsers.Syntaxs.SyntaxPiece.html">SyntaxPiece</a>></dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
<h4 class="section">Returns</h4>
|
||||
<dl class="parameters">
|
||||
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
|
||||
<dd></dd>
|
||||
</dl>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<a id="Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_MakeXmlSource_" data-uid="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.MakeXmlSource*"></a>
|
||||
|
||||
<h3 id="Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_MakeXmlSource_System_String_System_String_System_Boolean_" data-uid="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.MakeXmlSource(System.String,System.String,System.Boolean)">
|
||||
|
||||
+27
@@ -309,6 +309,33 @@ consumed silently, nothing written:
|
||||
<pre><code class="lang-csharp">{ "Parsing": { "Flags": ["TRAFOOF"] } }</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{}</code></pre>
|
||||
<p>The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section next to the still-active TRAORI. This is
|
||||
the reset edge (<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the control's reset
|
||||
deactivates the transformation (the MD20110 default is TRAFOOF on
|
||||
reset) while the tool's D compensation stays active, so the block
|
||||
gets exactly the TRAFOOF hand-back — the section returns to the
|
||||
recorded owner with the plain translation entry:
|
||||
#Previous:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "M30" },
|
||||
"ToolHeightCompensation": {
|
||||
"Offset_mm": 50, "Term": "TRAORI", "OffsetId": 2, "PriorTerm": "D"
|
||||
}
|
||||
}</code></pre>
|
||||
<p>#BeforeBuild:</p>
|
||||
<pre><code class="lang-csharp">{}</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"ToolHeightCompensation": { "Offset_mm": 50, "Term": "D", "OffsetId": 2 },
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "ToolHeightCompensation",
|
||||
"Kind": "Static",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,50,1]
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -201,6 +201,16 @@ tilt rotation into <a class="xref" href="Hi.NcParsers.Keywords.ITransformationDe
|
||||
<div class="markdown level1 summary"><p>Carries forward the tilt transform from a previous node
|
||||
when the current block has no new tilt command.
|
||||
Shared by all tilt syntaxes (G68, G68.2, CYCLE800, PLANE SPATIAL).</p>
|
||||
<p>
|
||||
At the program-end edge (<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html#Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_Hi_Common_Collections_LazyLinkedListNode_Hi_NcParsers_Syntaxs_SyntaxPiece__">IsResetEdge(LazyLinkedListNode<SyntaxPiece>)</a>
|
||||
— the previous block carried M02 / M30 / <code>END PGM</code>) an active
|
||||
term is <b>not</b> carried: the controller's reset cancels the tilted
|
||||
work plane, the coordinate rotation and the programmable frames, so
|
||||
the successor gets the explicit cancel state (<code>G69</code> section +
|
||||
identity entry, the shape <a class="xref" href="Hi.NcParsers.LogicSyntaxs.TiltTransformUtil.html#Hi_NcParsers_LogicSyntaxs_TiltTransformUtil_TryHandleG69_System_Text_Json_Nodes_JsonObject_System_Text_Json_Nodes_JsonObject_">TryHandleG69(JsonObject, JsonObject)</a> writes) — an
|
||||
explicit section, so <a class="xref" href="Hi.NcParsers.PostLogicSyntaxs.ModalCarrySyntax.html">ModalCarrySyntax</a>
|
||||
does not clone the predecessor's active section onto it.
|
||||
</p>
|
||||
</div>
|
||||
<div class="markdown level1 conceptual"></div>
|
||||
|
||||
|
||||
@@ -300,6 +300,35 @@ and the same offset-1 table provides 99.98 mm:
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section next to the still-active G43 H1. This is
|
||||
the reset edge (<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the controller's
|
||||
reset cancels tool length compensation, so the modal is not carried
|
||||
and the block gets the same G49 sentinel and identity Mat4d an
|
||||
explicit G49 writes; the unrelated G00 flag survives:
|
||||
#Previous:
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "M30" },
|
||||
"ToolHeightCompensation": {
|
||||
"Offset_mm": 99.98, "Term": "G43", "OffsetId": 1
|
||||
}
|
||||
}</code></pre>
|
||||
#BeforeBuild:
|
||||
<pre><code class="lang-csharp">{ "Parsing": { "Flags": ["G00"] } }</code></pre>
|
||||
#AfterBuild:
|
||||
<pre><code class="lang-csharp">{
|
||||
"Parsing": { "Flags": ["G00"] },
|
||||
"ToolHeightCompensation": {
|
||||
"Offset_mm": 0, "Term": "G49", "OffsetId": 0
|
||||
},
|
||||
"ProgramToMcTransform": [
|
||||
{
|
||||
"Source": "ToolHeightCompensation",
|
||||
"Kind": "Static",
|
||||
"Mat4d": [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
|
||||
}
|
||||
]
|
||||
}</code></pre>
|
||||
|
||||
|
||||
<h2 id="Hi_NcParsers_LogicSyntaxs_ToolHeightOffsetSyntax_remarks">Remarks</h2>
|
||||
|
||||
@@ -655,9 +655,18 @@ active frame for one block; in this pipeline all of those reduce to
|
||||
which the ProgramXyz back-derivation below already models). The
|
||||
matched code is stamped verbatim into
|
||||
<a class="xref" href="Hi.NcParsers.Keywords.IMotionEventDef.html#Hi_NcParsers_Keywords_IMotionEventDef_Term">Term</a> for bidirectional source recovery.
|
||||
Rotary words on the same block (e.g. <code>SUPA G0 B0</code>) are left to
|
||||
<a class="xref" href="Hi.NcParsers.LogicSyntaxs.McAbcSyntax.html">McAbcSyntax</a> — same behavior as ISO G53, where rotary
|
||||
axes flow through the normal rotary path.
|
||||
Rotary words on the same block (e.g. <code>SUPA G0 B0</code>,
|
||||
<code>G53 A0 C0</code>) are consumed by <a class="xref" href="Hi.NcParsers.LogicSyntaxs.McAbcSyntax.html">McAbcSyntax</a> ahead of
|
||||
this syntax — machine and program rotary coincide while no rotary
|
||||
offsets are modeled — and the block is still a machine-coordinate
|
||||
positioning: the linear axes <b>hold their machine position</b>
|
||||
when no X/Y/Z word is given, and the motion is always
|
||||
<a class="xref" href="Hi.NcParsers.Keywords.Generic.MotionForm.html#Hi_NcParsers_Keywords_Generic_MotionForm_McLinear">McLinear</a>. A machine-coordinate block never
|
||||
takes the RTCP tool-center-point linkage: on a real controller G53
|
||||
applies no compensation, so a rotary swing commanded through it
|
||||
turns the axis in place instead of dragging X/Y/Z to pin the tool
|
||||
tip (the tip's post-swing program coordinate is what the
|
||||
back-derivation reports).
|
||||
</p>
|
||||
<p>
|
||||
Must be placed <b>before</b> <a class="xref" href="Hi.NcParsers.LogicSyntaxs.IncrementalResolveSyntax.html">IncrementalResolveSyntax</a>
|
||||
@@ -1138,6 +1147,40 @@ Downstream syntaxes that need to reset modal state on program end
|
||||
should read the <a class="xref" href="Hi.NcParsers.Keywords.ProgramEnd.html">ProgramEnd</a> section rather than
|
||||
scanning for M30 in Flags directly.
|
||||
</p>
|
||||
<p>
|
||||
<b>The program-end edge.</b> On a real controller M02/M30 ends the
|
||||
program and enters the reset state: the modal G codes return to their
|
||||
power-on defaults — tool length compensation is cancelled (G49, which
|
||||
also ends tool-center-point control: Fanuc TCP is cancelled by G49 or
|
||||
reset), the tilted work plane and coordinate rotation are cancelled
|
||||
(G69), cutter radius compensation is cancelled (G40), the canned cycle
|
||||
is cancelled (G80). A simulator that plays a file with several
|
||||
programs chained by M02 must keep playing, so the reset is modelled as
|
||||
an <i>edge</i> between the program-end block and its successor: the
|
||||
program-end block itself keeps the modal state it executed under (its
|
||||
own motion — <code>G0 Z100. M30</code> — still sees the compensation), and
|
||||
the successor starts from the reset defaults. Each modal owner tests
|
||||
the edge with <a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html#Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_Hi_Common_Collections_LazyLinkedListNode_Hi_NcParsers_Syntaxs_SyntaxPiece__">IsResetEdge(LazyLinkedListNode<SyntaxPiece>)</a> in its single-step
|
||||
<code>node.Previous</code> lookback and writes its cancel state on the
|
||||
successor instead of carrying: <a class="xref" href="Hi.NcParsers.LogicSyntaxs.ToolHeightOffsetSyntax.html">ToolHeightOffsetSyntax</a>
|
||||
(G43/G44 → G49), <a class="xref" href="Hi.NcParsers.LogicSyntaxs.G43p4RtcpSyntax.html">G43p4RtcpSyntax</a> (G43.4 → G49),
|
||||
<a class="xref" href="Hi.NcParsers.LogicSyntaxs.Siemens.SiemensTraoriSyntax.html">SiemensTraoriSyntax</a> (TRAORI → TRAFOOF, the
|
||||
D compensation itself stays — Siemens retains the active tool on
|
||||
reset), <a class="xref" href="Hi.NcParsers.LogicSyntaxs.Heidenhain.HeidenhainRtcpSyntax.html">HeidenhainRtcpSyntax</a> (M128 / TCPM
|
||||
→ off, TOOL CALL compensation stays), <a class="xref" href="Hi.NcParsers.LogicSyntaxs.TiltTransformUtil.html">TiltTransformUtil</a>
|
||||
(every tilt / rotation / frame term → G69),
|
||||
<a class="xref" href="Hi.NcParsers.PostLogicSyntaxs.RadiusCompensationSyntax.html">RadiusCompensationSyntax</a> (G41/G42 →
|
||||
G40, the modal D is kept) and <a class="xref" href="Hi.NcParsers.LogicSyntaxs.CannedCycleResolveSyntax.html">CannedCycleResolveSyntax</a>
|
||||
(→ G80). Deliberately not reset: G00/G01, G90/G91, G17–G19, G94/G95,
|
||||
the work offset (G54–G59) and the path-smoothing mode — their reset
|
||||
defaults are controller-parameter dependent and they do not enter the
|
||||
program→machine transform chain; G20/G21 is retained by the controller
|
||||
itself. G52 keeps its existing behaviour of clearing on the
|
||||
program-end block (HardNc parity). A block right after the edge that
|
||||
has no words at all (a comment line) is still the edge — every owner
|
||||
handles it before any "no Parsing" early return, or the modal carry
|
||||
would clone the active section across it.
|
||||
</p>
|
||||
Must be placed before syntaxes that depend on the ProgramEnd section.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
+15
@@ -273,6 +273,21 @@ the modal fallthrough, not real motion, so it counts as bare:
|
||||
"MotionEvent": { "Form": "McLinear" },
|
||||
"RadiusCompensation": { "Side": "None", "Term": "G40", "OffsetId": 1 }
|
||||
}</code></pre>
|
||||
<p>The first block after a program end — <code>#Previous:</code> carries the
|
||||
<code>ProgramEnd</code> section next to a still-active G41 D1. This is the
|
||||
reset edge (<a class="xref" href="Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html">ProgramEndSyntax</a>): the
|
||||
controller's reset cancels cutter compensation, so the block is
|
||||
written cancelled (G40) instead of inheriting G41; the modal D row
|
||||
is kept, as it is across an explicit G40:
|
||||
#Previous:</p>
|
||||
<pre><code class="lang-csharp">{
|
||||
"ProgramEnd": { "Term": "M02" },
|
||||
"RadiusCompensation": { "Side": "Left", "Term": "G41", "OffsetId": 1, "Radius_mm": 5 }
|
||||
}</code></pre>
|
||||
<p>#BeforeBuild:</p>
|
||||
<pre><code class="lang-csharp">{}</code></pre>
|
||||
<p>#AfterBuild:</p>
|
||||
<pre><code class="lang-csharp">{ "RadiusCompensation": { "Side": "None", "Term": "G40", "OffsetId": 1 } }</code></pre>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2528,6 +2528,9 @@
|
||||
<li>
|
||||
<a href="Hi.NcParsers.Dependencys.MCodeEffects.html" name="" title="MCodeEffects">MCodeEffects</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="Hi.NcParsers.Dependencys.StrokeLimitUtil.html" name="" title="StrokeLimitUtil">StrokeLimitUtil</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -235,6 +235,7 @@ is <a href="../../workflows/project-construction.html">Project Construction</a>.
|
||||
<li><a href="finding-your-way.html">Finding Your Way</a> — the screens a project change rebuilds, and what happens to a selection in one</li>
|
||||
<li><a href="messages-and-logs.html">Messages and Logs</a> — the footer's background zone and the toasts a project action raises, and where they can be read afterwards</li>
|
||||
<li><a href="../utilities/file-explorer.html">File Explorer</a> — the browser these entries open as a picker, and the Project root that is this folder</li>
|
||||
<li><a href="../run/a-mission-that-resumes.html">A Mission That Resumes</a> — what a project's folder has to hold for a run to restart where the last one stopped</li>
|
||||
</ul>
|
||||
|
||||
</article>
|
||||
|
||||
@@ -217,6 +217,14 @@ result.</li>
|
||||
that is still ticked becomes the first thing to run, so it reads its cache, and the run picks up
|
||||
from there.</li>
|
||||
</ul>
|
||||
<p><strong>Clearing a stage clears everything in it, including its record.</strong> A stage is a checkbox around a
|
||||
list, and a cleared one is skipped whole — so in a chain where the cache a stage resumes from is the
|
||||
<em>previous</em> stage's end-of-stage record, clearing that previous stage removes the very entry that
|
||||
would have loaded it. The run then starts from the stock, quietly and without an error. Either leave
|
||||
the earlier stages ticked and clear only the Program File rows inside them, or clear them but keep
|
||||
the one stage whose end-of-stage record you are resuming from, with its own programs cleared. The
|
||||
rule is simply that <strong>the record you are resuming from has to be reachable</strong>: every checkbox above
|
||||
it stays ticked.</p>
|
||||
<p>That last line is the point of the layout. The cost of getting back to the middle of a long job is
|
||||
one file read.</p>
|
||||
<h2 id="the-stage-0-cache-goes-stale-silently">The stage-0 cache goes stale, silently</h2>
|
||||
@@ -232,6 +240,26 @@ second operation in a chained pair, a stage-0 record buys no time at all and fre
|
||||
upstream stage can be re-run all it likes and this one keeps reading the copy it took the first
|
||||
time. There, the previous stage's own end-of-stage file is already the cache, and the stage needs
|
||||
no record above its program.</p>
|
||||
<h2 id="resuming-then-cutting-finer">Resuming, then cutting finer</h2>
|
||||
<p>A record freezes the workpiece <strong>as meshed at the width in force when it ran</strong>. Reading one back
|
||||
does not pin the rest of the run to that width: put a finer Machining Resolution below the record
|
||||
and above the next program, and that program's removal is built at the finer width. Measured on a
|
||||
roughing stage recorded at 0.5 mm — read back, then cut at 0.0625 mm — the cut ran at 0.0625 mm and
|
||||
took 779 s where the same program at 0.5 mm took 27 s, for five times the mesh's own memory. The
|
||||
request binds; the record is not a ceiling, and at this end of the ladder it is not free either.</p>
|
||||
<p>What reading back cannot do is add detail that was never stored. Surfaces inherited from the record
|
||||
keep the width they were recorded at; only what the later program cuts is meshed finer. That is
|
||||
normally exactly right — the roughed surface is about to be cut away, and the finish surface is the
|
||||
one the fine mesh is for.</p>
|
||||
<p>So <strong>record each stage at the width that stage needs — with one exception: the stage the finishing
|
||||
pass reads from.</strong> Everything the finishing tool does not touch keeps that record's width, and that
|
||||
includes the surface the finish is measured against. Choose that one record's width against the
|
||||
finish, then, rather than against the roughing stage it happens to belong to.</p>
|
||||
<p>The earlier stages have no such constraint. Roughing at the finishing width to be safe buys nothing
|
||||
and costs the whole roughing run at the finishing price.</p>
|
||||
<p>This is a different thing from the stage-0 trap above, which is about the record above a program
|
||||
caching the <em>stock</em>: there the frozen mesh is what the run starts from, so the resolution really is
|
||||
stuck until the file is cleared.</p>
|
||||
<h2 id="one-record-per-stage">One record per stage</h2>
|
||||
<p>A mission with several Program File entries gets a record after each, plus the stage-0 record where
|
||||
that one earns its place. Name each file after the stage it ends, not after the program that wrote
|
||||
|
||||
@@ -222,6 +222,7 @@ to what the mission asked for — see <a href="the-program-branch.html">The Prog
|
||||
<li><a href="the-program-branch.html">The Program Branch</a> — what the run recorded against each line</li>
|
||||
<li><a href="the-other-commands.html">The Other Commands</a> — the rest of the command kinds, including the script that drives a session without NC</li>
|
||||
<li><a class="xref" href="../../anatomy/execution/mission/NcFileCommand-panel.html">NcFileCommand Panel</a> — the component behind Program File: its fields, its picker and the endpoints behind the banner</li>
|
||||
<li><a href="a-mission-that-resumes.html">A Mission That Resumes</a> — the layout these two commands sit in when the run has to be restartable</li>
|
||||
<li><a class="xref" href="../../anatomy/execution/mission/NcCodeCommand-panel.html">NcCodeCommand Panel</a> — the component behind NC Code: its editor, its stats row and how it saves</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -226,6 +226,7 @@ Pause with <kbd>F6</kbd> first.</p>
|
||||
<li><a href="inspecting-a-step.html">Inspecting a Step</a> — the column that reads whichever step you stopped on</li>
|
||||
<li><a href="when-something-goes-wrong.html">When Something Goes Wrong</a> — what to read when the run does not do what you expected</li>
|
||||
<li><a href="../basics/the-app-window.html">The Application Window</a> — the menu bar's connection badge, and the footer this page's state is reported in</li>
|
||||
<li><a href="a-mission-that-resumes.html">A Mission That Resumes</a> — how to lay the mission out so a stopped run restarts from where it got to</li>
|
||||
<li><a class="xref" href="../../anatomy/execution/execution-tool-bar.html">Execution Tool Bar</a> — the component behind these buttons: the enable rules, the status feed and the key bindings</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -323,6 +323,11 @@ public XElement MakeXmlSource(string baseDirectory, string relFile, bool exhibit
|
||||
return new XElement(XName,
|
||||
this.GetNameNoteXElementList(),
|
||||
new XElement(nameof(EnergyEfficiency), EnergyEfficiency),
|
||||
//the constructor reads this element; without the matching write a
|
||||
//save/load round trip through the web API silently reverted a
|
||||
//non-default bound to the 65 C default.
|
||||
new XElement(nameof(WorkingTemperatureUpperBoundary_C),
|
||||
WorkingTemperatureUpperBoundary_C),
|
||||
new XElement(nameof(GearShiftSpindleSpeed_rpm), GearShiftSpindleSpeed_rpm),
|
||||
new XElement(nameof(DryRunFrictionPowerCoefficient_mWdrpm),
|
||||
DryRunFrictionPowerCoefficient_mWdrpm),
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
<li><code>TMV-720A-STD-8000RPM.SpindleCapability</code></li>
|
||||
<li><code>VP-8--Fanuc-10000RPM.SpindleCapability</code></li>
|
||||
</ul>
|
||||
<p>To edit values interactively, see <a class="xref" href="../../anatomy/general-setup/spindle-capability.html">Spindle Capability Page</a> in the Quasar webservice. The desktop WPF app does not yet have a dedicated editor; load capabilities through the equipment's <code>ObjectManagementMenuButton</code> instead.</p>
|
||||
<p>To edit values interactively, see <a class="xref" href="../../anatomy/general-setup/spindle-capability.html">Spindle Capability Page</a>.</p>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
<ul>
|
||||
<li><a class="xref" href="../milling-physics/machinability.html">Process Machinability</a> — uses <code>MaxSpindleTorqueRatio</code> / <code>MaxSpindlePowerRatio</code> for tool-breakage prediction</li>
|
||||
|
||||
@@ -136,10 +136,9 @@
|
||||
<p>To make the Color Guide effective in a project, implement the <a class="xref" href="../../api/Hi.Coloring.IColorGuide.html">IColorGuide</a> interface and register it in the project's color guide dictionary.</p>
|
||||
<h2 id="xml-serialization">XML Serialization</h2>
|
||||
<p>See <a class="xref" href="../api-foundations/xml-io.html">About XML IO</a> for details on XML serialization implementation.</p>
|
||||
<h2 id="wpf-application-source-and-sample-code-path">WPF Application Source And Sample Code Path</h2>
|
||||
<h2 id="source-code-path">Source Code Path</h2>
|
||||
<ul>
|
||||
<li>HiMech/Coloring/IColorGuide</li>
|
||||
<li>HiNC-2025-win-desktop/Demo/DemoColorGuide</li>
|
||||
<li><code>HiMech/Coloring/IColorGuide.cs</code></li>
|
||||
</ul>
|
||||
<p>See <a class="xref" href="../../anatomy/index.html">HiNC App Anatomy</a> for git repository links.</p>
|
||||
<h2 id="see-also">See Also</h2>
|
||||
|
||||
@@ -153,9 +153,87 @@ than the run needs, the next value that changes anything is 0.5 mm — and going
|
||||
0.125 mm is another eight times the voxels, not a small step.</p>
|
||||
<p>The ladder bottoms out at <strong>0.001953125 mm</strong>. A finer request is clamped to it, so the finest entry
|
||||
offered in the workpiece's Initial Resolution list builds the same mesh as the one above it.</p>
|
||||
<h2 id="the-width-only-ever-goes-finer">The width only ever goes finer</h2>
|
||||
<p>A mesh that exists cannot be coarsened. Every cut takes the <strong>finer</strong> of the width already built and
|
||||
the width being asked for, so raising Machining Resolution above the mesh the workpiece was built at
|
||||
does not simplify anything — the request is dropped and the run keeps the mesh it has.</p>
|
||||
<p>This is why the two settings are not interchangeable. The workpiece's <strong>Initial Resolution</strong> is what
|
||||
builds the mesh and is therefore the memory setting; <strong>Machining Resolution</strong> gates how fine a
|
||||
<em>newly cut</em> surface may go, and can only ever refine. To make a run cheaper in memory, coarsen the
|
||||
Initial Resolution — coarsening Machining Resolution alone changes nothing about the stock that is
|
||||
already there.</p>
|
||||
<p>It still changes the <em>time</em>, and by a lot, because the same number sizes two other things: the
|
||||
tessellation of the cutter's own solid, and the number of engagement layers per step. Both are
|
||||
per-step work that is thrown away again, so a coarser Machining Resolution can cut the run time
|
||||
several-fold while the memory figure does not move at all. A run that got faster without getting
|
||||
smaller is this, not a mystery.</p>
|
||||
<p>Pick from the ladder and the number shown in the mission row is the number the run used. That
|
||||
matters beyond tidiness: a recorded mesh is built at whatever resolution is in force when the
|
||||
record runs, so an off-ladder value is silently baked into the cache as its rounded neighbour.</p>
|
||||
<h2 id="what-it-costs-in-memory">What It Costs in Memory</h2>
|
||||
<p>Far less than it costs in time, which is the opposite of what four rungs of the ladder — sixteen
|
||||
times finer, and so four thousand times the voxels — leads most people to expect. Measured by
|
||||
sweeping one case across five rungs with the program and the step count held fixed — a cylindrical
|
||||
blank, one roughing program, 199,242 steps every run:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Mesh width</th>
|
||||
<th>Play time</th>
|
||||
<th>Process memory outside the managed heap</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>2 mm</td>
|
||||
<td>10.5 s</td>
|
||||
<td>665 MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1 mm</td>
|
||||
<td>15.3 s</td>
|
||||
<td>688 MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0.5 mm</td>
|
||||
<td>31.2 s</td>
|
||||
<td>722 MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0.25 mm</td>
|
||||
<td>76.6 s</td>
|
||||
<td>826 MB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>0.125 mm</td>
|
||||
<td>242.9 s</td>
|
||||
<td>1,456 MB</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Sixteen times finer costs <strong>23 times the time and 2.2 times the memory</strong>. Two things flatten that
|
||||
second column, and it is worth separating them:</p>
|
||||
<ul>
|
||||
<li><strong>Most of the figure is a baseline the mesh does not set.</strong> The coarsest run in the sweep already
|
||||
sits at 665 MB, and the whole sixteen-fold refinement adds 791 MB on top of it. Read the column as
|
||||
increments rather than as totals: the ratio at the bottom of the table is diluted by everything in
|
||||
the figure that would be there at any mesh width.</li>
|
||||
<li><strong>The increments grow slowly at coarse widths and then accelerate.</strong> Halving the width added
|
||||
23 MB, then 34, then 104, then 630 — each increment about 1.5, then 3.1, then 6.1 times the one
|
||||
before it, a local exponent climbing from roughly 0.6 to 2.6. A cube stops subdividing as soon as
|
||||
the surface inside it is a single flat facet, so while the mesh is coarser than the part's facets
|
||||
and curvature, refining mostly buys nothing. The volume-scaling intuition is not wrong; it only
|
||||
arrives once the width is below the feature scale, and by then it arrives fast.</li>
|
||||
</ul>
|
||||
<p>A big <em>workpiece</em> moves the same curve up: where the stock is a large imported solid rather than a
|
||||
small procedural blank, there is far more surface to subdivide and the mesh-dependent part dominates
|
||||
much earlier.</p>
|
||||
<p><strong>Do not judge the mesh by the process's peak memory.</strong> On a long run most of that figure is the
|
||||
per-step data the run accumulates, which lives on the managed heap, scales with the number of steps
|
||||
and not with the mesh at all — and it moves the <em>other</em> way when the mesh is refined, because a
|
||||
slower run allocates more slowly and the collector commits less. The two cancel: measured on a
|
||||
larger case across a four-fold refinement, peak memory fell slightly while the mesh's own footprint
|
||||
grew by nearly 40%. Read the two apart before concluding anything.</p>
|
||||
<h2 id="what-the-mesh-does-not-change">What the Mesh Does Not Change</h2>
|
||||
<p>For a representative test case — downward circular slot milling with varying width and depth —
|
||||
the <strong>physical</strong> values move within about <strong>20%</strong> across the full range of mesh widths. The
|
||||
|
||||
@@ -367,7 +367,7 @@ refining further showed no benefit.</p>
|
||||
<pre><code class="lang-csharp">WriteStepFiles("Output/[NcName].step.csv");
|
||||
WriteShotFiles("Output/[NcName].shot.csv", 0.1); // 2nd arg = sampling period in ms
|
||||
</code></pre>
|
||||
<p>The shot file contains time-resolved force columns: <code>Tool.Fx/Fy/Fz</code>, <code>Workpiece.Fx/Fy/Fz</code>, <code>Spindle.Mx/My/Mz</code>.</p>
|
||||
<p>The shot file opens with <code>FileNo</code>, <code>LineNo</code>, <code>Time</code> and the mission's M-codes, then carries the time-resolved force columns: <code>Tool.Fx/Fy/Fz</code>, <code>Workpiece.Fx/Fy/Fz</code>, <code>Holder.Mx/My/Mz</code> — the same holder spelling the reader writes, not the obsolete <code>Spindle.M*</code>. A play driven from a controller CSV appends <code>ActualDateTime</code>; an NC-simulated play has no controller instant to stamp and omits that column.</p>
|
||||
<h3 id="-the-shot-sampling-period-is-the-dominant-accuracy-lever">⚠ The shot sampling period is the dominant accuracy lever</h3>
|
||||
<p>The second argument of <a class="xref" href="../api/Hi.MachiningProcs.SessionShell.html#Hi_MachiningProcs_SessionShell_WriteShotFiles_">WriteShotFiles</a> is the sampling period in <strong>milliseconds</strong>, and when a simulated shot file is fed back into training it — not the angular division count, not the machining resolution — sets the accuracy ceiling. Each row is interpolated from the per-division force waveform, so the information per revolution is <code>min(MillingCycleDivisionNum, samples per revolution)</code>, where</p>
|
||||
<pre><code>samples per revolution = 60000 / (rpm × samplingPeriod_ms)
|
||||
|
||||
@@ -119270,6 +119270,50 @@ references:
|
||||
isSpec: "True"
|
||||
fullName: Hi.NcParsers.Dependencys.Siemens.SiemensToolOffsetTableProxy.XName
|
||||
nameWithType: SiemensToolOffsetTableProxy.XName
|
||||
- uid: Hi.NcParsers.Dependencys.StrokeLimitUtil
|
||||
name: StrokeLimitUtil
|
||||
href: api/Hi.NcParsers.Dependencys.StrokeLimitUtil.html
|
||||
commentId: T:Hi.NcParsers.Dependencys.StrokeLimitUtil
|
||||
fullName: Hi.NcParsers.Dependencys.StrokeLimitUtil
|
||||
nameWithType: StrokeLimitUtil
|
||||
- uid: Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes(System.Collections.Generic.IEnumerable{System.String},System.Func{System.String,System.Nullable{System.Double}},System.Func{System.String,System.Nullable{System.Double}})
|
||||
name: DescribeUnlimitedAxes(IEnumerable<string>, Func<string, double?>, Func<string, double?>)
|
||||
href: api/Hi.NcParsers.Dependencys.StrokeLimitUtil.html#Hi_NcParsers_Dependencys_StrokeLimitUtil_DescribeUnlimitedAxes_System_Collections_Generic_IEnumerable_System_String__System_Func_System_String_System_Nullable_System_Double___System_Func_System_String_System_Nullable_System_Double___
|
||||
commentId: M:Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes(System.Collections.Generic.IEnumerable{System.String},System.Func{System.String,System.Nullable{System.Double}},System.Func{System.String,System.Nullable{System.Double}})
|
||||
name.vb: DescribeUnlimitedAxes(IEnumerable(Of String), Func(Of String, Double?), Func(Of String, Double?))
|
||||
fullName: Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes(System.Collections.Generic.IEnumerable<string>, System.Func<string, double?>, System.Func<string, double?>)
|
||||
fullName.vb: Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes(System.Collections.Generic.IEnumerable(Of String), System.Func(Of String, Double?), System.Func(Of String, Double?))
|
||||
nameWithType: StrokeLimitUtil.DescribeUnlimitedAxes(IEnumerable<string>, Func<string, double?>, Func<string, double?>)
|
||||
nameWithType.vb: StrokeLimitUtil.DescribeUnlimitedAxes(IEnumerable(Of String), Func(Of String, Double?), Func(Of String, Double?))
|
||||
- uid: Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes*
|
||||
name: DescribeUnlimitedAxes
|
||||
href: api/Hi.NcParsers.Dependencys.StrokeLimitUtil.html#Hi_NcParsers_Dependencys_StrokeLimitUtil_DescribeUnlimitedAxes_
|
||||
commentId: Overload:Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes
|
||||
isSpec: "True"
|
||||
fullName: Hi.NcParsers.Dependencys.StrokeLimitUtil.DescribeUnlimitedAxes
|
||||
nameWithType: StrokeLimitUtil.DescribeUnlimitedAxes
|
||||
- uid: Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames(Hi.Numerical.Xyzabc.IXyzabcChain,System.Boolean)
|
||||
name: GetChainAxisNames(IXyzabcChain, bool)
|
||||
href: api/Hi.NcParsers.Dependencys.StrokeLimitUtil.html#Hi_NcParsers_Dependencys_StrokeLimitUtil_GetChainAxisNames_Hi_Numerical_Xyzabc_IXyzabcChain_System_Boolean_
|
||||
commentId: M:Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames(Hi.Numerical.Xyzabc.IXyzabcChain,System.Boolean)
|
||||
name.vb: GetChainAxisNames(IXyzabcChain, Boolean)
|
||||
fullName: Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames(Hi.Numerical.Xyzabc.IXyzabcChain, bool)
|
||||
fullName.vb: Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames(Hi.Numerical.Xyzabc.IXyzabcChain, Boolean)
|
||||
nameWithType: StrokeLimitUtil.GetChainAxisNames(IXyzabcChain, bool)
|
||||
nameWithType.vb: StrokeLimitUtil.GetChainAxisNames(IXyzabcChain, Boolean)
|
||||
- uid: Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames*
|
||||
name: GetChainAxisNames
|
||||
href: api/Hi.NcParsers.Dependencys.StrokeLimitUtil.html#Hi_NcParsers_Dependencys_StrokeLimitUtil_GetChainAxisNames_
|
||||
commentId: Overload:Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames
|
||||
isSpec: "True"
|
||||
fullName: Hi.NcParsers.Dependencys.StrokeLimitUtil.GetChainAxisNames
|
||||
nameWithType: StrokeLimitUtil.GetChainAxisNames
|
||||
- uid: Hi.NcParsers.Dependencys.StrokeLimitUtil.McAxisNames
|
||||
name: McAxisNames
|
||||
href: api/Hi.NcParsers.Dependencys.StrokeLimitUtil.html#Hi_NcParsers_Dependencys_StrokeLimitUtil_McAxisNames
|
||||
commentId: F:Hi.NcParsers.Dependencys.StrokeLimitUtil.McAxisNames
|
||||
fullName: Hi.NcParsers.Dependencys.StrokeLimitUtil.McAxisNames
|
||||
nameWithType: StrokeLimitUtil.McAxisNames
|
||||
- uid: Hi.NcParsers.Dependencys.Syntec
|
||||
name: Hi.NcParsers.Dependencys.Syntec
|
||||
href: api/Hi.NcParsers.Dependencys.Syntec.html
|
||||
@@ -137703,6 +137747,22 @@ references:
|
||||
isSpec: "True"
|
||||
fullName: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.Build
|
||||
nameWithType: ProgramEndSyntax.Build
|
||||
- uid: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge(Hi.Common.Collections.LazyLinkedListNode{Hi.NcParsers.Syntaxs.SyntaxPiece})
|
||||
name: IsResetEdge(LazyLinkedListNode<SyntaxPiece>)
|
||||
href: api/Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html#Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_Hi_Common_Collections_LazyLinkedListNode_Hi_NcParsers_Syntaxs_SyntaxPiece__
|
||||
commentId: M:Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge(Hi.Common.Collections.LazyLinkedListNode{Hi.NcParsers.Syntaxs.SyntaxPiece})
|
||||
name.vb: IsResetEdge(LazyLinkedListNode(Of SyntaxPiece))
|
||||
fullName: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge(Hi.Common.Collections.LazyLinkedListNode<Hi.NcParsers.Syntaxs.SyntaxPiece>)
|
||||
fullName.vb: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge(Hi.Common.Collections.LazyLinkedListNode(Of Hi.NcParsers.Syntaxs.SyntaxPiece))
|
||||
nameWithType: ProgramEndSyntax.IsResetEdge(LazyLinkedListNode<SyntaxPiece>)
|
||||
nameWithType.vb: ProgramEndSyntax.IsResetEdge(LazyLinkedListNode(Of SyntaxPiece))
|
||||
- uid: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge*
|
||||
name: IsResetEdge
|
||||
href: api/Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html#Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_IsResetEdge_
|
||||
commentId: Overload:Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge
|
||||
isSpec: "True"
|
||||
fullName: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.IsResetEdge
|
||||
nameWithType: ProgramEndSyntax.IsResetEdge
|
||||
- uid: Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.MakeXmlSource(System.String,System.String,System.Boolean)
|
||||
name: MakeXmlSource(string, string, bool)
|
||||
href: api/Hi.NcParsers.LogicSyntaxs.ProgramEndSyntax.html#Hi_NcParsers_LogicSyntaxs_ProgramEndSyntax_MakeXmlSource_System_String_System_String_System_Boolean_
|
||||
|
||||
Reference in New Issue
Block a user