Table of Contents

NC optimization and writeback

Important

NC optimization is not finished on the 3.2 line. What follows describes the leg as it stands, and it is published for review, not for production. Work that depends on optimized output should stay on the 3.1 line, serviced as 3.1.175.<patch>.

  • The optimizer runs on the SoftNc pipeline by default. OptimizeToFiles keeps its signature, its script snippet and its HTTP route, but when EnableSoftNcRunner is on and the session holds played SyntaxPieceLayers, it delegates to the new OptimizeNcFiles; otherwise the frozen HardNc path runs unchanged. The new leg classifies the final SyntaxPiece layer, solves the per-step feed adjustments from milling physics, and regenerates text as anchored token edits over the verbatim source block — lines the optimizer does not touch round-trip byte-identically instead of being re-synthesized. Per-file results are retained in NcOptimizations. EnableIndividualStepAdjustmentLog drives both legs.
  • Depth splition re-interpolates through a planned fragment path, with separate modal chains for the pre-build feed and the emission endpoint, per-step machine-to-program-frame inversion, and per-fragment arc IJK recomputation — including R-to-IJK conversion — wherever the arc block itself carries the centre. An arc whose centre lives on a preceding modal block is exempt: its fragments keep the source block's arc words and share that upstream centre line unchanged, so only their endpoint and F words move. Two cases where the frozen HardNc optimizer is silently wrong are downgraded to a non-split rewrite rather than reproduced, each warned once per run. The first is an incremental block, and it is now taken by both of its spellings: G91 modal state, or a block whose modal state is absolute while individual axis words carry a per-word incremental override — Siemens X=IC(10) and the coded CIC(), klartext IX+20 and IC+90. The frozen fragment rewrite carries no G90/G91 handling at all and always re-emits a coordinate as an absolute program value, so it splits both shapes and is wrong on each in its own way: the G91 line comes back stating an absolute number the control still reads as a distance, and the per-word line keeps its incremental source word, so every fragment re-applies the same distance from its own start. Both now stop at NcOpt--SplitionIncrementalUnsupported. The per-word spelling is also the only one that can reach klartext: that dialect has no modal G90/G91 word, so a stamped axis word is the only incremental form it produces. The second case is a klartext C … DR± arc whose modal CC chain left one of the two in-plane axes unstated, so the block's own start point supplied that component — since every fragment would re-derive the centre from its own start; that one reports NcOpt--SplitionStartPointCenterUnsupported. A klartext C block whose centre lands entirely on its own start point never reaches that guard: its radius is zero, so play degrades it to a chord under a validation warning of its own. Neither the controller brand nor klartext as such refuses a split: a klartext L block re-interpolates like an ISO one.
  • The compensation stage is no longer dead on the SoftNc leg. The HardNc baseline wrote the compensation into the step contexts while its output read the piece packs, so it never emitted a compensated coordinate at all. Each fragment endpoint is now offset — XYZ only, rotary words untouched — by the tool-tip deflection rotated into the leaf program frame the endpoint lives in, so a G68.2 tilted setup is compensated in the right direction. It is consumed on re-interpolated splition fragments only, and CompensationMask defaults to 0, so with no mask set the stage is a strict no-op.
  • Output follows the source's decimal digits. Both legs used to write coordinates through a fixed F4 and every F word through F2, so a program stated to three decimals could come back with a fourth — an alarm on controllers strict about their least input increment. Digit counts are now scanned per word family over the played source texts with comment spans masked, floored at 3/3/0 and capped at 9, and threaded through the whole write path. The word-suppression tolerances and the F comparison grid derive from the resolved digits instead of the old fixed literals.
  • Leading zeros follow the source, and the project can pin the spelling. OmitLeadingZero is an output style: on, the writer drops a leading zero before the decimal (.5 rather than 0.5); off, it writes the zero. The option is carried on the project so two machines produce the same bytes, and a report names which style the source itself used.
  • Optimized NC is written back in the source file's encoding. NC play reads and optimized writes go through DetectRoundTripEncoding — BOM, then strict UTF-8, then Latin-1 — so an ANSI-family file (GBK, Big5, Shift-JIS) re-encodes to its original bytes instead of having every undecodable byte replaced. Comments in those encodings survive the round trip.
  • A feed change no longer mints a one-step carrier fragment. Under an arc split that fragment is a degenerate arc whose start and end nearly coincide, which an incremental-IJK reader — or a control that treats begin == end as a full turn — expands into a full circle. An F re-statement is now handed to the feed run's next emitted fragment, the one that actually runs at that feed.
  • A splition fragment at the head of the stream writes only the axis words the source stated, so it can no longer invent a Z0. whose value under the source's silence is just the home-fallback modal.
  • Unparsable NC lines survive. A line the parser could not read used to be dropped from the runner's line list, so the optimized file silently lost it. HardNcRunner now rebuilds a parse-failed line as an opaque no-op — the empty-text parse inherits modal state like a blank line, and the raw text is restored for writers — and the optimizer mirrors the fallback, so IF blocks, #-variable macros, G68 R# and GOTO come through verbatim. A BuildNcLines--ParseFailed diagnostic still reports the line, and the line stays un-simulated. The output writer is also closed in a finally, so an exception can no longer leave a half-written file locked. First delivered on the 3.1.175.x service line.
  • A Siemens CYCLE800 swivel counts as a macro line in the piece classifier, so it is preserved rather than treated as an optimizable motion block.
  • The host key HiNC:OptCoreNum governs both legs again. It used to set only the legacy NcOptProc.CoreNum; once the SoftNc optimizer became the default path the key silently stopped governing anything. It now assigns both (0 = derive from the processor count).
  • NC text writeback regenerates NC from a program that has already been played, in two stages over the session's finished syntax pieces: a converter turns the source piece stream into a destination stream plus a bidirectional source↔destination map keyed by sentence index, and a reverse segmenter serializes that stream back to lines. The data→text seam is a brand-agnostic sentence composer, first implemented for Fanuc. A patch-mode writer performs positional token edits — NaN deletes a word absorbing one separator space, insertion follows conventional order, trailing zeros trim keeping the dot — and refuses to rewrite variable, bracket and keyword values rather than corrupting them, reporting Writeback-Patch--VariableValue, --KeywordValue, --CommentOnlyText and --EditUnmatched. Five of its choices follow the dialect rather than the convention: the variable prefix it recognizes and refuses (Q on klartext, R on Siemens, # elsewhere), the keyword feed values it refuses (klartext's FMAX and FAUTO), the comment spans it protects (klartext's ; and // as well as the parenthesized span), and two that show in the written text. On a klartext file an inserted F lands after the rightmost of DR+/DR- and RL/RR/R0 as well as after its conventional predecessor coordinate words, so the patched block keeps the element order a TNC enforces — coordinates, rotation direction, radius compensation, F, M. And a trailing comment is wrapped in the file's own grammar, the Fanuc family's (text) against klartext's ;text, so the optimizer's embedded source note leaves a klartext program valid instead of handing a control a parenthesis it would read as code.
  • A second diagnostic home. NcManipulationDiagnosticProgress is a sibling of the play-time NcDiagnosticProgress, dedicated to NC-rework operations — writeback conversion and optimization — so a play reset never discards manipulation results and vice versa.