Table of Contents

Class NcOptPieceClassifier

Namespace
Hi.NcOpt
Assembly
HiMech.dll

Classifies the SoftNc final-layer SyntaxPiece stream into the INcOptPiecePack list and the per-step StepOptContext dictionary that the StepFeedSolver consumes: maps each piece to its MachiningStep index segment, runs the tool-change state machine, evaluates the opt-ability criteria and seeds preserved packs with their constraining feedrate.

public static class NcOptPieceClassifier
Inheritance
NcOptPieceClassifier
Inherited Members

Remarks

Ported from HiNc NcOptProc.CreateLinePackList + OnToolChanging (frozen HardNc baseline, HiNc/NcOpt/NcOptProc.cs lines 613-829). The HardNc NcFlagBitArray reads are replaced by reads of the SoftNc JSON sections (ToolChange, ToolHeightCompensation, CannedCycle, MotionState/MotionEvent, CompoundMotion, RadiusCompensation, Feedrate), and the HardNc GetStepIndexSegment FileLineIndex scan (lines 127-134, 693-695) is replaced by a two-pointer walk over SentenceIndex / SentenceIndex that yields CONTIGUOUS segments (see GetStepIndexSegment(List<MachiningStep>, ref int, int)): every step index lands in exactly one piece's segment, so downstream step-keyed dictionaries built from the segments are hole-free over the whole step list.

Null-step tolerance mirrors the oracle exactly where the oracle has it: the HardNc step list is the raw unfiltered strip-pose projection (NcOptProc.cs:2521) and only the segment key selector is null-conditional (machiningStep?.SourceCommand?..., NcOptProc.cs:132) — a null entry behaves as a key-less (SentenceIndex == -1) step in the mapping. Everywhere else (opt-ability probes, distance walkers, the solver) steps are read directly, exactly as the oracle reads them (e.g. NcOptProc.cs:739, 1211, 1236); no extra null guards are added.

The preserved-pack seed precedence mirrors the HardNc chain (lines 803-813) exactly: blank/comment-only line → +Inf; else macro line (in-canned-cycle, G28 or G53.1, see NcFlagUtil.IsMacro lines 648-656) → the minimum RapidFeed_mmds over the seed option list (the OPTION rapid feed, not the machine rapid); else rapid (G00-modal) line → the machine rapid feedrate (the value HardNcLine.Feedrate_mmds reads on a rapid line, HardNcLine.cs:206-211, inherited from HardNcEnv); else the line's modal F.

P2 splition emission: an opt-able piece whose seed options enable interpolation (and which is not radius-compensating nor a multi-turn arc) is emitted as a SplitionPiecePack — its ctor seeds the per-step StepAdjustment list — mirroring the oracle's SplitionLinePack emission (NcOptProc.cs:748-793). Two SoftNc-only guards downgrade such a piece to MonoPiecePack with one diagnostic per run each, safer than the oracle's silent wrongness: a G91 incremental-modal piece (NcOpt--SplitionIncrementalUnsupported; the oracle has no G90/G91 handling and its fragment rewrite always emits absolute coordinates, NcOptProc.cs:1934-1935), and a piece whose ProgramToMcTransform chain carries a Dynamic (RTCP) entry (NcOpt--SplitionRtcpUnsupported; a Dynamic entry is a block-endpoint snapshot whose per-step inverse is invalid at interpolated points, see HasDynamicEntry(JsonObject)). A third guard is brand-shaped: under Heidenhain the fragment rewrite would splice ISO-shaped words into klartext (NcOpt--SplitionKlartextUnsupported) — a klartext arc parses through HeidenhainCircularMotionSyntax into the same MotionEvent { Form: McArc, ArcCenter } the ISO path produces, so the splition arc rewrite would emit I/J/K offset words into a C … DR+ block that has no such vocabulary (its center comes from the modal CC block), and the block's RND R…/radius words would read as an R-format arc to delete. IsArc follows the oracle's MODAL semantics (NcFlagUtil.IsOnArcCommand, the G02/G03 Group-01 latch); the one-shot arc-data presence is carried separately as HasArcMotionEvent.

Scope notes still in effect. The Heidenhain L/LN veto of the HardNc IsRapid predicate (NcFlagUtil.cs:633-635: an L/LN line is never rapid, even under FMAX) is deliberately NOT reproduced: the SoftNc Logic bundle normalizes a klartext L block onto the shared ISO vocabulary and consumes the L marker, stamping G00 for FMAX and G01 otherwise (LogicSyntaxs.Heidenhain.HeidenhainMotionModeSyntax), so no piece-level probe for "this was an L statement" survives — and porting the veto on top of that normalization would classify an FMAX rapid as a feed move, which is wrong in the SoftNc model rather than merely different. Reproducing it would require carrying the klartext statement kind into the sections; that is a deliberate open question, not an oversight. G95 feed-per-revolution is warned once per run (NcOpt--FeedPerRevNotSupported) while its raw value is still treated as mm/min.

