This commit is contained in:
2026-09-09 17:35:23 +08:00
parent 2a98ae7556
commit 161af68fe3
1271 changed files with 58251 additions and 98639 deletions
@@ -0,0 +1,194 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Geometry Objects | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Geometry Objects | HiAPI-C# 2025 ">
<link rel="icon" href="../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Technique-BasicGeometry">
<h1 id="geometry-objects">Geometry Objects</h1>
<p><strong><a class="xref" href="../../api/Hi.Geom.IGetStl.html">IGetStl</a></strong> is the single-member interface that hands back an <a class="xref" href="../../api/Hi.Geom.Stl.html">Stl</a>, and
it is what the geometries listed below have in common — most of them reach it through
<a class="xref" href="../../api/Hi.Geom.IStlSource.html">IStlSource</a>, which adds XML persistence on top of it. It does not span every geometry
object: a voxel mesh reference such as <a class="xref" href="../../api/Hi.Cbtr.CubeTreeFile.html">CubeTreeFile</a> persists itself and presents
itself without ever answering <code>GetStl</code>. Code meant to accept every kind of geometry binds to the
interface that group actually shares, not to <code>IGetStl</code>.</p>
<p>Several common geometry types are available:</p>
<ul>
<li>Basic Geometrys
<ul>
<li><a class="xref" href="../../api/Hi.Geom.Box3d.html">Box3d</a></li>
<li><a class="xref" href="../../api/Hi.Geom.Cylindroid.html">Cylindroid</a></li>
<li><a class="xref" href="../../api/Hi.Geom.Stl.html">Stl</a></li>
<li><a class="xref" href="../../api/Hi.Geom.StlFile.html">StlFile</a></li>
</ul>
</li>
<li>Management Geometrys
<ul>
<li><a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a></li>
<li><a class="xref" href="../../api/Hi.Geom.GeomCombination.html">GeomCombination</a></li>
</ul>
</li>
</ul>
<p>See <a class="xref" href="../mechanism/transformers.html">Transformations</a> for <a class="xref" href="../../api/Hi.Geom.TransformationGeom.html">TransformationGeom</a>.</p>
<ul>
<li><a class="xref" href="../../api/Hi.Mech.Topo.GeneralTransform.html">GeneralTransform</a></li>
<li><a class="xref" href="../../api/Hi.Mech.Topo.StaticRotation.html">StaticRotation</a></li>
<li><a class="xref" href="../../api/Hi.Mech.Topo.StaticTranslation.html">StaticTranslation</a></li>
</ul>
<div class="NOTE">
<h5>Note</h5>
<p>All coordinate values use standard units (millimeters, radians)</p>
</div>
<h2 id="example-usage">Example Usage</h2>
<pre><code class="lang-csharp" name="SampleCode">using System;
using System.Collections.Generic;
using Hi.Geom;
using Hi.Mech.Topo;
namespace Sample.Geom;
/// &lt;summary&gt;
/// Demonstrates the creation and manipulation of geometric objects in HiAPI.
/// Shows how to create and transform various geometry types including boxes, cylindroids, and STL files.
/// &lt;/summary&gt;
/// &lt;remarks&gt;
/// ### Source Code
/// [!code-csharp[SampleCode](~/../Hi.Sample/Geom/DemoBuildGeom.cs)]
/// &lt;/remarks&gt;
public static class DemoBuildGeom
{
/// &lt;summary&gt;
/// Generates a collection of geometric objects for demonstration purposes.
/// Creates various geometry types including boxes, cylindroids, STL files, and transformed geometries.
/// &lt;/summary&gt;
/// &lt;returns&gt;A list of geometries implementing the IGetStl interface&lt;/returns&gt;
public static List&lt;IGetStl&gt; GenGeoms()
{
Box3d box = new Box3d(0, 0, -50, 70, 50, 0);
Cylindroid cylindroid = new Cylindroid([ new PairZr(0,12),new PairZr(20,12),
new PairZr(20,16),new PairZr(30,16)]);
Stl stl = new Stl(&quot;geom.stl&quot;);
StlFile stlFile = new StlFile(&quot;geom.stl&quot;);
TransformationGeom transformationGeom = new TransformationGeom()
{
Transformer = new GeneralTransform(1,
new StaticRotation(new Vec3d(0, 0, 1), MathUtil.ToRad(15), new Vec3d(0, 0, 0)),
new StaticTranslation(new Vec3d(0, 0, 0))),
Geom = stl
};
GeomCombination geomCombination = new GeomCombination(stlFile, transformationGeom);
return new List&lt;IGetStl&gt;([box, cylindroid, stl, stlFile, transformationGeom]);
}
}
</code></pre><h2 id="see-also">See Also</h2>
<ul>
<li><a href="getting-started.html">Getting Started with HiAPI</a> — the environment these geometries are assembled into</li>
<li><a href="xml-io.html">About XML IO</a> — how a geometry is persisted with its project</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,282 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Getting Started with HiAPI | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Getting Started with HiAPI | HiAPI-C# 2025 ">
<link rel="icon" href="../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Technique-GettingStarted">
<h1 id="getting-started-with-hiapi">Getting Started with HiAPI</h1>
<p>What a first HiAPI application needs: where the packages come from, what the program has to
initialise, and the shape every HiNC program follows once it runs.</p>
<h2 id="installation">Installation</h2>
<ol>
<li><p>Create a dotnet project. A console or service project targets <strong>net10.0</strong>. A project that also
takes one of the Windows UI packages targets <strong>net10.0-windows</strong> — that is what <code>Hi.WinForm</code> and
<code>Hi.WpfPlus</code> are built for, and a plain <code>net10.0</code> project cannot reference them. An earlier
target framework cannot reference any of the packages.</p>
</li>
<li><p>Register the HiAPI package source on the machine.</p>
<p>The feed requires authentication, and the same account that gives you the sample repositories
gives you the packages. One command registers the source <em>and</em> its credentials, which is the
whole of what a restore needs:</p>
<pre><code>dotnet nuget add source https://superhightech-gitea.webredirect.org/api/packages/HiAPI/nuget/index.json --name HiAPI --username &lt;your-account&gt; --password &lt;your-token&gt; --store-password-in-clear-text
</code></pre>
<p>Run it once per machine. Customers served by the mainland mirror register the feed address
issued with their account in place of the URL above; nothing else changes.</p>
<p><strong>Prefer this to a project-local <code>nuget.config</code>, and never declare the feed in both places.</strong>
NuGet resolves credentials by source <em>name</em>, and the match is case-sensitive, so a file that
declares the same URL under a name the machine holds no credentials for adds a <em>second</em>,
credential-less source. NuGet asks every source about every package, and one <code>401</code> fails the
whole restore instead of falling through — so the packages it then reports as missing are the
public <code>nuget.org</code> ones, and the cause is nowhere near the symptom. A credential-free file
cannot stand in for the command either: the feed rejects anonymous requests, so it carries a
fresh clone no further than having no source at all.</p>
<p>Where a per-machine source is genuinely unavailable — an ephemeral build agent, say — a
<code>nuget.config</code> beside the project file does the job, provided it is the only declaration of
that URL and carries its own credentials under exactly the key it gave the source:</p>
<pre><code class="lang-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;configuration&gt;
&lt;packageSources&gt;
&lt;add key=&quot;HiAPI&quot; value=&quot;https://superhightech-gitea.webredirect.org/api/packages/HiAPI/nuget/index.json&quot; /&gt;
&lt;add key=&quot;nuget.org&quot; value=&quot;https://api.nuget.org/v3/index.json&quot; protocolVersion=&quot;3&quot; /&gt;
&lt;/packageSources&gt;
&lt;packageSourceCredentials&gt;
&lt;HiAPI&gt;
&lt;add key=&quot;Username&quot; value=&quot;xxxxxx&quot; /&gt;
&lt;add key=&quot;ClearTextPassword&quot; value=&quot;xxxxxx&quot; /&gt;
&lt;/HiAPI&gt;
&lt;/packageSourceCredentials&gt;
&lt;/configuration&gt;
</code></pre>
<p>That file holds a password in clear text: keep it out of version control.</p>
</li>
<li><p>In the dotnet project file, add the package reference.</p>
<pre><code class="lang-xml">&lt;ItemGroup&gt;
&lt;PackageReference Include=&quot;HiNc&quot; Version=&quot;3.2.*&quot; /&gt;
&lt;!--optional; needs a net10.0-windows project--&gt;
&lt;PackageReference Include=&quot;Hi.WpfPlus&quot; Version=&quot;3.2.*&quot; /&gt;
&lt;/ItemGroup&gt;
</code></pre>
</li>
<li><p>In the program file, setting the HiNC application initialization and finalization.</p>
<pre><code class="lang-csharp" name="SampleCode">using Hi.HiNcKits;
using Microsoft.Extensions.Logging;
using System;
namespace Sample
{
/// &lt;summary&gt;
/// A sample class demonstrating initialization and usage of the HiAPI framework.
/// Shows the basic setup of display engine, MongoDB server, licensing, and other core functionality.
/// &lt;/summary&gt;
/// &lt;remarks&gt;
/// This example serves as an entry point for those getting started with HiAPI.
/// It demonstrates proper initialization and teardown of key components.
/// ### Source Code
/// [!code-csharp[SampleCode](~/../Hi.Sample/HelloHiAPI.cs)]
/// &lt;/remarks&gt;
public static class HelloHiAPI
{
static int Main(string[] args)
{
Console.WriteLine(&quot;HiAPI starting.&quot;);
using var loggerFactory = Microsoft.Extensions.Logging.LoggerFactory.Create(b =&gt; b.AddConsole());
LocalApp.AppBegin(loggerFactory.CreateLogger(&quot;Hi.Sample&quot;));
Console.WriteLine(&quot;Hello World! HiAPI.&quot;);
LocalApp.AppEnd();
Console.WriteLine(&quot;HiAPI exited.&quot;);
return 0;
}
}
}
</code></pre></li>
</ol>
<h2 id="the-shape-of-a-hinc-program">The Shape of a HiNC Program</h2>
<p>Every HiNC program, whether it is the shipped application or twenty lines in a console project,
runs the same five steps. <code>DemoBuildMachiningProject</code> in the Hi.Sample repository is the complete
worked example.</p>
<pre><code class="lang-mermaid">graph TD
A[&quot;Create MachiningProject&quot;] --&gt; B[&quot;Setting Environment&quot;]
B --&gt; C[&quot;Setting Project Tasks&quot;]
C --&gt; D[&quot;Run Tasks&quot;]
D --&gt; E[&quot;View Analysis Results&quot;]
</code></pre>
<h3 id="1-create-">1. Create <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a></h3>
<p>Creating a machining project is the first step in the HiNC workflow, accomplished by initializing a <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a> object.</p>
<h3 id="2-setting-environment-in-">2. Setting Environment In <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a></h3>
<p>The equipment has two faces. <a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html">SetupEquipment</a> is the
authored one — the only face a project file persists, and the one every setting below is written to.
<a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.MachiningEquipment.html">MachiningEquipment</a> is the runtime face the runner,
physics, collision and execution display read; it is rebuilt from the authored face at project
assignment and at session boundaries, so a value written onto it is discarded rather than saved.</p>
<ul>
<li>Set <a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html">SetupEquipment</a>:
<ul>
<li>Usually one-time settings:
<ul>
<li><a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html#Hi_Machining_MachiningEquipmentUtils_SetupEquipment_MachiningChain">MachiningChain</a> - Configure the complete machine tool including geometry, kinematic chain, and coordinate transformations</li>
<li><a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html#Hi_Machining_MachiningEquipmentUtils_SetupEquipment_SpindleCapability">SpindleCapability</a> - Configure <a class="xref" href="../../api/Hi.Milling.SpindleCapability.html">SpindleCapability</a></li>
<li><a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html#Hi_Machining_MachiningEquipmentUtils_SetupEquipment_CoolantHeatCondition">CoolantHeatCondition</a> - Configure coolant heat conditions</li>
<li><a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html#Hi_Machining_MachiningEquipmentUtils_SetupEquipment_BackgroundTemperature_C">BackgroundTemperature_C</a> - Configure the environment background temperature in Celsius; <a class="xref" href="../../api/Hi.Machining.MachiningEquipmentUtils.SetupEquipment.html#Hi_Machining_MachiningEquipmentUtils_SetupEquipment_BackgroundTemperature_K">BackgroundTemperature_K</a> holds the same value in Kelvin</li>
</ul>
</li>
<li>Variable settings:
<ul>
<li><a class="xref" href="../../api/Hi.NcMech.Fixtures.Fixture.html">Fixture</a> - Configure fixture</li>
<li><a class="xref" href="../../api/Hi.NcMech.Workpieces.Workpiece.html">Workpiece</a> - Configure workpiece</li>
</ul>
</li>
</ul>
</li>
<li>Set <a class="xref" href="../../api/Hi.Machining.MachiningToolHouse.html">MachiningToolHouse</a> - Configure tool house</li>
<li>Set <a class="xref" href="../../api/Hi.Numerical.HardNcEnv.html">HardNcEnv</a> (Controller) - Configure NC system environment parameters</li>
</ul>
<h3 id="3-setting-project-tasks">3. Setting Project Tasks</h3>
<p>Set sequential tasks using <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html#Hi_MachiningProcs_MachiningProject_PlayerCommand">PlayerCommand</a>:</p>
<ul>
<li>Set NC Files - Set the file path and customize simulation and optimization settings for each NC file</li>
<li>Configure NC optimization - Configure NC code optimization parameters</li>
<li>Set <a class="xref" href="../../api/Hi.SessionCommands.GeomDiffCommand.html">GeomDiffCommand</a> - Configure geometry comparison functionality to compare target workpiece shape with simulated shape</li>
<li>Set <a class="xref" href="../../api/Hi.MillingForces.Training.MillingTraining.html">MillingTraining</a> - Configure milling parameter training to calibrate simulation parameters based on actual machining data</li>
<li>Other task configurations&hellip;</li>
</ul>
<p>The PlayerCommand is typically a <a class="xref" href="../../api/Hi.SessionCommands.ListCommand.html">ListCommand</a> that contains a sequence of command entries to be executed during the simulation.</p>
<h3 id="4-run-the-tasks-simulation-and-optimization">4. Run the Tasks (Simulation and Optimization)</h3>
<p>Run <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html#Hi_MachiningProcs_MachiningProject_PlayerCommand">PlayerCommand</a> through <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_PacePlayer">PacePlayer</a>.</p>
<p>At this stage, the simulation process is similar to video playback, which can be:</p>
<ul>
<li>Started</li>
<li>Stopped</li>
<li>Paused</li>
<li>Run one line</li>
<li>Run one step</li>
<li>Reset</li>
</ul>
<p>The <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_PacePlayer">PacePlayer</a> controls the execution pace of the simulation, allowing you to observe the machining process in detail or run it at full speed.</p>
<h4 id="view-the-analysis-during-process-or-result">View the Analysis During Process or Result</h4>
<p><a class="xref" href="../../api/Hi.MachiningProcs.ShellProgress.html">ShellProgress</a> contains a sequence of simulation messages and step data, which can be used to monitor and analyze the simulation process and results.</p>
<h2 id="sample-code-to-start-a-">Sample Code to Start a <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a></h2>
<p>See the following sample code to start a HiAPI application.</p>
<ul>
<li><code>DemoBuildMachiningProject</code>
Build a <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a>.</li>
<li><code>DemoUseMachiningProject</code>
Load a <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a> and run NC simulation.</li>
<li><code>DemoRenderingMachiningProcessAndStripPosSelection</code>
Apply <a class="xref" href="../../api/Hi.MachiningProcs.MachiningProject.html">MachiningProject</a> to 3D canvas with user-interaction in windows platform.</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="packages-and-samples.html">HiAPI Packages and Sample Code</a> — the NuGet feed and the sample repositories the demos named here live in</li>
<li><a href="basic-geometry.html">Geometry Objects</a> — the geometry types the environment in step 2 is assembled from</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,137 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>API Foundations | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="API Foundations | HiAPI-C# 2025 ">
<link rel="icon" href="../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="">
<h1 id="api-foundations">API Foundations</h1>
<p>What a C# application built on HiAPI needs before anything else runs: where the packages come
from, what a program has to initialise, the geometry objects it passes around, and the two
cross-cutting services — messages and XML serialization — that the rest of the API assumes are
already there.</p>
<p>Ordered the way a new application meets them: getting the packages, writing the first program,
then the pieces every later page takes for granted.</p>
<h2 id="starting-an-application">Starting an Application</h2>
<ul>
<li><a href="packages-and-samples.html">HiAPI Packages and Sample Code</a> — The NuGet feed, the package dependency chain, which package a UI framework needs, and the three sample repositories</li>
<li><a href="getting-started.html">Getting Started with HiAPI</a> — Wiring the feed into a project, initialising and finalising the runtime, and the five steps every HiNC program follows</li>
</ul>
<h2 id="what-every-page-assumes">What Every Page Assumes</h2>
<ul>
<li><a href="basic-geometry.html">Geometry Objects</a> — The STL-backed interface behind every geometry type, and the basic and management geometries built on it</li>
<li><a href="message-management.html">Message Management</a> — Three independent message channels — diagnostic, UI notification, application log — and why they are never mixed</li>
<li><a href="xml-io.html">About XML IO</a> — The serialization pattern every persisted HiAPI type implements, and the registration that must happen before a project is loaded</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="../rendering/index.html">Rendering</a> — putting what these types describe on a screen</li>
<li><a href="../mechanism/index.html">Mechanism</a> — assembling them into a machine that moves</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Message Management | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Message Management | HiAPI-C# 2025 ">
<link rel="icon" href="../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Technique-MessageManagement">
<h1 id="message-management">Message Management</h1>
<p>HiNc applications use three independent message categories. Each category serves a distinct purpose and should not be mixed.</p>
<h2 id="categories">Categories</h2>
<h3 id="1-diagnostic--iprogressimessage">1. Diagnostic — <code>IProgress&lt;IMessage&gt;</code></h3>
<p>Operation-scoped progress and diagnostic messages. The caller provides an <code>IProgress&lt;IMessage&gt;</code> sink to the callee, which reports progress, warnings, and errors through it. Every <a class="xref" href="../../api/Hi.Common.Messages.IMessage.html">IMessage</a> carries a <a class="xref" href="../../api/Hi.Common.Messages.Severity.html">Severity</a>, a <a class="xref" href="../../api/Hi.Common.Messages.Category.html">Category</a>, and a filterable id.</p>
<ul>
<li><strong>Session-scoped</strong>: <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_ShellProgress">ShellProgress</a> feeds the <a class="xref" href="../../anatomy/shell/session-message-panel.html">Session Message Panel</a>; <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_StepDiagnosticProgress">StepDiagnosticProgress</a> retains step-anchored diagnostics and <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_NcDiagnosticProgress">NcDiagnosticProgress</a> retains NC-parsing diagnostics.</li>
<li><strong>XML IO chain</strong>: <a class="xref" href="../../api/Hi.Common.XmlUtils.XFactory.html">XFactory</a> threads <code>IProgress&lt;IMessage&gt;</code> through all deserialization calls so that parsing errors are reported to the caller rather than a global handler.</li>
<li><strong>Script-level</strong>: <a class="xref" href="../../api/Hi.MachiningProcs.SessionShell.html#Hi_MachiningProcs_SessionShell_ShellProgress">ShellProgress</a> exposes the session sink to user scripts.</li>
<li><strong>Per-call</strong>: inject a <a class="xref" href="../../api/Hi.Common.Messages.MessageCollector.html">MessageCollector</a> to buffer one call's messages and read them back afterwards (e.g., to return them inline in an HTTP response).</li>
<li><strong>Project IO</strong>: <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_LoadProject_">LoadProject</a> and <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_ReloadProject_">ReloadProject</a> take a sink of their own, because project IO runs outside any session and none of the session sinks above exists while it runs. A load-time diagnostic — a referenced STL missing on disk, a child XML that will not deserialize — does not fail the load; the project comes up without that geometry and the call returns normally. Passing no sink leaves the application log as the only witness, and the caller sees an unqualified success.</li>
</ul>
<h4 id="reporting-to-a-sink-and-the-log-at-once">Reporting to a sink and the log at once</h4>
<p>An operation a caller may or may not be watching reports to both: always to the service <code>ILogger</code>, and additionally to an injected <code>IProgress&lt;IMessage&gt;</code> when there is one. <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_EnableCollisionDetection_">EnableCollisionDetection</a>, <a class="xref" href="../../api/Hi.MachiningProcs.LocalProjectService.html#Hi_MachiningProcs_LocalProjectService_ResetRuntime_">ResetRuntime</a> and the two project-load entry points share that shape, and the parameter being optional is what lets a host with no caller to answer to — a script, a desktop shell — behave exactly as it did before the sink existed.</p>
<p>The counterpart obligation is that one operation reports one diagnostic once. Where a later stage re-reads what an earlier one has already reported on — the XML round trip that materialises execution equipment re-walks the sources the deserialization pass just read — that stage stays logger-only deliberately, so a caller collecting a project load does not receive every missing file twice.</p>
<h4 id="reporting-helpers-and-the-args-channel">Reporting helpers, and the args channel</h4>
<p>Use the <a class="xref" href="../../api/Hi.Common.Messages.MessageUtil.html">MessageUtil</a> id-first helpers to report typed messages. Each is named <code>{Category}{Severity}</code> — <code>SystemError</code>, <code>SystemWarning</code>, <code>ValidationWarning</code>, <code>ConfigurationWarning</code>, … — takes the structured id first, and is null-safe on the sink.</p>
<p>Every helper has a <code>{Category}{Severity}Fmt</code> sibling that takes a <code>FormattableString</code> in place of the <code>string</code>. The sibling keeps the template and the values interpolated into it on the message itself, as <a class="xref" href="../../api/Hi.Common.Messages.IMessage.html#Hi_Common_Messages_IMessage_GetFormat">GetFormat()</a> and <a class="xref" href="../../api/Hi.Common.Messages.IMessage.html#Hi_Common_Messages_IMessage_GetArgs">GetArgs()</a>, so a consumer holding a translation of that template can re-render the message in another language instead of dropping the numbers. The notification stays the invariant English rendering, so a value carried in it never picks up a decimal separator from a locale. What a client does with the pair, and why the English template is load-bearing rather than descriptive, is under <a class="xref" href="../../anatomy/platform/i18n.html">Internationalization</a>.</p>
<pre><code class="lang-csharp">progress.SystemErrorFmt(&quot;StlFile-Read--Failed&quot;, $&quot;File Reading Failed: {path}&quot;);
</code></pre>
<div class="IMPORTANT">
<h5>Important</h5>
<p><strong>The sibling is opted into by name, and nothing reports its absence.</strong> An interpolated literal handed to the plain helper binds to <code>string</code>, is formatted on the spot, and the template is gone: the call compiles, reads identically at the site, and produces a message no client can translate. Report through <code>Fmt</code> wherever the text interpolates a value. Where it does not, stay on the plain helper — a client swaps a hole-less message by id alone, so giving it a template only adds a way for the equality gate to miss.</p>
</div>
<h3 id="2-ui-error-notification--messageboardutil">2. UI Error Notification — <code>MessageBoardUtil</code></h3>
<p>Toast-style popups for immediate user attention (e.g., &ldquo;File saved&rdquo;, &ldquo;Load failed&rdquo;). <a class="xref" href="../../api/Hi.Common.Messages.MessageBoardUtil.html">MessageBoardUtil</a> triggers the <code>ShowMessageBoard</code> event consumed by the GUI layer.</p>
<div class="NOTE">
<h5>Note</h5>
<p><code>MessageBoardUtil</code> is not yet mature for all scenarios. In practice, <code>ILogger</code> with level-filtered treatment is often applied instead.</p>
</div>
<h3 id="3-app-log--ilogger">3. App Log — <code>ILogger</code></h3>
<p>Standard .NET <code>ILogger</code> for application-level logging. Use <a class="xref" href="../../api/Hi.Common.Messages.ActionProgress-1.html">ActionProgress&lt;T&gt;</a>.<a class="xref" href="../../api/Hi.Common.Messages.ActionProgress-1.html#Hi_Common_Messages_ActionProgress_1_FromLogger_">FromLogger</a> to bridge <code>IProgress&lt;object&gt;</code> APIs to an <code>ILogger</code> instance:</p>
<pre><code class="lang-csharp">IProgress&lt;object&gt; progress = ActionProgress&lt;object&gt;.FromLogger(logger);
</code></pre>
<p>This routes each reported <a class="xref" href="../../api/Hi.Common.Messages.IMessage.html">IMessage</a> (or raw <code>Exception</code>) to the appropriate log level (<code>LogError</code>, <code>LogWarning</code>, <code>LogInformation</code>) based on its severity — with one precedence worth knowing: a message carrying an <code>Exception</code> as its detail goes to <code>LogError</code> with that exception attached whatever severity the message itself declares, so a warning that names an exception is logged as an error.</p>
<p>A null <code>logger</code> is accepted and becomes a no-op sink. A host built without dependency injection has none to hand over, and this bridge is reached from the error-reporting path itself, so a version that threw on a null logger would turn the first reported error into a crash inside the code meant to describe it.</p>
<h2 id="basic-component--utility-level">Basic-Component / Utility Level</h2>
<p>Low-level utilities (e.g., in <code>Hi.Common</code>, <code>Hi.Geom</code>) cannot assume which category the caller intends. These APIs accept <code>Action&lt;Exception&gt;</code> or <code>IProgress&lt;IMessage&gt;</code> as parameters so the caller decides how to handle messages:</p>
<pre><code class="lang-csharp">await task.CatchExceptions(ex =&gt; progress?.Report(ex));
</code></pre>
<h2 id="design-rationale">Design Rationale</h2>
<p>Static/global message sinks mix the three categories, making it unclear whether a message is diagnostic, UI notification, or app log. The current pattern threads the handler explicitly through the call chain so each caller decides the appropriate category.</p>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="xml-io.html">About XML IO</a> — the other cross-cutting service, and the one that threads a progress channel through deserialization</li>
<li><a href="../scripting/shell-progress.html">ShellProgress</a> — the session-scoped face of the diagnostic channel, as a script sees it</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,181 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>HiAPI Packages and Sample Code | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="HiAPI Packages and Sample Code | HiAPI-C# 2025 ">
<link rel="icon" href="../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Technique-PackagesAndSamples">
<h1 id="hiapi-packages-and-sample-code">HiAPI Packages and Sample Code</h1>
<p>HiAPI is a C# software development kit for machining simulation. It provides libraries for NC motion simulation, collision detection, geometry removal simulation, milling force simulation, optimization, and more.</p>
<h2 id="nuget-packages">Nuget Packages</h2>
<p>The HiAPI is applied by the form of Nuget Packages. You have to apply <code>HiNc</code> nuget package and its dependencies. They include all the functionality of the HiNC software, but do not include the GUI components.</p>
<p>The packages can be downloaded and installed from the HiAPI NuGet Server. The server URL is:</p>
<p><a href="https://superhightech-gitea.webredirect.org/api/packages/HiAPI/nuget/index.json">https://superhightech-gitea.webredirect.org/api/packages/HiAPI/nuget/index.json</a></p>
<div class="NOTE">
<h5>Note</h5>
<ul>
<li>Authentication is required to access the server. Register the feed and the account together
with the single <code>dotnet nuget add source</code> command in
<a href="getting-started.html#installation">Getting Started</a> — the feed rejects anonymous requests, so a
source declared without credentials gets a restore no further.</li>
<li>Direct browser access to the URL will not show meaningful content. Since the server is designed for Visual Studio NuGet package management. For more information about NuGet, visit <a href="https://www.nuget.org/">NuGet.org</a></li>
</ul>
</div>
<h3 id="package-dependencies">Package Dependencies</h3>
<p>The <code>HiNc</code> package has the following dependency chain:</p>
<pre><code class="lang-mermaid">graph LR
HiGeom --&gt; HiDisp
HiDisp --&gt; HiCbtr
HiCbtr --&gt; HiMech
HiMech --&gt; HiUniNc
HiUniNc --&gt; HiNc
HiDisp --&gt; Hi.WinForm
HiDisp --&gt; Hi.WpfPlus
style HiNc fill:#d3d,stroke:#333,stroke-width:2px
</code></pre>
<h3 id="ui-framework-support">UI Framework Support</h3>
<p>If you need to develop Windows desktop applications:</p>
<ul>
<li>For Windows Forms applications, use the <code>Hi.WinForm</code> package.</li>
<li>For WPF applications, use the <code>Hi.WpfPlus</code> package.</li>
</ul>
<div class="NOTE">
<h5>Note</h5>
<p>See <a class="xref" href="../rendering/custom-rendering-canvas.html">Building Your Own Rendering Canvas</a> to build the rendering canvas cross-platform.</p>
</div>
<h2 id="hiapi-sample-code">HiAPI Sample Code</h2>
<p>Download the sample repositories below to get the samples. They demonstrate various aspects of using HiAPI for machining simulation:</p>
<ul>
<li>HiNC-2025-webservice
<ul>
<li><a href="https://superhightech-gitea.webredirect.org/HiAPI/HiNC-2025-webservice.git">https://superhightech-gitea.webredirect.org/HiAPI/HiNC-2025-webservice.git</a></li>
<li>The source of the shipped HiNC application itself — a Quasar SPA served by ASP.NET Core. It is the production-scale example: every screen you see in the product is built from the public API documented here, and each component is dissected in <a class="xref" href="../../anatomy/index.html">HiNC App Anatomy</a>.</li>
</ul>
</li>
<li>Hi.Sample
<ul>
<li><a href="https://superhightech-gitea.webredirect.org/HiNC-Deploy/Hi.Sample.git">https://superhightech-gitea.webredirect.org/HiNC-Deploy/Hi.Sample.git</a></li>
<li>The repository generally contains the sample codes without using rendering canvas.</li>
</ul>
</li>
<li>Hi.Sample.Wpf
<ul>
<li><a href="https://superhightech-gitea.webredirect.org/HiNC-Deploy/Hi.Sample.Wpf.git">https://superhightech-gitea.webredirect.org/HiNC-Deploy/Hi.Sample.Wpf.git</a></li>
<li>The repository generally contains the sample code that requires rendering canvas.</li>
</ul>
</li>
</ul>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="getting-started.html">Getting Started with HiAPI</a> — wiring this feed into a project and writing the first program against it</li>
<li><a href="../rendering/index.html">Rendering</a> — what the Hi.WinForm and Hi.WpfPlus packages above are for</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,37 @@
<div id="sidetoggle">
<div>
<div class="sidefilter">
<form class="toc-filter">
<span class="glyphicon glyphicon-filter filter-icon"></span>
<span class="glyphicon glyphicon-remove clear-icon" id="toc_filter_clear"></span>
<input type="text" id="toc_filter_input" placeholder="Filter by title" onkeypress="if(event.keyCode==13) {return false;}">
</form>
</div>
<div class="sidetoc">
<div class="toc" id="toc">
<ul class="nav level1">
<li>
<a href="index.html" name="" title="Overview">Overview</a>
</li>
<li>
<a href="packages-and-samples.html" name="" title="HiAPI Packages and Sample Code">HiAPI Packages and Sample Code</a>
</li>
<li>
<a href="getting-started.html" name="" title="Getting Started">Getting Started</a>
</li>
<li>
<a href="basic-geometry.html" name="" title="Geometry Objects">Geometry Objects</a>
</li>
<li>
<a href="message-management.html" name="" title="Message Management">Message Management</a>
</li>
<li>
<a href="xml-io.html" name="" title="XML IO">XML IO</a>
</li>
</ul>
</div>
</div>
</div>
</div>
@@ -0,0 +1,2 @@
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"HiAPI Packages and Sample Code","href":"packages-and-samples.html","topicHref":"packages-and-samples.html"},{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"Geometry Objects","href":"basic-geometry.html","topicHref":"basic-geometry.html"},{"name":"Message Management","href":"message-management.html","topicHref":"message-management.html"},{"name":"XML IO","href":"xml-io.html","topicHref":"xml-io.html"}]}
@@ -0,0 +1,393 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>About XML IO | HiAPI-C# 2025 </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="About XML IO | HiAPI-C# 2025 ">
<link rel="icon" href="../../img/HiAPI.favicon.ico">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../../">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../img/HiAPI.logo.png" alt="">
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="Technique-XmlIo">
<h1 id="about-xml-io">About XML IO</h1>
<p>The XML IO design pattern in HiNc Framework is based on <a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html">IMakeXmlSource</a> interface and <a class="xref" href="../../api/Hi.Common.XmlUtils.XFactory.html">XFactory</a> class. This pattern provides a standardized way to serialize and deserialize objects to and from XML format.</p>
<p>Don't serialize the runtime member object like <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.func-1">Func&lt;TResult&gt;</a> or <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.action">Action</a> either cache object. The runtime objects can be optionally sent by the <code>res</code> part on the XFactory Registration or set by the other host or dependent object. If it is set by the other object, then there is nothing can do to it in the XML IO procedure.</p>
<h2 id="core-components">Core Components</h2>
<h3 id="imakexmlsource-interface">IMakeXmlSource Interface</h3>
<p>The <a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html">IMakeXmlSource</a> interface defines the contract for objects that can be serialized to XML format. It contains a single method <code>MakeXmlSource</code>.</p>
<h3 id="xfactory">XFactory</h3>
<p><a class="xref" href="../../api/Hi.Common.XmlUtils.XFactory.html">XFactory</a> is an instance class with a process-wide <code>Default</code> singleton (<code>XFactory.Default</code>). The instance form exists for test isolation and parallel pipelines that need disjoint generator registries; the static <code>Gen&lt;T&gt;</code> / <code>GenByChild&lt;T&gt;</code> / <code>GenByFile&lt;T&gt;</code> entry points always read from <code>Default</code>.</p>
<p>Each instance owns its own <code>Generators</code> dictionary (XML element name → generator delegate). Types add themselves via a <code>Reg(factory)</code> call (see below).</p>
<h3 id="explicit-registration-via-regxfactory-factory--null">Explicit Registration via <code>Reg(XFactory factory = null)</code></h3>
<p>Every class implementing IMakeXmlSource exposes a public static <code>Reg</code> method:</p>
<pre><code class="lang-csharp">public static void Reg(XFactory factory = null)
{
factory ??= XFactory.Default;
factory.Generators.TryAdd(XName, (xml, baseDirectory, relFile, progress, res)
=&gt; new MyClass(xml, baseDirectory, relFile, progress));
}
</code></pre>
<p>Key properties:</p>
<ul>
<li><strong>Explicit.</strong> Callers see registration happen — no hidden side effect from accessing a static member or constructing a type.</li>
<li><strong>Idempotent.</strong> Uses <code>TryAdd</code>, so the same <code>Reg</code> may be invoked any number of times from any number of boot paths.</li>
<li><strong>Composable.</strong> Custom factory instances are supported via the optional <code>factory</code> parameter; default usage (<code>MyClass.Reg();</code>) populates <code>XFactory.Default</code>.</li>
</ul>
<p>For example, see <a class="xref" href="../../api/Hi.Milling.Apts.BallApt.html">BallApt</a>:</p>
<pre><code class="lang-csharp" name="XmlRegistration">/// &lt;summary&gt;
/// Registers this type's deserializer with the given &lt;see cref=&quot;XFactory&quot;/&gt;
/// (or &lt;see cref=&quot;XFactory.Default&quot;/&gt; when &lt;paramref name=&quot;factory&quot;/&gt; is
/// &lt;c&gt;null&lt;/c&gt;). Idempotent.
/// &lt;/summary&gt;
public static void Reg(XFactory factory = null)
{
factory ??= XFactory.Default;
factory.Generators.TryAdd(XName, (xml,baseDirectory, relFile, progress, res) =&gt; new BallApt(xml));
}
</code></pre><h3 id="composite-types-chain-regfactory-on-dependents">Composite types chain <code>Reg(factory)</code> on dependents</h3>
<p>When a class deserializes child elements via <code>XFactory.Gen&lt;T&gt;</code> / <code>XFactory.GenByChild&lt;T&gt;</code>, its <code>Reg(factory)</code> must chain <code>Reg(factory)</code> on each concrete child type so the whole dependency graph is reachable from a single root call:</p>
<pre><code class="lang-csharp">public static void Reg(XFactory factory = null)
{
factory ??= XFactory.Default;
DependentA.Reg(factory);
DependentB.Reg(factory);
factory.Generators.TryAdd(XName, (xml, baseDirectory, relFile, progress, res)
=&gt; new MyComposite(xml, baseDirectory, relFile, progress));
}
</code></pre>
<p>For polymorphic deserialization (<code>GenByChild&lt;IInterface&gt;</code>), the composite must chain every concrete implementation that may appear in the XML. The largest composite, <a class="xref" href="../../api/Hi.NcParsers.SoftNcRunner.html">SoftNcRunner</a>, chains roughly 130 dependents (every dependency, initializer, segmenter, syntax, and semantic the NC pipeline may deserialize).</p>
<h3 id="multi-name-registration-legacy-aliases">Multi-name registration (legacy aliases)</h3>
<p>When the XML payload may carry an old element name for backward compatibility, register the current <code>XName</code> first and group legacy aliases under a <code>//legacy aliases</code> comment:</p>
<pre><code class="lang-csharp">public static void Reg(XFactory factory = null)
{
factory ??= XFactory.Default;
XFactory.XGeneratorDelegate gen = (xml, baseDirectory, relFile, progress, res)
=&gt; new MachiningProject(xml, baseDirectory, progress);
factory.Generators.TryAdd(XName, gen);
//legacy aliases
factory.Generators.TryAdd(&quot;MachiningCourse&quot;, gen);
factory.Generators.TryAdd(&quot;MillingCourse&quot;, gen);
}
</code></pre>
<h3 id="iprogress-threading">IProgress Threading</h3>
<p>The <code>IProgress&lt;IMessage&gt;</code> parameter is threaded through the entire deserialization chain. When a class constructor calls <a class="xref" href="../../api/Hi.Common.XmlUtils.XFactory.html">XFactory</a> to deserialize child objects, it passes the same <code>progress</code> instance:</p>
<pre><code class="lang-csharp">public MyClass(XElement src, string baseDirectory, string relFile,
IProgress&lt;IMessage&gt; progress)
{
Child = XFactory.GenByChild&lt;IChild&gt;(
src.Element(nameof(Child)), subBaseDirectory, progress);
}
</code></pre>
<p>Parsing errors are reported to the caller-provided <code>IProgress&lt;IMessage&gt;</code> handler.</p>
<h3 id="what-a-failing-child-does">What a failing child does</h3>
<p><code>XFactory</code> does not swallow failures: a generator that throws propagates, and the load fails with it. Tolerance is opted into per type, and is visible at the place that chose it.</p>
<ul>
<li>A type that owns an external file catches its own read failure and reports it, then comes up without that content. <a class="xref" href="../../api/Hi.Geom.StlFile.html">StlFile</a> reports the <strong>resolved</strong> path rather than the relative <code>SourceFile</code>, because the base directory is gone by the time the message is read anywhere else — a load response, a message panel — and the folder is what says which machine or part file is missing.</li>
<li><a class="xref" href="../../api/Hi.Common.XmlUtils.XFactory.html#Hi_Common_XmlUtils_XFactory_GenListSkippingUnloadable_">GenListSkippingUnloadable</a> drops the list entries whose element name is unregistered or whose generator throws, reporting each as a warning. It is for lists whose schema drifts while a feature is in development — the NC pipeline's dependency, initializer and syntax lists — where a partially loadable list beats aborting the whole load.</li>
</ul>
<h2 id="writing">Writing</h2>
<p><a class="xref" href="../../api/Hi.Common.XmlUtils.IMakeXmlSource.html#Hi_Common_XmlUtils_IMakeXmlSource_MakeXmlSource_">MakeXmlSource</a> produces the element; the file layer around it is <a class="xref" href="../../api/Hi.Common.XmlUtils.XmlUtil.html#Hi_Common_XmlUtils_XmlUtil_MakeXmlSourceToFileRef_">MakeXmlSourceToFileRef</a>, which either hands that element back inline — when no relative file is named for it — or writes it to a file of its own and returns a file-reference element in its place. That is what makes a project file a document of references instead of one large document.</p>
<h3 id="children-first-parent-last">Children first, parent last</h3>
<p><code>MakeXmlSourceToFileRef</code> prepares only the directory up front. The children's own side files — nested XML, STL copies — are written from inside <code>MakeXmlSource</code>, and the parent file itself is written by <a class="xref" href="../../api/Hi.Common.XmlUtils.XmlUtil.html#Hi_Common_XmlUtils_XmlUtil_SaveToFileRef_">SaveToFileRef</a> only once every child has succeeded. A child that fails — a locked or read-only side file, a full disk, a serialization bug — therefore leaves the previous version of the parent intact, rather than an empty file that points nowhere.</p>
<p>An <strong>existing</strong> parent is probed for write access before the children are touched, by opening it without truncating. A read-only or locked parent fails there, instead of leaving a folder of freshly written children beside an unchanged old parent.</p>
<h3 id="copy-on-save-and-the-file-that-must-stay-missing">Copy-on-save, and the file that must stay missing</h3>
<p><a class="xref" href="../../api/Hi.Geom.StlFile.html">StlFile</a> serializes as its path and copies its mesh beside the new document, but only when nothing is at that target path already — the mechanism that lets one project be written under several base directories without rewriting meshes that are there. <a class="xref" href="../../api/Hi.Geom.StlFile.html#Hi_Geom_StlFile_SaveStlToFile_">SaveStlToFile</a> owns the directory creation, from the resolved path, and stays away from the file system entirely when <a class="xref" href="../../api/Hi.Geom.StlFile.html#Hi_Geom_StlFile_CacheStl">CacheStl</a> is null.</p>
<p>That last condition is the contract, not a guard. An STL whose source was missing when the project was read has no cached mesh and must stay missing: a zero-length file in its place reads back as an opaque loading failure instead of an exception naming the path, and it is a new untracked file in someone's project folder.</p>
<div class="IMPORTANT">
<h5>Important</h5>
<p><strong><code>exhibitionOnly</code> suppresses the XML writes; it does not reach the copy.</strong> <code>MakeXmlSourceToFileRef</code> and <code>SaveToFileRef</code> both honour it and produce the reference elements without creating anything, but <code>StlFile</code>'s copy-on-save does not consult it at all. So a purely in-memory round trip still copies cached meshes into a base directory that lacks them — which is what a project load does when it materialises the runtime equipment from the authored one. Writing is not confined to saving.</p>
</div>
<h2 id="boot-path">Boot path</h2>
<p>An application's entry point (web service <code>Program.cs</code>, WPF <code>App.xaml.cs</code>, test fixture, etc.) must call the appropriate top-level <code>Reg()</code> once at startup, before any project XML is deserialized. For the simulation pipeline this is:</p>
<pre><code class="lang-csharp">LocalProjectService.Reg();
</code></pre>
<p><code>LocalProjectService.Reg()</code> chains <code>MachiningProject.Reg()</code>, which in turn chains every type the simulation pipeline may deserialize. After this single call returns, <code>XFactory.Default.Generators</code> carries the full deserialization graph.</p>
<h2 id="implementation-patterns">Implementation Patterns</h2>
<h3 id="simple-value-objects">Simple Value Objects</h3>
<p>See <a class="xref" href="../../api/Hi.Milling.Apts.BallApt.html">BallApt</a> implementation:</p>
<pre><code class="lang-csharp" name="XmlImplementation">/// &lt;summary&gt;
/// Name for XML IO.
/// &lt;/summary&gt;
public static string XName =&gt; nameof(BallApt);
/// &lt;summary&gt;
/// Ctor.
/// &lt;/summary&gt;
/// &lt;param name=&quot;src&quot;&gt;XML&lt;/param&gt;
public BallApt(XElement src)
{
Diameter_mm = double.Parse(src.Element(&quot;D&quot;).Value);
FluteHeight_mm = double.Parse(src.Element(&quot;FluteH&quot;).Value);
}
/// &lt;inheritdoc/&gt;
public XElement MakeXmlSource(string baseDirectory, string relFile, bool exhibitionOnly) =&gt; ToXElement();
/// &lt;inheritdoc/&gt;
public XElement ToXElement()
{
return new XElement(XName,
new XElement(&quot;D&quot;, Diameter_mm),
new XElement(&quot;FluteH&quot;, FluteHeight_mm)
);
}
</code></pre><h3 id="complex-data-structures">Complex Data Structures</h3>
<p>See <a class="xref" href="../../api/Hi.Milling.SpindleCapability.html">SpindleCapability</a> implementation:</p>
<pre><code class="lang-csharp" name="XmlImplementation">/// &lt;summary&gt;
/// Name for XML IO.
/// &lt;/summary&gt;
public static string XName =&gt; nameof(SpindleCapability);
/// &lt;summary&gt;
/// Initializes a new instance of the &lt;see cref=&quot;SpindleCapability&quot;/&gt; class.
/// &lt;/summary&gt;
/// &lt;param name=&quot;src&quot;&gt;The XML element containing spindle data.&lt;/param&gt;
/// &lt;param name=&quot;baseDirectory&quot;&gt;The base directory for resolving relative paths.&lt;/param&gt;
/// &lt;param name=&quot;res&quot;&gt;Additional resolution parameters.&lt;/param&gt;
public SpindleCapability(XElement src, string baseDirectory, params object[] res)
{
this.SetNameNote(src);
if (src.Element(nameof(EnergyEfficiency)) != null)
EnergyEfficiency = XmlConvert.ToDouble(
src.Element(nameof(EnergyEfficiency)).Value);
src.Element(nameof(WorkingTemperatureUpperBoundary_C))?.SelfInvoke(
e =&gt; WorkingTemperatureUpperBoundary_C = XmlConvert.ToDouble(e.Value));
src.Element(nameof(GearShiftSpindleSpeed_rpm))?.Value?.SelfInvoke(
s =&gt; GearShiftSpindleSpeed_rpm = string.IsNullOrEmpty(s)
? null : XmlConvert.ToDouble(s));
if (src.Element(nameof(DryRunFrictionPowerCoefficient_mWdrpm)) != null)
DryRunFrictionPowerCoefficient_mWdrpm = XmlConvert.ToDouble(
src.Element(nameof(DryRunFrictionPowerCoefficient_mWdrpm)).Value);
if (src.Element(nameof(DryRunWindagePowerCoefficient_pWdrpm3)) != null)
DryRunWindagePowerCoefficient_pWdrpm3 = XmlConvert.ToDouble(
src.Element(nameof(DryRunWindagePowerCoefficient_pWdrpm3)).Value);
if (src.Element(&quot;SpindleSpeedToPowerContours&quot;) != null) //for legacy
WorkableDurationToSpindleSpeedPowerContoursDictionary_min_cycleDs_kW =
src.Element(&quot;SpindleSpeedToPowerContours&quot;).Elements(&quot;Contour&quot;)
.ToDictionary(
contourElem =&gt;
{
double r = XmlConvert.ToDouble(contourElem.Attribute(&quot;InsistentRatio&quot;)?.Value);
//600s=10mins
return r == 1 ? double.PositiveInfinity : (r * 600);
},
contourElem =&gt; contourElem.Elements(&quot;SpindleSpeedToPower&quot;).Select(
elem =&gt; new Vec2d(
XmlConvert.ToDouble(elem.Element(&quot;SpindleSpeed-RPM&quot;).Value) / 60,
XmlConvert.ToDouble(elem.Element(&quot;Power-kW&quot;).Value)))
.ToList());
src.Element(&quot;WorkableDurationToSpindleSpeedPowerContoursDictionary&quot;)
?.SelfInvoke(dicElem =&gt;
{
WorkableDurationToSpindleSpeedPowerContoursDictionary_min_cycleDs_kW
= dicElem.Elements(&quot;Contour&quot;)
.ToDictionary(
contourElem =&gt; XmlConvert.ToDouble(
contourElem.Attribute(&quot;WorkableDuration-min&quot;)?.Value),
contourElem =&gt; contourElem.Elements(&quot;SpindleSpeedToPower&quot;).Select(
elem =&gt; new Vec2d(
XmlConvert.ToDouble(elem.Element(&quot;SpindleSpeed-RPM&quot;).Value) / 60,
XmlConvert.ToDouble(elem.Element(&quot;Power-kW&quot;).Value)))
.ToList());
});
if (src.Element(&quot;SpindleSpeedToTorqueContours&quot;) != null) //for legacy
WorkableDurationToSpindleSpeedTorqueContoursDictionary_min_cycleDs_Nm =
src.Element(&quot;SpindleSpeedToTorqueContours&quot;).Elements(&quot;Contour&quot;)
.ToDictionary(
contourElem =&gt;
{
double r = XmlConvert.ToDouble(contourElem.Attribute(&quot;InsistentRatio&quot;)?.Value);
//600s=10mins
return r == 1 ? double.PositiveInfinity : (r * 600);
},
contourElem =&gt; contourElem.Elements(&quot;SpindleSpeedToTorque&quot;).Select(
elem =&gt; new Vec2d(
XmlConvert.ToDouble(elem.Element(&quot;SpindleSpeed-RPM&quot;).Value) / 60,
XmlConvert.ToDouble(elem.Element(&quot;Torque-Nm&quot;).Value)))
.ToList());
src.Element(&quot;WorkableDurationToSpindleSpeedTorqueContoursDictionary&quot;)
?.SelfInvoke(dicElem =&gt;
{
//MessageUtil.WriteLine($&quot;dicElem: {dicElem}&quot;);
WorkableDurationToSpindleSpeedTorqueContoursDictionary_min_cycleDs_Nm =
dicElem.Elements(&quot;Contour&quot;).ToDictionary(
contourElem =&gt; XmlConvert.ToDouble(
contourElem.Attribute(&quot;WorkableDuration-min&quot;)?.Value),
contourElem =&gt; contourElem.Elements(&quot;SpindleSpeedToTorque&quot;).Select(
elem =&gt; new Vec2d(
XmlConvert.ToDouble(elem.Element(&quot;SpindleSpeed-RPM&quot;).Value) / 60,
XmlConvert.ToDouble(elem.Element(&quot;Torque-Nm&quot;).Value)))
.ToList());
//MessageUtil.WriteLine($&quot;keys: {string.Join(',',WorkableDurationToSpindleSpeedTorqueContoursDictionary_min_cycleDs_Nm.Select(e=&gt;e.Key))}&quot;);
});
//for legacy compatible.
if (src.Element(&quot;SpindleSpeedToPower--RPM-to-kW&quot;) != null)
InfInsistentSpindleSpeedToPower_cycleDs_kW =
src.Element(&quot;SpindleSpeedToPower--RPM-to-kW&quot;).Elements()
.Select(elem =&gt; new Vec2d(XmlConvert.ToDouble(elem.Attribute(
&quot;SpindleSpeed-RPM&quot;).Value) / 60,
XmlConvert.ToDouble(elem.Value))).ToList();
//for legacy compatible.
if (src.Element(&quot;SpindleSpeedToTorque--RPM-to-Nm&quot;) != null)
InfInsistentSpindleSpeedToTorque_cycleDs_Nm =
src.Element(&quot;SpindleSpeedToTorque--RPM-to-Nm&quot;).Elements()
.Select(elem =&gt; new Vec2d(XmlConvert.ToDouble(elem.Attribute(
&quot;SpindleSpeed-RPM&quot;).Value) / 60,
XmlConvert.ToDouble(elem.Value))).ToList();
}
/// &lt;inheritdoc/&gt;
public XElement MakeXmlSource(string baseDirectory, string relFile, bool exhibitionOnly)
{
return new XElement(XName,
this.GetNameNoteXElementList(),
new XElement(nameof(EnergyEfficiency), EnergyEfficiency),
new XElement(nameof(GearShiftSpindleSpeed_rpm), GearShiftSpindleSpeed_rpm),
new XElement(nameof(DryRunFrictionPowerCoefficient_mWdrpm),
DryRunFrictionPowerCoefficient_mWdrpm),
new XElement(nameof(DryRunWindagePowerCoefficient_pWdrpm3),
DryRunWindagePowerCoefficient_pWdrpm3),
new XElement(&quot;WorkableDurationToSpindleSpeedPowerContoursDictionary&quot;,
WorkableDurationToSpindleSpeedPowerContoursDictionary_min_cycleDs_kW.OrderBy(entry =&gt; entry.Key)
.Select(entry =&gt; new XElement(&quot;Contour&quot;,
new XAttribute(&quot;WorkableDuration-min&quot;, entry.Key),
entry.Value.Select(entry
=&gt; new XElement(&quot;SpindleSpeedToPower&quot;,
new XElement(&quot;SpindleSpeed-RPM&quot;, entry.X * 60),
new XElement(&quot;Power-kW&quot;, entry.Y)))))
),
new XElement(&quot;WorkableDurationToSpindleSpeedTorqueContoursDictionary&quot;,
WorkableDurationToSpindleSpeedTorqueContoursDictionary_min_cycleDs_Nm.OrderBy(entry =&gt; entry.Key)
.Select(entry =&gt; new XElement(&quot;Contour&quot;,
new XAttribute(&quot;WorkableDuration-min&quot;, entry.Key),
entry.Value.Select(entry
=&gt; new XElement(&quot;SpindleSpeedToTorque&quot;,
new XElement(&quot;SpindleSpeed-RPM&quot;, entry.X * 60),
new XElement(&quot;Torque-Nm&quot;, entry.Y)))))
)
);
}
</code></pre><h2 id="best-practices">Best Practices</h2>
<ol>
<li><strong>XName</strong>: Always define static <code>XName</code> property matching the class name.</li>
<li><strong>Registration</strong>: Expose <code>public static void Reg(XFactory factory = null)</code>; first line is <code>factory ??= XFactory.Default;</code> then <code>factory.Generators.TryAdd(XName, …)</code>.</li>
<li><strong>Chain dependents</strong>: For every concrete type T that the ctor reads via <code>XFactory.Gen&lt;T&gt;</code> / <code>XFactory.GenByChild&lt;T&gt;</code>, add <code>T.Reg(factory);</code> to the chain. For polymorphic <code>GenByChild&lt;IInterface&gt;</code>, chain every implementation that the XML may carry.</li>
<li><strong>Idempotent</strong>: Use <code>TryAdd</code>, never <code>Add</code>. The same <code>Reg</code> is called from many boot paths.</li>
<li><strong>Progress Threading</strong>: Pass the <code>IProgress&lt;IMessage&gt;</code> parameter through all nested <code>XFactory</code> calls. See <a href="message-management.html">Message Management</a> for the rationale.</li>
<li><strong>Legacy Support</strong>: Register the canonical <code>XName</code> first, then group aliases under a <code>//legacy aliases</code> comment.</li>
<li><strong>Derived class registration</strong>: When a derived class needs its own <code>Reg</code>, mark it <code>public new static void Reg(XFactory factory = null)</code> so the C# compiler does not warn about hiding the base method.</li>
<li><strong>Side files from inside <code>MakeXmlSource</code>, never ahead of it</strong>: an implementation that owns an external file writes it from within <code>MakeXmlSource</code>, which is what keeps the framework's children-first ordering true. It must not create a file for content it does not hold — a source that was missing at load time stays missing, because an empty file is harder to diagnose than an absent one.</li>
</ol>
<h2 id="see-also">See Also</h2>
<ul>
<li><a href="message-management.html">Message Management</a> — the diagnostic channel threaded through deserialization</li>
<li><a href="basic-geometry.html">Geometry Objects</a> — the types most often persisted through this pattern</li>
<li><a href="../rendering/color-guide.html">Color Guide System</a> — a project-registered implementation serialized this way</li>
</ul>
</article>
<div class="contribution d-print-none">
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<span> Copyright © 2025 <a href='https://superhightech.com.tw'>Tech Coordinate</a>. All rights reserved. <a href='https://superhightech.com.tw'>超級高科技股份有限公司</a> © 2025 版權所有 </span>
</div>
</div>
</footer>
</body>
</html>