Class WorkpieceService
- Namespace
- Hi.NcMech.Workpieces
- Assembly
- HiMech.dll
Runtime service for Workpiece.
public class WorkpieceService : IDisplayee, IExpandToBox3d, IDisposable, IGetAnchoredDisplayeeList, IAnchoredCollidableLeaf, IAnchoredCollidableNode, IAnchoredCollidableBased, ICollidable
- Inheritance
-
WorkpieceService
- Implements
- Inherited Members
- Extension Methods
Remarks
WorkpieceService handles meshed geometry, caching, diff calculation, defect scanning, display and collision — state that does not require configuration IO. Compare to Workpiece, which holds the persistent/serializable configuration.
Constructors
WorkpieceService(Func<Workpiece>, Func<string>)
Ctor.
public WorkpieceService(Func<Workpiece> workpieceGetter, Func<string> baseDirectoryGetter = null)
Parameters
Properties
BaseDirectoryGetter
Provides the base directory that relative file paths in this service resolve against (injected by the owning project service); when null, paths are used as-is.
public Func<string> BaseDirectoryGetter { get; }
Property Value
BottomResolution
Resolution.
public double BottomResolution { get; }
Property Value
BuiltMeshedGeom
The meshed geometry when it is built, null until then: a read that never builds (the lock-free
reference read of IsMeshedGeomInit, handing the tree back), for a reader on a hot
path that must not voxelize the stock – the step pipeline's licence clamp notice
(MachiningActRunner.ReportMachiningResolutionClampedByLicense) reads the tree's
ReferenceSize_mm through it. GetOrBuildMeshedGeom(CancellationToken, IProgress<IMessage>) builds.
public CubeTree BuiltMeshedGeom { get; }
Property Value
CollidableName
Gets the name of the collidable object.
public string CollidableName { get; }
Property Value
ConstructionDefectDisplayee
Construction defect displayee.
public ConstructionDefectDisplayee ConstructionDefectDisplayee { get; }
Property Value
DetectionRadius_mm
Detection radius in millimeters the current diff overlay was built with — written by Diff(double, CancellationToken, IProgress<IMessage>) once the overlay exists, never by display callers. Meaningless while HasDiffOverlay is false (the initial value is a placeholder, not a run). It does not bound DiffVisualRadius_mm: the visual radius is the project's colour criterion, and above the detection radius the scale simply never saturates.
public double DetectionRadius_mm { get; set; }
Property Value
DiffAttachmentBag
transient object. For Internal Use.
public ConcurrentBag<DiffAttachment> DiffAttachmentBag { get; }
Property Value
DiffRangeColorRule
Internal used.
public RangeColorRule DiffRangeColorRule { get; set; }
Property Value
DiffVisualRadius_mm
Visual radius for difference visualization: the colour-scale ceiling of the diff overlay, applied live — recolours the attached overlay, never recomputes it. This is the LIVE rule; the project-level value is DiffVisualRadius_mm and the host mirrors the two (LocalProjectService). Finite and positive: zero collapses floor onto ceiling, and NaN would slip past the equality early-out below and poison every colour.
public double DiffVisualRadius_mm { get; set; }
Property Value
HasDiffOverlay
Whether a computed diff overlay is attached to the live meshed tree right now — a Diff(double, CancellationToken, IProgress<IMessage>) ran, had something to compare, and nothing has retired it since (reset, a swapped tree). Not “there are deviations”: a zero-deviation comparison attaches too. Not “a diff was requested”: a skipped one attaches nothing.
public bool HasDiffOverlay { get; }
Property Value
IdealGeom
Delegate property for IdealGeom with cache cleanup.
public IGetStl IdealGeom { get; set; }
Property Value
IdealSolid
Gets the drawing representing the ideal geometry faces of the workpiece. The derived solid from IdealGeom.
public Solid IdealSolid { get; }
Property Value
InitGeom
Delegate property for InitGeom with runtime cleanup.
public IMakeXmlSource InitGeom { get; set; }
Property Value
InitSolid
The derived solid from InitGeom.
public Solid InitSolid { get; }
Property Value
IsMeshedGeomInit
Indicates whether the meshed geometry is initialized.
public bool IsMeshedGeomInit { get; }
Property Value
Workpiece
The underlying workpiece data model.
public Workpiece Workpiece { get; }
Property Value
WorkpieceGetter
public Func<Workpiece> WorkpieceGetter { get; }
Property Value
Methods
ClearCache()
Drops the raw / ideal solid and defect display caches so the next access rebuilds from the current Workpiece.
public void ClearCache()
ClearDefectDisplayee()
Clears all defect displayees.
public void ClearDefectDisplayee()
ClearIdealGeomCache()
Clears the ideal geometry cache.
public void ClearIdealGeomCache()
ClearRawGeomCache()
Clears the raw geometry cache.
public void ClearRawGeomCache()
Diff(double, CancellationToken, IProgress<IMessage>)
Calculates the difference between ideal and actual geometry and attaches it to the live meshed tree as the diff overlay (HasDiffOverlay).
public bool Diff(double detectionRadius, CancellationToken token, IProgress<IMessage> messageProgress = null)
Parameters
detectionRadiusdoubleDetection radius; saved to DetectionRadius_mm once the overlay is built.
tokenCancellationTokenCancellation token: cancels the meshed-geometry build and stops the compare itself within a node per worker (the player's Stop or Reset, a project close).
messageProgressIProgress<IMessage>Progress reporting interface.
Returns
- bool
True when an overlay was built. False when there was nothing to compare — no ideal (target) geometry or no meshed geometry, each reported as a warning so a skipped comparison is never read as a clean one — when the compare attached nothing (a disposed tree or a missing licence, reported as
Diff–NoResult), when the build was cancelled, when a reset retired the tree before the compare began or while it ran, or when the compare was stopped (Diff–Stopped): what it had compared then stays attached as the overlay, and the leaves it never reached keep the colouring they had – white and picking nothing where only the base was, an earlier step's colour where a play cut them – until the next reset, or until a play gives the tree its base back before it cuts (RestorePlainBaseAfterStoppedDiff(IProgress<IMessage>)).
Display(Bind)
Display function called in DispEngine rendering loop.
public void Display(Bind bind)
Parameters
bindBindBind with DispEngine. See Bind.
Dispose()
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
public void Dispose()
Dispose(bool)
protected virtual void Dispose(bool disposing)
Parameters
disposingbool
ExpandToBox3d(ref box3d_t)
Expands the destination box.
This function is usually used to compute the bounding box of elements.
box3d_t is a value type, so the destination is passed by reference
(the C++ expand_to_box3d(box3&) shape); an implementation writes
dst = dst.Expanded(...) or forwards ref dst to its parts.
public void ExpandToBox3d(ref box3d_t dst)
Parameters
dstbox3d_tDestination box, expanded in place
GetAnchoredCollidableNode()
Gets the anchored collidable node associated with this object.
public IAnchoredCollidableNode GetAnchoredCollidableNode()
Returns
- IAnchoredCollidableNode
The anchored collidable node.
GetAnchoredDisplayeeList()
Gets a list of anchored displayable objects.
public List<IAnchoredDisplayee> GetAnchoredDisplayeeList()
Returns
- List<IAnchoredDisplayee>
A list of IAnchoredDisplayee objects
GetCollidableAnchor()
Gets the anchor associated with this collidable leaf.
public Anchor GetCollidableAnchor()
Returns
- Anchor
The anchor for this collidable leaf.
GetCollidee()
Get ICollidee.
public ICollidee GetCollidee()
Returns
GetOrBuildMeshedGeom(CancellationToken, IProgress<IMessage>)
Returns the current meshed geometry, lazily building it from the workpiece's InitGeom (voxelize via NewWithDefectInfos(Stl, double, CancellationToken, IProgress<IMessage>, Action<DefectNodeInfo>), or load a CubeTreeFile) when not yet present. The first build can be slow — hence the cancellation token + progress sinks; once built, the tree is returned cheaply.
public CubeTree GetOrBuildMeshedGeom(CancellationToken token, IProgress<IMessage> messageProgress = null)
Parameters
tokenCancellationTokenCancels an in-progress build (leaves the geometry unbuilt / null).
messageProgressIProgress<IMessage>IMessage-channel sink (null = silent).
Returns
- CubeTree
The meshed cube tree; null when there is no workpiece / InitGeom, or the build was cancelled.
GetReferenceSize_mm(CubeTree, out bool)
GetReferenceSize_mm(out bool) over a tree the caller read – one read of BuiltMeshedGeom serves a reply that also reports the tree's cube width, where two reads could pair two trees across a swap: the tree's own reference when the tree stands for the geometry of the moment (MeshedGeomIsOf(IMakeXmlSource), whatever its kind: it is the number the engine's clamp reads, and a tree built from a shape records the raw bounds' longest side anyway) and it has one, else the raw geometry's bounds – so a tree of a geometry an edit replaced, which stands until the next build retires it, never answers for the new one. The tree handed in must still be the one standing: a swap between the caller's read and this one answers the raw bounds rather than pairing the new tree's key with the old tree's number.
public double GetReferenceSize_mm(CubeTree tree, out bool fromMeshedGeom)
Parameters
treeCubeTreeThe standing tree as the caller read it; null when none.
fromMeshedGeomboolTrue when the size is the tree's own.
Returns
- double
The reference size in mm; 0 when unknown.
GetReferenceSize_mm(out bool)
The workpiece's reference size for the licence's resolution cap, in mm: the longest side of the bounding box of the geometry the stock is built from. The bounds of InitGeom as ReferenceSizeOfRawGeom_mm(IMakeXmlSource) takes them – what the native build records in the trailer of a tree built from a shape, so the raw bounds answer whether that tree stands or not, and a tree built from a previous geometry never answers for the current one – never a mesh generation; the standing tree's own ReferenceSize_mm whenever the tree stands for the geometry of the moment (MeshedGeomIsOf(IMakeXmlSource), whatever its kind: the number the engine's clamp reads; for a CubeTreeFile the only source there is). 0 when unknown: no workpiece or geometry, a CubeTreeFile whose tree is not loaded or stands for another file, a geometry without bounds, or bounds without volume.
public double GetReferenceSize_mm(out bool fromMeshedGeom)
Parameters
fromMeshedGeomboolTrue when the size is the standing tree's own (the tree stands for the geometry of the moment); false when it came from the raw geometry's bounds (or is 0).
Returns
- double
The reference size in mm; 0 when unknown.
MeshedGeomIsOf(IMakeXmlSource)
Whether the standing tree is the stock of rawGeom: a tree stands, and it was built from,
loaded from, or set or read under a geometry of the same key
(SourceKeyOf(IMakeXmlSource, string): the same file, the same mesh object, or
the same XML text, so the authored copy of the runtime face's geometry asks and is answered). False with no
tree, with no geometry, and for a file-backed geometry that has no file. The project service reports the
stock's width through it: a stock standing is reported only while it is the stock of this geometry – the next
play's, or the one a mid-session re-play goes on cutting – never the stock of the geometry an edit replaced,
which stands until the next build retires it.
public bool MeshedGeomIsOf(IMakeXmlSource rawGeom)
Parameters
rawGeomIMakeXmlSourceThe raw geometry asked about, as either face holds it.
Returns
- bool
True when the standing tree stands for
rawGeom.
ReadMeshedGeom(string, IProgress<IMessage>)
Reads the meshed geometry from a file, relative to BaseDirectoryGetter. The file is
read whatever its resolution (the owner, 2026-10-09): the licence's resolution cap
(Hi.Licenses.LicenseCaps) limits the machining on the stock, not the file – a stock finer
than the cap allows runs its cuts at its own width, which no cut refines.
public bool ReadMeshedGeom(string relFile, IProgress<IMessage> messageProgress = null)
Parameters
relFilestringSource file path, relative to the injected base directory.
messageProgressIProgress<IMessage>IMessage-channel sink injected by the caller (null = silent).
Returns
- bool
True if the file existed and was read; false if it was not found.
ReadMeshedGeom(string, nint[], IReadOnlyList<CbtrPickable>, IProgress<IMessage>, out CubeTreeRebindStats)
Reads the meshed geometry from a file as ReadMeshedGeom(string, IProgress<IMessage>) does, with
the nodes' attachments rebound (the NC play result review): a node whose attachment pointer, as the file
holds it, equals nodeAttachKeys[i] carries nodeAttachments[i] – the
review's strip positions, so that the stock is coloured and picked by its steps as in the play –; a node whose
non-null pointer no key names carries the fresh plain base this service owns; a node whose pointer is null stays
unattached, as it was in the play (UpdateAttach(CbtrPickable) is run for the nodes a walk from the root
reaches unattached – the root of an empty tree –, and binds nothing in a stock a play wrote, whose root carries
an attachment). The caller owns the pickables and keeps them alive while the tree carries them (a strip
position until its strip is cleared, whose retire detaches them through RetireAttachments(IReadOnlyCollection<CbtrPickable>)
under the render barrier).
public bool ReadMeshedGeom(string relFile, nint[] nodeAttachKeys, IReadOnlyList<CbtrPickable> nodeAttachments, IProgress<IMessage> messageProgress, out CubeTreeRebindStats stats)
Parameters
relFilestringSource file path, relative to the injected base directory.
nodeAttachKeysnint[]The attachment pointer values the file holds, one a pickable (NativeAttachmentHandle when the file was written).
nodeAttachmentsIReadOnlyList<CbtrPickable>The pickables to bind, one a key, in the same order.
messageProgressIProgress<IMessage>IMessage-channel sink injected by the caller (null = silent).
statsCubeTreeRebindStatsWhat the rebind did to the nodes; default when the file was not found.
Returns
- bool
True if the file existed and was read; false if it was not found.
Exceptions
- ArgumentNullException
nodeAttachKeysornodeAttachmentsis null.- ArgumentException
The keys and the pickables differ in number.
- EntryPointNotFoundException
The native library has no
cube_tree__new_by_file_rebound(acore.dllolder than this build); the previous stock is retired by then.
ReferenceSizeOfRawGeom_mm(IMakeXmlSource)
The longest side of the bounding box of the triangles rawGeom would be voxelized as – what
the native build records as the tree's reference size – without generating a mesh. A
TransformationGeom over a resident mesh (an Stl, or an StlFile whose
CacheStl is loaded) transforms the mesh's vertices, so a rotated part gets its true box
rather than the box of its box, and a transformation nested in a transformation composes the matrices down to
the mesh and walks the vertices once; over anything else, the transformed corner box (a superset: never finer
than the engine's reference). 0 when the geometry has no bounds, is not loaded yet (a
CubeTreeFile), or has no volume (the build refuses it). The box itself, in whole mm for the
usage report, is TryGetReferenceBox_mm(IMakeXmlSource, out uint, out uint, out uint): the same traversal.
public static double ReferenceSizeOfRawGeom_mm(IMakeXmlSource rawGeom)
Parameters
rawGeomIMakeXmlSourceThe raw geometry as InitGeom holds it; null answers 0.
Returns
- double
The longest side in mm; 0 when unknown.
ResetMeshedGeom()
Resets the meshed geometry.
public void ResetMeshedGeom()
RestorePlainBaseAfterStoppedDiff(IProgress<IMessage>)
Gives the live tree its plain base back when a stopped
Diff(double, CancellationToken, IProgress<IMessage>) left leaves without an attachment
(the base is retired for the compare, and the leaves the stop kept it from reaching get no
DiffAttachment); no-op otherwise. Machining needs every leaf attached: a step nulls the attachments
on its cut path up to the root and then attaches its pose to each attachment-free leaf it reaches
from there (UpdateAttach(CbtrPickable)), so a bare leaf would take the pose of a step that
never cut it, drawn in that step's colour and picking it. One rebuild walk puts the base on every
node, as a tree build does, which also replaces the partial overlay and the poses of earlier steps
on the leaves the compare never reached; the overlay's attachments are left with no node, so their
detach behind the render barrier walks nothing before they are freed. Called before a play or a
scripted act machines the tree (BeginNcRunner()), not
by the stop: a close or a reset after a stop retires the tree instead, and must not wait for this
walk. It holds the field lock for the walk – seconds on a tree of millions of leaves – so it says
so first (Diff–StoppedCleared), which also tells the user where the partial colours went.
public void RestorePlainBaseAfterStoppedDiff(IProgress<IMessage> messageProgress = null)
Parameters
RetireAttachments(IReadOnlyCollection<CbtrPickable>)
Retires attachments OWNED BY A CALLER (e.g. ClStrip's ClStripPos) that are attached to the current meshed tree. If a tree is current it detaches them under its write-gate render barrier first; otherwise (tree already retired) it just frees them on the background chain. Targeted — never touches the base attachment or diff attachments.
public void RetireAttachments(IReadOnlyCollection<CbtrPickable> attachments)
Parameters
attachmentsIReadOnlyCollection<CbtrPickable>
ScanMeshedGeomInfDefect(IProgress<IMessage>, CancellationToken)
Scans the meshed geometry for inf defects.
public bool? ScanMeshedGeomInfDefect(IProgress<IMessage> messageProgress, CancellationToken cancellationToken)
Parameters
messageProgressIProgress<IMessage>cancellationTokenCancellationToken
Returns
- bool?
SetMeshedGeom(CubeTree)
Sets the meshed geometry instance and rebuilds its attachments.
public void SetMeshedGeom(CubeTree meshedGeom_)
Parameters
meshedGeom_CubeTreeThe meshed cube tree geometry.
TryGetReferenceBox_mm(IMakeXmlSource, out uint, out uint, out uint)
The bounding box of the triangles rawGeom would be voxelized as, each side rounded up to a
whole mm: the workpiece size of the usage report, from the traversal
ReferenceSizeOfRawGeom_mm(IMakeXmlSource) takes its longest side from – the transformed vertices of a resident
mesh, the transformed corner box otherwise, never a mesh generation. False, with the sides 0, when the
geometry is null, has no bounds or is not loaded (a CubeTreeFile), has no volume (the build
refuses it), or is not finite.
public static bool TryGetReferenceBox_mm(IMakeXmlSource rawGeom, out uint x, out uint y, out uint z)
Parameters
rawGeomIMakeXmlSourceThe raw geometry as InitGeom holds it; null answers false.
xuintThe box's side along x, rounded up to a whole mm; 0 when false.
yuintThe box's side along y, likewise.
zuintThe box's side along z, likewise.
Returns
- bool
Whether the box is known.
WriteMeshedGeom(string, CancellationToken, IProgress<IMessage>)
Writes the meshed geometry to a file, relative to BaseDirectoryGetter.
public void WriteMeshedGeom(string relFile, CancellationToken token, IProgress<IMessage> messageProgress = null)
Parameters
relFilestringTarget file path, relative to the injected base directory.
tokenCancellationTokenCancellation token.
messageProgressIProgress<IMessage>IMessage-channel progress sink (null = silent).