Methods

CreatePiecePackList(IReadOnlyList<SyntaxPiece>, List<MachiningStep>, SortedList<int, NcOptOption>, MachiningToolHouse, bool, double, string, out Dictionary<int, StepOptContext>, NcDiagnosticProgress, IProgress<IMessage>, CancellationToken)

Creates the piece pack list with the step segments built, and prepares the StepOptContext seats of every step of the opt-able pieces (only those steps get an entry).

public static List<INcOptPiecePack> CreatePiecePackList(IReadOnlyList<SyntaxPiece> pieces, List<MachiningStep> machiningSteps, SortedList<int, NcOptOption> stepIndexToSeedOptionSortedList, MachiningToolHouse machiningToolHouse, bool isPhysicsComputable, double machineRapidFeedrate_mmds, string targetBrand, out Dictionary<int, StepOptContext> stepIndexToStepOptContextDictionary, NcDiagnosticProgress conversionProgress, IProgress<IMessage> messageProgress, CancellationToken cancellationToken)

Parameters

pieces IReadOnlyList<SyntaxPiece>

Final-layer syntax pieces in execution order, already filtered of the init seed (pieces without a source file path). SentenceIndex must be strictly increasing (gaps allowed); the precondition is validated and a violation aborts the classification (see returns).

machiningSteps List<MachiningStep>

