Table of Contents

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

workpieceGetter Func<Workpiece>
baseDirectoryGetter Func<string>

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

Func<string>

BottomResolution

Resolution.

public double BottomResolution { get; }

Property Value

double

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

CubeTree

CollidableName

Gets the name of the collidable object.

public string CollidableName { get; }

Property Value

string

ConstructionDefectDisplayee

Construction defect displayee.

public ConstructionDefectDisplayee ConstructionDefectDisplayee { get; }

Property Value

ConstructionDefectDisplayee

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

double

DiffAttachmentBag

transient object. For Internal Use.

public ConcurrentBag<DiffAttachment> DiffAttachmentBag { get; }

Property Value

ConcurrentBag<DiffAttachment>

DiffRangeColorRule

Internal used.

public RangeColorRule DiffRangeColorRule { get; set; }

Property Value

RangeColorRule

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

double

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

bool

IdealGeom

Delegate property for IdealGeom with cache cleanup.

public IGetStl IdealGeom { get; set; }

Property Value

IGetStl

IdealSolid

Gets the drawing representing the ideal geometry faces of the workpiece. The derived solid from IdealGeom.

public Solid IdealSolid { get; }

Property Value

Solid

InitGeom

Delegate property for InitGeom with runtime cleanup.

public IMakeXmlSource InitGeom { get; set; }

Property Value

IMakeXmlSource

InitSolid

The derived solid from InitGeom.

public Solid InitSolid { get; }

Property Value

Solid

IsMeshedGeomInit

Indicates whether the meshed geometry is initialized.

public bool IsMeshedGeomInit { get; }

Property Value

bool

Workpiece

The underlying workpiece data model.

public Workpiece Workpiece { get; }

Property Value

Workpiece

WorkpieceGetter

Lazy factory for the active Workpiece; invoked whenever consumers read Workpiece.

public Func<Workpiece> WorkpieceGetter { get; }

Property Value

Func<Workpiece>

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

detectionRadius double

Detection radius; saved to DetectionRadius_mm once the overlay is built.

token CancellationToken

Cancellation 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).

messageProgress IProgress<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

bind Bind

Bind 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

disposing bool

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

dst box3d_t

Destination 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

ICollidee

ICollidee

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

token CancellationToken

Cancels an in-progress build (leaves the geometry unbuilt / null).

messageProgress IProgress<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

tree CubeTree

The standing tree as the caller read it; null when none.

fromMeshedGeom bool

True 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

fromMeshedGeom bool

True 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

rawGeom IMakeXmlSource

The 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

relFile string

Source file path, relative to the injected base directory.

messageProgress IProgress<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

relFile string

Source file path, relative to the injected base directory.

nodeAttachKeys nint[]

The attachment pointer values the file holds, one a pickable (NativeAttachmentHandle when the file was written).

nodeAttachments IReadOnlyList<CbtrPickable>

The pickables to bind, one a key, in the same order.

messageProgress IProgress<IMessage>

IMessage-channel sink injected by the caller (null = silent).

stats CubeTreeRebindStats

What 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

nodeAttachKeys or nodeAttachments is null.

ArgumentException

The keys and the pickables differ in number.

EntryPointNotFoundException

The native library has no cube_tree__new_by_file_rebound (a core.dll older 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

rawGeom IMakeXmlSource

The 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

messageProgress IProgress<IMessage>

IMessage-channel sink for that notice (null = silent).

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

attachments IReadOnlyCollection<CbtrPickable>

ScanMeshedGeomInfDefect(IProgress<IMessage>, CancellationToken)

Scans the meshed geometry for inf defects.

public bool? ScanMeshedGeomInfDefect(IProgress<IMessage> messageProgress, CancellationToken cancellationToken)

Parameters

messageProgress IProgress<IMessage>
cancellationToken CancellationToken

Returns

bool?

SetMeshedGeom(CubeTree)

Sets the meshed geometry instance and rebuilds its attachments.

public void SetMeshedGeom(CubeTree meshedGeom_)

Parameters

meshedGeom_ CubeTree

The 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

rawGeom IMakeXmlSource

The raw geometry as InitGeom holds it; null answers false.

x uint

The box's side along x, rounded up to a whole mm; 0 when false.

y uint

The box's side along y, likewise.

z uint

The 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

relFile string

Target file path, relative to the injected base directory.

token CancellationToken

Cancellation token.

messageProgress IProgress<IMessage>

IMessage-channel progress sink (null = silent).