The raw strip-pose step projection, UNFILTERED (a strip pos without a machining step contributes a null entry — the oracle's unfiltered read, NcOptProc.cs:2521), ordered so that SentenceIndex is monotonic non-decreasing (key-less -1 steps may be interspersed). Step indices used in the outputs are positions in this list, which equal StepIndex (the strip pos index) exactly because the list is unfiltered.

stepIndexToSeedOptionSortedList SortedList<int, NcOptOption>

Sorted list mapping step index to the seed NcOptOption effective from that step on (floor lookup semantics).

machiningToolHouse MachiningToolHouse

The machining tool house (int tool id keys).

isPhysicsComputable bool

Whether the physics data required by the solver exists (HardNc equivalent: millingPara != null).

machineRapidFeedrate_mmds double

The machine rapid traverse feedrate in mm/s (HardNc equivalent: HardNcEnv.RapidFeedrate_mmds), see GetMachineRapidFeedrate_mmds(MachiningSession). NaN when no rapid-feedrate config is reachable; rapid pieces then fall back per piece, see ResolveRapidFeedrate_mmds(double, List<MachiningStep>, IndexSegment).

targetBrand string

The session's CNC brand (CncBrandDependency values; defaults to Fanuc) — consulted only by the klartext splition guard, see the class remarks.

stepIndexToStepOptContextDictionary Dictionary<int, StepOptContext>

Output: one StepOptContext per step of every opt-able piece, keyed by step index, with the ExtendedIndexSegment already fixed up to inclusive-begin / exclusive-end.

conversionProgress NcDiagnosticProgress

Optional diagnostic home for piece-anchored warnings (tool not found, splition guard downgrades).

messageProgress IProgress<IMessage>

The message host for progress logging.

cancellationToken CancellationToken

Cancellation token to cancel the operation.

Returns

List<INcOptPiecePack>

One INcOptPiecePack per piece, in the same order — the piece segments are contiguous and cover every step index (see GetStepIndexSegment(List<MachiningStep>, ref int, int)). Null when canceled, or when the piece SentenceIndex stream is not strictly increasing (e.g. a legacy counter-less preset replaying a subprogram): a NcOpt-Pieces–NonMonotonic error is emitted on both the message channel and the diagnostic home and the optimization aborts gracefully (the orchestrator treats null as the cancel path).

GetEffectiveMachineRapidFeedrate_mmds(double)

The machine rapid feedrate to seed modal-F state with, in mm/s: machineRapidFeedrate_mmds when resolved (non-NaN), otherwise the 20000 mm/min sentinel — the shared default of both HardNcEnv.RapidFeedrate_mmds (HardNcEnv.cs:252) and IRapidFeedrateConfig (ControllerParameterTableBase.cs:39). This is the SoftNc dual of the HardNc chain seed: HardNcEnv.RefNcLineOnInit seeds BOTH the rapid and the machining modal-F registers with the env rapid (HardNcLine.cs:332-333).

public static double GetEffectiveMachineRapidFeedrate_mmds(double machineRapidFeedrate_mmds)

Parameters

machineRapidFeedrate_mmds double

The machine rapid feedrate in mm/s; NaN when unresolved (see GetMachineRapidFeedrate_mmds(MachiningSession)).

Returns

double

GetLiteralArcTurnCount(string)

The literal L (turn count) word on an arc block's text, comment masked, or 0 when absent/non-numeric — the SoftNc stand-in for the oracle's ArcNcArg.L multi-turn splition veto (frozen NcOptProc.cs:757-762): a value > 0 refuses re-interpolation.

public static double GetLiteralArcTurnCount(string blockText)

Parameters

blockText string

The arc block's text; null/empty reads 0.

Returns

double

Remarks

Deliberately NOT the parsed MotionEvent.AdditionalCircleNum. That field is derived, not literal: CircularMotionSyntaxUtil.IsClosedOnPlane makes it 1 for an L-less closed full circle (the renderer needs the extra turn) and a pitch helix can carry one too — arcs the oracle splits happily, because its veto reads the L word alone. Probing the source text keeps the two sides on the same criterion. Only reached under a G02/G03 modal, so a Heidenhain L motion word never lands here (and it is followed by a space, not a number, so it would read as absent anyway).

GetLiteralFeedrateTagKind(string)

Classifies the literal F token of the block text (outside comments) through the patcher's own value grammar, ProbeTagValue(string, string, string, IReadOnlyList<(int Start, int Length)>, IReadOnlyList<string>) (number | variable/bracket expression | keyword) — so this probe and a subsequent NcPatchWriter F edit can never disagree on token presence or editability. The modal-carried Feedrate section cannot answer this — it is present on every block once any F has appeared — so the writeback path uses this text probe to know when a preserved line keeps its own F token, when deleting the F token is meaningful at all, and when an F edit would be refused (Unpatchable: e.g. F#500). Fanuc-family comment spans and the # variable prefix are assumed (P1 scope; the writer is brand-aware, the probe follows in P2).

public static NcTagValueKind GetLiteralFeedrateTagKind(string blockText)

Parameters

blockText string

The block text to test.

Returns

NcTagValueKind

HasLiteralFeedrateTag(string)

Whether the block text literally carries an F word (outside comments), numeric or not — see GetLiteralFeedrateTagKind(string).

public static bool HasLiteralFeedrateTag(string blockText)

Parameters

blockText string

The block text to test.

Returns

bool

IsBlankOrCommentOnly(string)

Whether the block text is blank or consists of comments only (Fanuc family comment shapes: head-% line and paren spans). Such a piece never constrains its neighbors, so its preserved seed feedrate is positive infinity.

public static bool IsBlankOrCommentOnly(string blockText)

Parameters

blockText string

Returns

bool

IsIncrementalPositioning(JsonObject)

public static bool IsIncrementalPositioning(JsonObject json)

Parameters

json JsonObject

Returns

bool

IsMacroPiece(JsonObject)

Whether the piece's modal positioning state is G91 incremental — its Positioning section (written on every NC block by PositioningSyntax, defaulting to absolute) carries Mode == Incremental. A missing section (e.g. a CL-sourced piece) counts as absolute. This is the probe behind the NcOpt–SplitionIncrementalUnsupported guard (see class remarks).

public static bool IsMacroPiece(JsonObject json)

Parameters

json JsonObject

The piece's JSON object.

Returns

bool

IsSimpleFeedrateAssignable(string, IProgress<IMessage>)

Whether an F word can simply be inserted into (or restated on) the block: the block carries a G01/G02/G03 (or Heidenhain L/LN) token, or — excluding head-% blocks — it consists solely of axis words (X/Y/Z and A/B/C both present) with nothing else left after grabbing them.

public static bool IsSimpleFeedrateAssignable(string blockText, IProgress<IMessage> messageProgress)

Parameters

blockText string

The block text to test.

messageProgress IProgress<IMessage>

The message host for parse-error logging.

Returns

bool

Remarks

Ported from HiNc NcOptProc.IsSimpleFeedrateAssignableNcLine (frozen HardNc baseline, lines 1994-2025) over BlockText, including the original's requirement that both an XYZ and an ABC word exist on the bare-coordinate branch.

ResolveRapidFeedrate_mmds(double, List<MachiningStep>, IndexSegment)

Resolves the effective rapid feedrate of a rapid (G00-modal) piece in mm/s: machineRapidFeedrate_mmds when resolved (non-NaN); otherwise the maximum played step feedrate over the piece's segment (the SoftNc player runs rapids at the configured per-axis rapid rates, so the effective step feedrate approximates the machine rapid); last resort the 20000 mm/min sentinel — the shared default of both HardNcEnv.RapidFeedrate_mmds (HardNcEnv.cs:252) and IRapidFeedrateConfig (ControllerParameterTableBase.cs:39).

public static double ResolveRapidFeedrate_mmds(double machineRapidFeedrate_mmds, List<MachiningStep> machiningSteps, IndexSegment stepIndexSegment)

Parameters

machineRapidFeedrate_mmds double

The machine rapid feedrate in mm/s; NaN when unresolved.

machiningSteps List<MachiningStep>

All machining steps.

stepIndexSegment IndexSegment

The piece's step index segment.

Returns

double