This document is the detailed user and developer reference for Easy G-Code Plot. It reflects the current working tree and explains the GUI, FANUC execution kernel, the supported SINUMERIK native and ISO-M subsets, Macro B runtime, turning and milling cycles, indexed rotary behavior, diagnostics, CLI, batch analysis and export behavior.
The same FAQ can be packaged for offline use in Help → FAQ.
- Easy G-Code Plot FAQ
- Project scope and execution model
- Getting started
- Diagnostics and fail-closed behavior
- FANUC Macro B and program flow
- How complete is Macro B support?
- Which variable forms are supported?
- What is special about
#0? - What happens when an undefined variable is used numerically?
- Which arithmetic and relational operators are supported?
- Which Macro B functions are implemented?
- Are assignments supported on labeled blocks?
- Is unconditional
GOTOsupported? - Is
IF [...] GOTOsupported? - Are
WHILE / DO / ENDloops supported? - Are real Macro B milling programs exercised by the tests?
- Is
G65supported? - How are G65 Type I arguments mapped?
- How are repeated I/J/K G65 arguments handled?
- Do G65 argument words also perform machine actions?
- What happens to
#1..#33when a G65 macro returns? - What does
G65 ... L...do? - How deeply can G65 macros nest?
- How does M98 behave inside a G65 macro?
- Are M98/M99 subprograms supported outside Macro B?
- Is
M99 P...supported? - Are Macro B variable values stored per execution step?
- Does Expanded Execution export keep Macro B statements?
- FANUC turning
- Main differences between Type A and Type B
- What is the turning coordinate model?
- How do X/U and Z/W behave?
- How are G20 and G21 handled?
- Which turning arc formats are supported?
- Why can G2/G3 direction look inverted in an XZ plot?
- Is direct A-angle turning programming supported?
- Are C chamfers and corner R fillets supported?
- Are G32 and G33 threading motions supported?
- What are the turning feed modes?
- Are G96 and G97 modeled?
- What does G50 S do in turning?
- Are spindle start/stop signals tracked?
- Which WCS features work in turning?
- Is G53 supported in turning?
- How does G28 work?
- Is G30 the same as G28?
- How does tool-nose compensation work?
- Turning cycles
- Which turning cycles are modeled?
- Do cycle motions remember where they came from?
- How are cycle profiles selected by P and Q?
- Do G71/G72/G73 profile blocks support lines and arcs?
- How does G70 work?
- What form of G71 is supported?
- How is G71 depth interpreted?
- How are G71 U/W finish allowances handled?
- How does G71 distinguish OD and ID roughing?
- What is G71 Type I behavior?
- Is G71 Type II supported?
- How does G72 work?
- Is G72 Type II fully generic?
- How does G73 work?
- How does G74 work?
- How does G75 work?
- How is turning peck motion represented?
- How does two-line G76 work?
- How are G76 P/Q integer increments interpreted?
- How is G76 pass depth generated?
- What do the packed G76 P digits mean here?
- Which G76 tool angles are modeled?
- How is G76 chamfer modeled?
- Is G92 a modal threading cycle?
- Is G90 a modal turning cycle?
- Is G94 a modal facing cycle?
- What cancels G90/G92/G94?
- Are turning G83 and G84 modal?
- How does turning G83 behave?
- How does turning G84 behave?
- Does P dwell in turning G83/G84 create geometry?
- What happens if a modal drilling/tapping cycle is left in an invalid state?
- FANUC milling
- Which milling G functions are recognized?
- Which milling M functions are recognized?
- What basic milling motion is modeled?
- How is indexed rotary milling handled?
- Which rotary profiles have been checked?
- What happens when indexed geometry cannot be resolved?
- Which milling canned cycles are modeled?
- What is the difference between G73 and G83 milling peck cycles?
- How is G82 dwell represented?
- How is milling G84 represented?
- How is milling G86 represented?
- What do milling G98/G99 mean?
- What are milling feed modes?
- Which work coordinate systems are supported?
- How does G10 behave under G91 in milling?
- How does G52 work?
- How do G68 and G69 work?
- How does G51/G50 scaling work?
- Is G53 supported in milling?
- Is G28 supported in milling?
- Is continuous five-axis TCP (
G43.4) supported? - How are milling arcs programmed?
- What does Arc Type autodetection do?
- Can one program mix R arcs with IJK arcs?
- Are full circles supported?
- Is helical interpolation supported?
- What does G16/G15 polar programming do?
- How does polar G90 work?
- How does polar G91 work?
- Do G20/G21 scale the polar angle?
- Are polar G2/G3 arcs supported?
- Is G12.1/G13.1 polar interpolation supported?
- How does milling cutter compensation work?
- What does
UNVERIFIED_CUTTER_COMPENSATIONmean? - Is G43 tool-length geometry applied?
- Tool libraries and tool discovery
- Where are persistent tools stored?
- What is the difference between Current Program and Saved Library?
- Does opening a program write discovered tools to the database?
- How are turning tool numbers represented?
- Can comments describe tool geometry?
- What happens when no explicit type hint is present?
- Are macro T expressions discovered as literal tools?
- Which turning tool geometries are stored?
- Which milling tools can be previewed?
- How are milling tool lengths defined?
- Does CLI execution load the GUI Saved Library?
- Interface, editor and playback
- What are the two main GUI panels?
- How does an imported STL affect toolpath visibility?
- How do I use the STL Objects panel?
- How do I import and select STL models?
- What do Undo, Redo, Statistics and Delete do?
- How do STL base points and bounding-box picks work?
- How do I position and transform an STL model?
- How do STL arrays work?
- How do I make a 3D section through an STL model?
- What does STL Statistics report, and how do I display inches?
- How do I change letter case or mark optional blocks?
- How do I print the plot?
- Which fixed views are available?
- How does playback relate to the kernel?
- What do Step Backward and Step Forward do?
- Why can many playback motions map to one source line?
- How do I locate a plotted move in the editor?
- Does automatic refresh move the editor caret?
- What happens when Auto Update is too expensive?
- What does Cancel stop?
- What CNC editing assistants are included?
- What does Hole Calculator generate?
- What does Pocket Calculator generate?
- Where are snippets stored?
- Options and scene configuration
- Turning Stock Removal
- Statistics and Tokens/Macro Variables
- Export
- Which GUI export families exist?
- Are exporters separate G-code interpreters?
- What does Full Program mean?
- What does Expanded Execution mean?
- What does DXF contain?
- Does DXF parse the G-code again?
- Which NC formatting options exist?
- Which milling Expanded arc output modes exist?
- What happens when a full circle is exported in R mode?
- Can Expanded NC be converted between millimetres and inches?
- Can Full Program be forced to mm or inch?
- What units does DXF use?
- Can comments be removed from export?
- Are exports written atomically by the CLI service?
- Can CLI export overwrite the source file?
- SINUMERIK 840D input
- CLI
- Does the CLI use the same kernel as the GUI?
- Which commands exist?
- What does
parsedo? - What does
tracedo? - What does
analyzedo? - What does
batchdo? - What does
exportdo? - What does
batch-exportdo? - Are single export and batch export different exporters?
- Which dialect names are used?
- What are the exit codes?
- How do I see every option and default?
- Batch analysis
- What does batch analysis validate?
- Which batch statuses exist?
- Which extensions are scanned by default?
- Can files without a normal NC extension be discovered?
- Is discovery deterministic?
- Can I restrict extensions?
- What is aggregated in the batch summary?
- What files are written?
- Does a bad input file stop the whole batch?
- Are there preset batch scripts?
- Batch export
- What problem does batch export solve?
- Does batch export modify the input files?
- Is the source directory hierarchy preserved?
- What happens if two source names map to one output name?
- Does one export error stop every file?
- What files describe the batch export?
- What are batch-export statuses?
- Which export modes are available from the CLI?
- Which options are intentionally rejected in Full Program mode?
- Can sequence start/increment be supplied without sequence numbers?
- Are there preset batch-export scripts?
- Configuration
- Troubleshooting
- The plot is empty
- Macro B motion is missing
- My G65 M/S/T words did not start spindle/coolant/change tool
- Cutter compensation is not visible
- G43 appears in the source but the plotted Z does not include tool length
- G71 leaves material on the wrong side
- G72 Type II reports an error
- G76 reports
UNSUPPORTED_G76_TOOL_ANGLE - Batch shows
UNSUPPORTED_M_CODEbut the geometry looks correct - Export unit conversion is refused
- Batch-export says the output directory is invalid
- A large program does not update while typing
- The GUI says the current execution is stale
- Development and architecture
- How is the CNC kernel organized?
- What belongs in
frontend/? - What belongs in
runtime/? - Why are turning cycles separate files?
- What belongs in
milling/? - What belongs in
compensation/? - What belongs in
app/gcode/export/? - What does
program_execution.pydo? - What does
batch.pydo? - What does
batch_export.pydo? - Which native components exist?
- How are execution results represented publicly?
- What is an
ExecutionStep? - What is an
ExecutionEvent? - How are tests organized?
- How do I run the main checks?
- How do I run the daily GUI smoke test with a visible window?
- Are generated Qt Python files edited manually?
- Build and release
- License
Easy G-Code Plot is a FANUC-style CNC editor, deterministic program executor, analyzer, backplotter and exporter for turning and milling programs.
The project has two user-facing entry points:
- a PyQt6 desktop GUI;
- a standalone CLI executable.
Both use the same CNC kernel and the same resolved ExecutionResult. The GUI is not a second interpreter, and the CLI does not contain a simplified parser of its own.
The core data flow is:
G-code source
|
`--> Parser / controller frontend
|- native Cython parser
`- per-block Python fallback where required
|
v
Program / AST
|
v
Program tool setup
(AST operation hints, library lookup, manual overrides)
|- source comments / dimensions: Cython scanner
`- Python scanner fallback
|
v
CNC execution kernel
(flow, cycles, compensation, geometry)
|
v
ExecutionResult
|
+--> GUI rendering / playback
+--> statistics
+--> batch / CLI trace
`--> NC / DXF export
ExecutionResult contains the resolved logical motion trace plus diagnostics, execution steps, signals, structural events, WCS state and execution completeness.
No. Rendering consumes the resolved trace produced by the kernel. The renderer does not independently reinterpret G-code.
This separation is intentional: the same resolved geometry is used by playback, statistics, export and analysis.
No. Easy G-Code Plot models supported FANUC program semantics and toolpath geometry. It does not model a complete physical CNC machine, servo dynamics, acceleration, spindle inertia, fixtures, machine envelopes or all controller parameters.
A clean result means the modeled program was executed without a known error inside the supported contract. It is not a substitute for machine verification.
For supported input, execution is intended to produce the same logical trace and diagnostics from the same source and configuration. The kernel avoids guessing controller-dependent behavior when the required semantics are not known.
Where the program cannot be resolved safely, the preferred behavior is an explicit diagnostic or incomplete result rather than invented geometry.
Release builds provide separate GUI and CLI executables for Windows and a Linux x64 archive containing both executables. A Python installation is not required for packaged builds.
For a source checkout, the project requires Python 3.13+, uv and a compiler for the native extensions.
git clone https://github.com/MaestroFusion360/easy_gcode_plot.git
cd easy_gcode_plot
uv sync --no-dev
uv run --no-dev python main.py- Open or drag a CNC program into the application.
- Select Lathe Mode for turning or leave it disabled for milling.
- Configure WCS, home and tools when the program requires them.
- Refresh the execution result.
- Inspect the trajectory, playback, diagnostics and statistics.
- Export FULL, EXPANDED or DXF when required.
The normal document encodings are UTF-8 and Windows-1251. The GUI opens .ptp files by default and tries Windows-1251 if UTF-8 decoding fails; saving preserves the detected encoding. The CLI exposes the supported encodings through --encoding.
Yes. Words do not need spaces. Blocks such as:
G18G21G40G54G80G99
G0X100Z5
are parsed as address words rather than relying on whitespace splitting.
Both common forms are recognized:
(COMMENT)
; COMMENT
A persistent comment-style option controls generated text exports. Reading source programs is not limited to the selected output style.
A source block beginning with / is marked as optional.
With Ignore Block Skip enabled, the complete block is excluded from execution, including:
- motion;
- Macro B assignments;
- signals;
- subprogram or macro calls.
With the option disabled, it executes normally.
ExecutionResult.ok describes whether execution avoided a fatal modeled error. ExecutionResult.complete indicates whether the kernel considers the resulting execution trace complete enough for consumers such as export.
A program can therefore retain trustworthy motions before an unsupported or invalid block while still being marked incomplete.
A diagnostic can contain:
- a stable code such as
UNSUPPORTED_G_CODEorUNDEFINED_MACRO; - a human-readable message;
- severity;
- status such as verified, unverified, unsupported, malformed or resource-limited;
- source line;
- offending raw block.
The kernel does not assume that the old position remains trustworthy. For turning, an unsupported position-changing command can create an unknown-axis gap. Trace publication resumes only after later absolute coordinates establish a known position again.
This prevents a misleading connector line from being drawn through an unknown region.
An unsupported G-code that can affect geometry is treated more seriously than a non-geometric control code. For example, an unsupported code on a block containing X/Z/U/W can make the block unsupported rather than merely unverified.
Y-axis motion is not modeled in fanuc_turn and produces UNSUPPORTED_AXIS.
The core tracks modeled program-control and machine signals. Batch/analyze mode additionally reports literal turning M-codes that are not modeled as UNSUPPORTED_M_CODE warnings instead of pretending that their machine effect is known.
Yes. Supported modal groups are checked for conflicts within one block. A conflict such as two mutually exclusive motion, plane, unit, compensation, feed, spindle or transform modes produces MODAL_GROUP_CONFLICT and the block is not silently interpreted using source-order luck.
Yes. The default execution budget protects against runaway macros, recursive calls and pathological cycles:
| Resource | GUI default |
|---|---|
| Executed blocks | 500,000 |
| Subprogram/macro calls | 10,000 |
| Generated motions | 2,147,483,647 |
| Auto update max segments | 2,147,483,647 |
| Cycle iterations | 100,000 |
| Macro loop iterations | 100,000 |
| General call depth | 64 |
Cancellation is checked through the same budget mechanism. Resource exhaustion produces a structured RESOURCE_LIMIT-style result instead of an unbounded run.
Macro B is part of the execution runtime, not a text substitution preprocessor. Expressions are evaluated while the program executes, so loops, branches, subprogram calls and variable state affect the real logical motion trace.
The same Macro B runtime is used by turning and milling.
Numeric variables:
#1
#100
#500
#13001
Named variables:
#<NAME>
#<TOOL_RADIUS>
Indirect references:
#[#1]
#[100+#2]
#[FUP[#[ROUND[#3]]]]
Indirect assignment is also supported:
#1=100
#[#1]=5
#[#1+1]=#100+2
The indirect destination must resolve to an integer variable number.
#0 is permanently vacant.
It cannot be assigned:
#0=123
produces INVALID_MACRO_ASSIGNMENT.
Vacant values are distinct from numeric zero for equality tests:
IF[#1 EQ #0] GOTO10
is the normal way to detect an omitted/vacant local argument.
In arithmetic, a vacant value behaves as numeric zero. Assigning a vacant value clears the destination variable:
#100=#0
After that assignment, #100 is vacant rather than stored as numeric 0.
A normal numeric reference to an undefined variable fails closed with UNDEFINED_MACRO.
The special null-aware comparison behavior is used where FANUC vacant semantics are required, such as comparisons to #0.
The expression evaluator supports ordinary arithmetic and FANUC-style relational/logical tokens used by the project fixtures, including:
+ - * /
MOD
EQ NE GT GE LT LE
AND OR XOR
Brackets may be nested:
X[#100+5]
#10=[[#1+#2]*#3]
Compact expressions such as #1LT#3 are accepted. AND/OR/XOR convert operands to integers and apply bitwise arithmetic; they do not use Python truthiness. Comparisons return numeric 0/1.
The evaluator rejects exponentiation (**), strings, bytes, containers and boolean constants. Limits are 4,096 source characters, 512 AST nodes and depth 64; expression arithmetic uses finite floating-point constants. LN requires a positive argument; EXP overflow produces an execution diagnostic. BIN/BCD/ADP remain explicitly unsupported because their controller-specific semantics were not verified against local references.
The current evaluator includes:
ABS
SQRT
SIN
COS
TAN
ATAN
FIX
FUP
ROUND
MIN
MAX
LN
EXP
Trigonometric arguments and results follow FANUC-style degree semantics.
Two-argument FANUC arctangent syntax is supported:
ATAN[y]/[x]
For example:
#119=ATAN[0.75]/[1.625]
ROUND uses FANUC-style nearest-integer rounding with .5 away from zero.
Yes. An N block label may precede a Macro B flow statement or assignment:
N900 #151=7
Labels are indexed once for flow execution.
Yes:
GOTO100
...
N100 ...
A missing target produces FLOW_TARGET_MISSING.
Yes:
IF[#1 EQ 2] GOTO900
IF[[#2*#11] GT 360] GOTO16
Conditions are evaluated at runtime using the current variable state.
Yes:
#1=0
WHILE[#1 LT 3] DO1
#1=#1+1
G1 X#1 F100
END1
Nested loop IDs are indexed before execution. Missing END, unmatched END, runaway loops or an exhausted macro-iteration budget produce diagnostics rather than hanging the application.
Yes. The regression corpus includes Macro B programs that generate:
- repeated boss milling;
- face milling;
- hole milling;
- thread milling;
- nested loops;
- large deterministic arc counts;
- indirect variable access.
These execute through the normal milling kernel rather than a separate test interpreter.
Yes. G65 P... calls an O macro program and creates a proper macro-local scope.
Example:
G65 P7700 X0 Y0 M48 S5. D1 R50. Z-70. Q4. V8. I860. A7.5 B15. H24. K1. E100. F200.
The called macro can then use the mapped local variables #1..#33.
The current Type I mapping is:
| Address | Local variable |
|---|---|
| A | #1 |
| B | #2 |
| C | #3 |
| I | #4 on first occurrence |
| J | #5 on first occurrence |
| K | #6 on first occurrence |
| D | #7 |
| E | #8 |
| F | #9 |
| H | #11 |
| M | #13 |
| Q | #17 |
| R | #18 |
| S | #19 |
| T | #20 |
| U | #21 |
| V | #22 |
| W | #23 |
| X | #24 |
| Y | #25 |
| Z | #26 |
G, L, N, O and P are control words and are not bound as ordinary local arguments.
Repeated I/J/K words use FANUC Type II-style sequential local slots. Each occurrence advances by three:
I -> #4, #7, #10, ...
J -> #5, #8, #11, ...
K -> #6, #9, #12, ...
Up to 10 occurrences of each I/J/K address are accepted in one G65 call.
No. On a G65 call, words such as M, S, T, X, Y, Z and F are macro arguments, not simultaneous spindle, tool, motion or feed commands.
For example, T7 or M8 inside a G65 argument list does not create a tool-change or coolant signal.
Local variables are scoped.
On macro entry, the caller's local variables are saved and replaced by the call arguments. On M99, the caller's local values are restored. Common and named variables remain shared.
The Macro Variables inspector reflects the active local scope while playback is inside the macro and shows the restored caller values after return.
L repeats the macro call. The accepted range is 1..9999.
Each repetition starts again with the original G65 local arguments. Changes made by the previous repetition to #1..#33 do not leak into the next repetition.
The current implementation allows four nested G65 local-variable levels. A deeper macro nesting request produces CALL_DEPTH_EXCEEDED rather than silently sharing a damaged local scope.
The wider M98/G65 call-stack budget is separately limited by the general call-depth setting.
An M98 subprogram call inside a G65 macro shares the current macro-local level. It does not create another G65 local scope by itself.
Yes.
Typical form:
M98 P2000
M98 P2000 L3
...
O2000
...
M99
P must identify an existing positive integer O-program number. L must be a positive integer. Missing targets and invalid values produce structured subprogram diagnostics.
No. M99 P is controller-profile dependent and currently produces UNSUPPORTED_M99_P rather than guessing its jump semantics.
Yes. ExecutionStep.variables contains an immutable snapshot of the variable state for that occurrence of a source block. Unchanged snapshots are internally reused rather than copied for every motion.
This is what allows the GUI Macro Variables inspector to follow logical playback without re-running the CNC program.
Expanded Execution follows the actual executed occurrence order. Macro flow and G65 calls are resolved into their resulting execution rather than exported as a second unevaluated macro program.
Subprogram/macro boundaries are preserved as execution events/comments where appropriate, while generated motion comes from the authoritative trace.
The turning interpreter supports FANUC Type A (default) and Type B. Select Type B in Options under Lathe G-code system, or pass --lathe-gcode-system B to a CLI command. Type B uses G90/G91 for absolute/incremental X/Z, G33 for threading, G77/G78/G79 for simple cycles, and G94/G95 for feed per minute/revolution. Type C, G66/G67 modal macro calls and G68.2/G53.1 indexed-plane operations are outside the current turning language.
| Operation | Type A | Type B |
|---|---|---|
| Rapid | G00 | G00 |
| Linear | G01 | G01 |
| Arc CW | G02 | G02 |
| Arc CCW | G03 | G03 |
| Dwell | G04 | G04 |
| Thread cutting | G32 | G33 |
| Coordinate system / spindle clamp | G50 | G92 |
| Finish cycle | G70 | G70 |
| Rough turning | G71 | G71 |
| Rough facing | G72 | G72 |
| Pattern repeating | G73 | G73 |
| Face peck drilling | G74 | G74 |
| OD/ID grooving | G75 | G75 |
| Multiple threading | G76 | G76 |
| Turning canned cycle | G90 | G77 |
| Threading canned cycle | G92 | G78 |
| Facing canned cycle | G94 | G79 |
| Feed per minute | G98 | G94 |
| Feed per revolution | G99 | G95 |
Type A uses absolute X/Z and incremental U/W. Type B uses G90/G91 to switch X/Z between absolute and incremental; U/W remain incremental.
Turning uses X/Z geometry. Internally, physical X geometry is radial, while programmed X can follow diameter or radius programming.
The default turning state is diameter programming.
XandZare absolute-axis words where the active mode requires absolute programming.UandWare incremental turning-axis words.- X/U conversion respects diameter versus radius mode.
Cycle expansion uses the same conversion helpers rather than treating cycle X values differently from ordinary motion.
The kernel normalizes physical geometry to millimetres internally.
G20sets inch input scaling;G21sets millimetre input scaling.
The selected unit mode is captured per execution step so playback, statistics and export can reconstruct the executed unit context.
Turning uses G18 XZ circular interpolation with:
- relative or absolute I/K center coordinates, selected by Arc Type or auto detection;
- R radius programming.
Resolved arcs store analytical center, radius, sweep and direction in physical geometry.
R-programmed profile arcs remain R arcs during G71/G72/G73 roughing and G70 finishing, regardless of the selected I/K interpretation. If an I/K arc in a P/Q profile is invalid in the manually selected mode, the associated cycle emits no partial trajectory and reports the source line.
The physical G18 orientation and the visual X/Z plot orientation are not the same coordinate view. The kernel resolves the physical arc direction and the plotting layer uses the correct XZ convention rather than treating it as XY geometry.
Yes. On ordinary G1 turning blocks, A-angle programming can resolve a missing X or Z endpoint using the previous contour direction and programmed angle.
Yes. Ordinary G1 contour blocks can include:
Ccorner chamfers;- corner
Rfillets.
This is distinct from G2/G3 R, where R is the circular interpolation radius.
Yes. G32/G33 are represented as synchronized threading motions in the resolved trace. Threading state is preserved into export and Stock Removal where applicable.
For turning:
G98 -> feed per minute
G99 -> feed per revolution
The default turning feed mode is per revolution.
Per-revolution machining time is only known when a trustworthy spindle speed is also available. Otherwise statistics report unknown time rather than inventing a feed rate.
Yes.
G96 -> constant surface speed (CSS)
G97 -> direct RPM mode
In CSS mode, the S value is stored as surface speed. In inch mode the source surface-speed value is converted to metres per minute internally.
G50 S... is tracked as the spindle-speed limit used with the turning spindle model. It is not treated as the milling G50 scaling cancel operation.
Yes. M3/M4 mark the spindle running and M5 marks it stopped. Machine signals such as spindle, coolant, dwell and program end are also published in ExecutionResult.signals.
The kernel supports:
G54-G59;G54.1 P1-P99extended offsets;G10 L2programming of G54-G59;G10 L20programming of G54.1 offsets.
Runtime G10 changes are returned in the execution result and do not silently write application settings.
Yes, for non-modal machine-coordinate G0/G1 motion.
A turning G53 G2/G3 cannot be modeled by the current contract and produces UNSUPPORTED_G53_MOTION instead of being executed as a WCS-relative arc.
When configured reference-return emulation is enabled, G28 resolves the intermediate programmed point and then emits the configured machine-home motion. Reference-return events are also recorded structurally.
No. The project does not silently reuse the configured G28 home as a second reference point for G30. A controller-specific G30 reference must not be invented from G28 configuration.
G40/G41/G42 state is tracked in turning. When a valid configured turning tool with usable nose geometry is available, the resolved trace can be compensated deterministically.
The compensation layer works from executed motions and tool geometry rather than rewriting source text.
If the required geometry cannot be established safely, the result is not presented as verified compensated motion.
The current turning cycle layer includes:
| Type A | Type B | Purpose in the kernel |
|---|---|---|
| G70 | G70 | P-Q finishing contour |
| G71 | G71 | Longitudinal roughing |
| G72 | G72 | Facing roughing |
| G73 | G73 | Pattern-repeat roughing |
| G74 | G74 | Z peck / face grooving |
| G75 | G75 | X peck / radial grooving |
| G76 | G76 | Two-line multipass threading |
| G83 | G83 | Axial peck drilling |
| G84 | G84 | Axial tapping |
| G90 | G77 | Modal longitudinal turning cycle |
| G92 | G78 | Modal threading cycle |
| G94 | G79 | Modal facing cycle |
Cycle geometry is expanded into ordinary logical motions. Those motions are then consumed by playback, statistics, Stock Removal and export.
Yes. Generated motions are marked as cycle-generated and retain source ownership such as the invoking block, source text and playback group where applicable.
This is why one source cycle block can own many logical playback motions without losing editor navigation.
P/Q contour cycles resolve N labels in the parsed program. The resolver handles repeated labels relative to the cycle call site rather than assuming every N label is globally unique.
For finishing, a preceding P-Q profile can be preferred where appropriate.
Yes. The P-Q contour is built as profile segments and can include supported linear and circular geometry. Analytical arc data is preserved where possible rather than converting every profile arc into a staircase.
G70 P... Q... builds the referenced finish contour and approaches it from the actual G70 call position.
The finish path is based on the nominal P-Q profile, not the roughing-offset profile used by G71/G72/G73.
If tool-nose compensation is active and can be verified, the finishing contour uses the compensated profile.
After the finish group, the cycle returns to the saved call position using the project's deterministic turning return order.
The common two-line FANUC form is modeled:
G71 U... R...
G71 P... Q... U... W... F...
The first line captures rough depth and retract. The second line supplies the P-Q profile, finishing allowances and feed.
The first-line U depth is treated as a radial depth and converted consistently into programmed diameter motion when diameter programming is active.
An empty P-Q profile or zero first-line depth produces an explicit G71 diagnostic; no partial cycle trajectory is published.
The second-line U and W are applied to the roughing profile before rough passes are generated.
U is signed. This matters for OD versus ID work:
- positive U leaves outside material on an OD contour;
- negative U can leave material toward the bore interior on an ID contour.
The sign is not discarded by taking an unconditional absolute value.
The cycle compares the stock-side approach and profile geometry and selects boring versus outside behavior. The same P-Q contour engine is used, but pass direction and retract direction follow the selected material side.
Type I is treated as monotonic longitudinal roughing. Each rough pass is parallel to Z and terminates at the P-Q roughing profile.
After the roughing passes, the implementation adds one complete pass along the already allowance-offset roughing profile. It does not incorrectly reuse the nominal finishing contour at this stage.
A Type II profile is detected when the first P block contains both an X/U component and a Z/W component.
The implementation can follow non-monotonic/pocketed profile geometry using clipped profile segments. Controller-dependent cases are handled conservatively; unsupported geometry is not silently simplified.
G72 uses the same P-Q profile infrastructure as G71 but performs facing roughing in Z planes.
Typical two-line form:
G72 W... R...
G72 P... Q... U... W... F...
The first line captures axial depth and retract. The second line references the profile and finishing allowances.
No. Type II is supported where the facing plane resolves to a deterministic profile span. If one facing plane produces multiple disjoint material spans that require controller-specific interpretation, execution fails explicitly with:
UNSUPPORTED_G72_TYPE_II_SPANS
instead of choosing an arbitrary span.
An empty profile, zero pass depth, or a lone interior crossing after a closed Type II span also produces an explicit diagnostic. No cuttable Type II facing span is reported as an error rather than an empty expansion.
Repeated intersections at the same endpoint of a closed contour count as one crossing. Distinct, disjoint spans still produce UNSUPPORTED_G72_TYPE_II_SPANS.
G73 is implemented as repeated shifted copies of the roughing profile.
The first line captures the total U/W pattern displacement and the R pass count. The second line provides P/Q, finish allowances and feed.
The signs of programmed U/W are preserved. The cycle does not infer displacement direction from where the tool happened to approach the contour.
G74 supports Z-direction peck behavior and face-grooving style repetition.
A first block containing R alone can establish the retract distance. The executing block can use X/U and Z/W plus P/Q/R/F parameters.
If no X target is supplied, G74 can operate as a drilling-style Z peck at the current X.
When X repetition is requested, P controls the X step and Q controls Z peck depth. The cycle returns to its saved start using an explicit Z-first return order.
G75 performs X-direction peck/radial grooving.
P controls the radial peck step. Q can repeat grooves along Z. If Q is omitted, a programmed Z/W selects one groove location rather than being treated as an invalid zero-step repetition.
The R value from the setup block controls retract distance, and the executing-block R value is handled as the bottom allowance where applicable.
The kernel emits actual feed and rapid primitives for each peck/retract sequence. It does not store G74/G75 as an opaque cycle that the renderer has to understand separately.
The modeled form is FANUC-style two-line G76:
G76 P...... Q... R...
G76 X... Z... P... Q... R... F...
The first block stores:
- packed P control digits;
- minimum radial increment Q;
- optional finish allowance R.
The second block supplies:
- final thread X;
- final Z;
- thread height P;
- first cut Q;
- optional taper R;
- lead F.
The first-block Q and second-block P/Q are treated as integer least-input increments rather than ordinary floating length words.
For metric turning they are converted in thousandths of a millimetre. Inch mode uses the corresponding 0.0001-inch increment converted to physical millimetres.
The thread passes use a decreasing-depth / approximately constant-chip-area progression based on the first-cut depth and square-root pass relationship, while respecting the minimum radial increment and finish allowance.
The final commanded X is authoritative for the final thread diameter.
The packed first-line P is decoded as:
P(m)(r)(a)
where the fields represent:
- final/spring-pass count;
- chamfer amount in tenths of pitch;
- tool/thread angle.
The supported set is:
0, 29, 30, 55, 60, 80 degrees
Other packed angles fail explicitly with:
UNSUPPORTED_G76_TOOL_ANGLE
For supported nonzero angles, pass start/end Z is shifted to model FANUC-style single-edge flank infeed rather than ignoring the angle digits.
The packed chamfer digits are converted into an axial chamfer length based on thread lead. The final part of each thread pass is split when necessary to represent the chamfer section.
Yes.
Example:
G92 X18 Z-10 F1.5
X17.5
X17.0
The initial G92 establishes the thread end and lead. Subsequent X/U-only blocks continue the active G92 cycle with new depths until another explicit motion/cycle mode cancels it.
Each pass expands to approach, synchronized longitudinal cutting, retract and return primitives.
Yes. G90 establishes a longitudinal rectangular turning cycle. Subsequent X/U-only blocks can continue the active cycle at new diameters until cancellation by another explicit motion/cycle code.
Yes. G94 establishes a facing rectangular cycle. Subsequent Z/W-only blocks can continue the active cycle at new face positions until cancellation.
A non-motion modal code such as G96/G97 does not cancel the active cycle.
Another explicit motion or cycle code cancels the old modal turning cycle unless that same cycle is explicitly present in the block.
Yes. G83 and G84 remain active for subsequent eligible coordinate blocks until G80, another cycle state, or a tool change cancels them.
G83 is an axial Z drilling cycle.
- If Q is supplied, Z pecks are generated.
- If Q is absent, the kernel does not invent peck depth; it emits one feed stroke to depth and a rapid return.
- Optional X positioning is handled before the axial stroke and restored afterward.
G84 is an axial tapping cycle. The downstroke and return are synchronized feed motions; the return is not represented as a rapid move.
No. Dwell is a time/control event, not a spatial segment. The backplot geometry therefore does not invent a motion for the dwell itself.
The runtime can report an UNCLOSED_CYCLE-class execution error rather than silently carrying an impossible modal cycle to program end.
This table lists the G codes recognized by the fanuc_mill kernel. Details and limits are explained below.
| G code | Function in the kernel |
|---|---|
| G00 | Rapid positioning |
| G01 | Linear interpolation |
| G02 / G03 | Clockwise / counterclockwise circular interpolation |
| G04 | Dwell signal; no spatial motion |
| G10 | Program WCS offsets (L2, L20) |
| G15 / G16 | Cancel / enable polar coordinate programming |
| G17 / G18 / G19 | Select XY / XZ / YZ plane |
| G20 / G21 | Inch / millimetre input units |
| G28 | Reference return using the configured home |
| G40 / G41 / G42 | Cancel / left / right cutter-radius compensation |
| G43 / G49 | Track / cancel tool-length state; G43 does not apply H geometry to the plotted path |
| G43.4 | TCP G0/G1/G2/G3 motion for the angled AC/BC table profiles, including Cartesian arcs with rotary interpolation; combination with G68.2 is unsupported |
| G50 / G51 | Cancel / enable coordinate scaling |
| G52 | Local coordinate shift |
| G53 | Non-modal machine-coordinate motion |
| G54–G59 | Select work coordinate system |
| G54.1 P1–P99 | Parsed and selected; the GUI has no offset setting, so the offset is zero unless the program sets it with G10 L20 |
| G65 | Call a Macro B program |
| G68 / G69 | Enable / cancel coordinate rotation |
| G68.2 / G53.1 | Tilted working plane / tool-axis orientation (3+2, fanuc_mill with two-axis table-table, head-head or head-table kinematics) |
| G73 | High-speed peck drilling cycle |
| G80 | Cancel canned cycle |
| G81 | Drilling cycle |
| G82 | Drilling cycle with dwell |
| G83 | Full-retract peck drilling cycle |
| G84 | Tapping cycle |
| G85 | Boring cycle with feed return |
| G86 | Boring cycle with spindle-stop signal |
| G90 / G91 | Absolute / incremental programming |
| G94 / G95 | Feed per minute / feed per revolution |
| G98 / G99 | Return to initial / R plane in canned cycles |
| M code | Function in the kernel |
|---|---|
| M00 / M01 | Stop / optional-stop signal |
| M02 / M30 | End program |
| M03 / M04 / M05 | Spindle clockwise / counterclockwise / stop signals |
| M06 | Tool-change event for the selected T number |
| M07 | Recognized; no machine-specific coolant action is modeled |
| M08 / M09 | Coolant on / off signals |
| M19 | Spindle-orientation signal; S on this block is an angle, not spindle RPM |
| M29 | Prepare rigid tapping; S on this block sets spindle RPM for the following G84 |
| M98 / M99 | Call / return from subprogram |
Unknown M codes produce UNSUPPORTED_M_CODE warnings. Recognized M codes describe trace signals and program flow; they do not simulate machine hardware.
M29 S500 followed by G84 marks rigid tapping in the trace. With G95, F1.5 is 1.5 mm per revolution in metric mode; with G94, the equivalent feed at 500 RPM is F750 mm/min. G80 clears the rigid-tapping preparation. M29 syntax and whether it is required depend on the machine configuration. The kernel records synchronization semantics but does not simulate an encoder or spindle acceleration.
The milling kernel supports XYZ rapid, linear and circular/helical motion in the active G17/G18/G19 plane.
Resolved TraceMotion is full 3D geometry even though many CNC constructs are planar.
Select a profile in Settings → Rotary kinematics or pass --kinematics PROFILE_ID with --lang fanuc_mill in the CLI. The GUI selection is stored as CNC/ROTARY_KINEMATICS. The profile maps programmed A/B/C addresses to signed rotary axes. G90 assigns an absolute rotary angle; G91 adds an increment. For the checked table profiles, later XYZ motions, resolved arcs and milling cycles are transformed into the fixed WCS display frame, and playback orients the tool preview at the resolved tool-tip point. WCS axes themselves do not rotate.
G28 reference return and non-modal G53 use machine-axis coordinates first, including repeated returns and G91 increments, then map their trace points into the indexed display frame. The active WCS remains selected after G53. An A/B index records an event and changes subsequent geometry; the kernel does not currently generate a sampled tool-tip sweep during the rotary movement. The plot omits a connector across that position change.
For the checked 4ax_table_c profile, concurrent X/C feed blocks and C-only blocks map their endpoints into the fixed XY plane. Here X is the programmed radius and C is the angle about Z; the source program provides the contour sampling. These blocks record ROTARY_MOTION rather than an index event.
The 4ax_table_a and 4ax_table_b profiles have been compared with the programs in tests/fixtures/milling/indexed_table_a.nc and tests/fixtures/milling/indexed_table_b.nc. The 4ax_table_c profile is checked against tests/fixtures/milling/indexed_table_c.nc: its X/C contour overlays the program's first XY contour within 0.05 mm at the sampled endpoints. The fixture files are reference inputs, not definitions of a machine. Automated checks also cover A/B angle signs, G90/G91, and repeated G28/G53 behavior.
The catalog also contains head, mixed head/table and other two-rotary-axis profiles. They remain in JSON with enabled: false and are hidden from the GUI. The enabled profiles are 4ax_table_a, 4ax_table_b, 4ax_table_c, 5ax_table_ac_angled and 5ax_table_bc_angled; None is the default selection. The angled AC/BC tables support indexed 3+2 through G68.2/G53.1. The schema does not specify rotary pivot locations, tool-center-point behavior or controller-specific offsets.
The JSON editor validates a profile and saves it to rotary_profiles.json beside the user's config.ini. It does not change the installed catalog. A selected profile defines the table/head axis and sign explicitly; the software cannot infer those properties from an A, B or C word. Execution steps retain the selected WCS and the configured rotary angles. G10 L2 and WCS changes preserve the current machine position after a table index.
If the user profile file is damaged or invalid, the GUI and JSON editor open with the installed profiles. Saving a valid edit recovers the override file and preserves its original bytes in a neighboring rotary_profiles.json.invalid-*.bak file. Valid edits retain the other valid overrides. Kernel and CLI loads remain strict until the file is repaired.
A changed A/B/C address without a selected profile or an address absent from the selected profile stops milling execution with an explicit diagnostic. Simultaneous rotary/XYZ movement and non-rapid rotary interpolation also stop for the indexed A/B profiles; the checked 4ax_table_c planar X/C feed contour is the exception. This is the current implementation, not a general FANUC restriction. A/B/C with an unsupported position-changing G-code also stops execution. Unknown M-codes and G41/G42 that cannot be verified because of missing tool or unsupported contour data produce warnings and let execution continue. G30 is not modeled as G28: its controller-specific second reference point is not inferred from the configured G28 home.
For 4ax_table_c, G41/G42 cutter compensation is unsupported. Execution continues, but the X/C plot shows the programmed tool-tip path without cutter-radius offset and reports UNSUPPORTED_TABLE_C_CUTTER_COMPENSATION. G40 cancels the modal request. Do not treat this plot as a verified compensated contour.
A selected profile makes the calculation repeatable; it does not by itself prove that the profile matches a physical machine. Inspect diagnostics and the supported contract before using ok or complete as an export decision.
The current set includes:
G73
G80
G81
G82
G83
G84
G85
G86
The common cycle runtime returns generated geometry, modal updates, signals and final position as one outcome.
G73 is high-speed peck drilling with short intermediate retract behavior. G83 returns to R between pecks, then rapidly re-enters at clearance d above the previous depth before continuing at feed. Reentry is limited to the R plane. The kernel option milling_g83_clearance sets d in millimetres, including inch programs; it must be finite and non-negative. The default 1.0 mm is a modeling assumption because the controller setting cannot be read from the program. This changes G83 feed distance and cycle-time statistics; turning G83 and native SINUMERIK CYCLE83 keep their separate behavior.
For milling drilling cycles, a depth above R reports INVALID_DRILLING_DEPTH. Z equal to R remains valid and produces no drilling feed stroke.
G82 includes its dwell semantics, but dwell itself does not create spatial geometry.
G84 tapping returns from depth as synchronized feed motion rather than rapid motion.
The cycle models spindle-stop semantics together with its drilling motion/return behavior.
For milling canned cycles, G98/G99 select cycle return behavior. They are not the turning feed-mode meanings of G98/G99.
For milling:
G94 -> feed per minute
G95 -> feed per revolution
Statistics only compute trustworthy machining time where the required feed/spindle information is known.
The kernel supports:
G54-G59;G54.1 P1-P99;- runtime
G10 L2; - runtime
G10 L20.
For runtime work-offset programming, incremental mode updates the existing selected offset instead of silently replacing it with the raw incremental value.
G52 X/Y/Z sets a local coordinate-system shift for subsequent motion. The G52 control block itself does not move the tool.
G68 enables coordinate rotation around the programmed center in the active plane. G69 cancels the rotation.
In SINUMERIK ISO-M mode (G291), the modeled G68 subset requires G90 and has no I/J/K vector. G68 with G91 angle semantics or with any I/J/K 3D rotation vector is recognized but unsupported. G69 remains supported.
The active transform applies to later endpoints and I/J/K arc vectors. Enabling or cancelling the transform does not itself create a motion segment.
G68.2 X/Y/Z I/J/K defines a 3+2 tilted working plane with Z-X-Z Euler angles. Select a kinematics profile with two distinct rotary axes first; supported topologies include table-table, head-head and head-table. G53.1 must be the next standalone block: it solves the selected profile's rotary angles to align the physical tool axis with functional +Z. An unreachable orientation stops with a diagnostic. G69 cancels the plane while retaining the indexed rotary position. This model applies only to fanuc_mill. Explicit A/B/C addresses during the tilted plane and simultaneous G68 rotation are unsupported. G53 and G28 reference motions use machine coordinates. Expanded NC export is unavailable for these programs; Full Program preserves the source.
Milling G51 supports:
- uniform scaling with P, where
P1000means factor 1.0; - per-axis factors through I/J/K.
G50 cancels milling scaling.
For SINUMERIK ISO-M, G51 uses the modeled 0.001 scale-factor weighting (P2000 means a factor of 2.0). Machine-specific alternative weighting is not modeled.
The scaling center is interpreted as absolute coordinates even under G91, and omitted center axes use the current position.
Axis-specific scaling of an arc can turn a circle into non-circular geometry. The kernel reports that unsupported case instead of approximating it as a circle.
Yes. G53 is non-modal machine-coordinate motion. It does not overwrite the active WCS for later ordinary work-coordinate blocks. An absolute zero axis target such as G53 Z0 resolves to the configured machine home on that axis; non-zero absolute and incremental targets retain their machine-coordinate meanings.
Yes. The configured reference-return path is resolved through the execution kernel rather than handled only by the GUI. For indexed milling, the intermediate and home targets are resolved on machine axes before their trace points are transformed for display. G91 G28 Z0 returns the Z axis to the configured home Z.
With 4/5-axis table kinematics, G28/G53 use the current table orientation without resetting ABC. For example, with home Z=500 and zero WCS offset, a B-table return targets global Z=500 at B0 and Z=-500 at B180. A Z-only reference segment that crosses the WCS centre plane stops execution with an error; check machine home Z and the WCS offset. This check does not detect collisions with a part model.
After G28/G53 in a 4/5-axis program, the next approach can start a separate trace segment in the new table orientation. No connecting line is drawn between those segments. Ordinary three-axis paths remain continuous, including reference returns.
For fanuc_mill, continuous G0/G1 tool-center motion with simultaneous linear and rotary axes is supported on the angled AC and BC table profiles. Activating TCP preserves the current physical point in the plotted trace. With TCP off, indexing retains programmed XYZ and changes the displayed table frame. G2/G3 TCP arcs may interpolate configured rotary axes while programmed XYZ remains the authoritative tool-center path; start/end tool orientations and rotary events are retained. Combining TCP with G68.2 remains unsupported. This is toolpath interpretation, not a complete machine or collision simulation.
Milling supports:
- relative IJK center offsets;
- absolute IJK center coordinates;
- R radius programming.
The selected source interpretation is resolved into one analytical arc center/radius/sweep representation.
When enabled, the kernel examines milling or turning IJK arcs in source occurrence order before final geometry resolution. Turning X and I values are converted from diameter coordinates to physical radial coordinates for this comparison.
For each IJK arc it compares relative and absolute-center interpretations using the configured arc tolerance. The first unambiguous candidate fixes the IJK mode for that execution.
R-only arcs are ignored during detection because they do not distinguish IJK conventions.
If every candidate is ambiguous, the selected fallback mode is used. CLI analysis/batch currently use relative IJK as the fallback.
Selecting an Arc Type in the GUI manually overrides auto detection for the current document. The Auto Detect setting remains enabled for the next opened document. In turning, an I/K arc interpreted with the wrong center mode reports INVALID_TURNING_ARC_CENTER; selecting Radius mode for an arc without an R word reports TURNING_ARC_REQUIRES_R.
Yes. Arc-type detection determines the IJK interpretation. An R-only block remains an R arc regardless of that decision.
Yes. Analytical full circles are represented directly by the kernel.
When Expanded Execution is asked to emit R-format arcs, a full circle is exported as two exact R semicircles because one R block cannot uniquely represent a full circle.
Yes. Circular interpolation can include motion along the axis normal to the active plane where the supported geometry contract permits it.
G16 enables milling polar-coordinate endpoint programming and G15 returns to ordinary Cartesian programming.
The active G17/G18/G19 plane determines the polar plane:
- first in-plane axis = radius;
- second in-plane axis = angle in degrees.
In absolute mode, the active work/local origin is used as the pole. Programmed polar radius and angle are absolute polar values.
When entering G91 G16, the current position becomes the pole. Later G91 polar words increment modal radius or angle, and omitted components retain their previous polar value.
No. The radius is a length and follows units. The angle remains degrees.
The implemented polar circular contract requires R radius programming. I/J/K center programming while G16 polar mode is active is rejected with an explicit diagnostic rather than guessed.
No.
G40/G41/G42 uses configured milling tool diameter and works on supported line, arc and compatible helical contours.
For indexed table A/B milling, the offset is calculated in the local programmed working plane before the completed geometry is transformed into the fixed WCS plot. Execution continues when the tool or contour cannot be verified, with UNVERIFIED_CUTTER_COMPENSATION reported. The 3D view uses left drag to pan and middle drag to orbit around the cursor, as in CNCEditor; the table B 3D/ISO preset shows +Y vertically upward, +X upward-right and +Z downward-right while table A keeps the vertical mill preset.
For 4ax_table_c, G41/G42 is not resolved. The trace retains the programmed X/C tool-tip coordinates and emits UNSUPPORTED_TABLE_C_CUTTER_COMPENSATION; G40 ends the modal request. This limit is specific to the current C-table implementation.
The compensation engine resolves:
- entry transitions;
- steady offset geometry;
- line/arc and arc/line joins;
- corners;
- G40 exit transitions.
Inserted transition motions preserve execution-step ownership so editor navigation and export remain coherent.
The source requested G41/G42, but the kernel could not prove a valid compensated path with the available tool/configuration/geometry.
The system marks that state explicitly rather than presenting uncompensated geometry as verified compensation.
No. G43/G49 and H values are tracked for execution/export context, but H-offset geometry is not currently applied to the resolved toolpath.
That limitation is intentional and should not be interpreted as a simulated tool-length-compensated machine position.
Turning and milling tools are stored in:
%LOCALAPPDATA%\easy-gcode-plot\tools.db
This SQLite database is authoritative for Saved Library tools.
Current Program is temporary state for the open CNC program. Literal T selections can be discovered from source and assigned geometry without modifying the persistent library.
The operation identifies the fallback tool type first. A matching T number in the corresponding Saved Library then supplies the actual geometry, including its saved type and dimensions. If no valid matching record exists, discovery uses source comment dimensions and the operation-based default. Milling T02 matches T2; turning T202 matches T0202, while different packed offsets remain distinct. Manual Current Program edits take priority on subsequent recalculations.
Saved Library is persistent and is committed to tools.db only when the Tool Library window is accepted.
No. Tool discovery is temporary.
Turning selections retain the packed tool/offset form such as:
T0909
Milling selections use the tool number, for example T03 becomes tool key T3.
Yes. Tool discovery recognizes useful inline and nearby comments, for example:
(T3 D=6. CR=0. - FLAT END MILL)
(OD ROUGH R0.8)
(ID ROUGH R0.8)
(GROOVE H4)
(DRILL)
(TAP)
(THREAD)
(BALL)
(FACE MILL)
(CHAMFER)
Dimensions are interpreted using the units active at the tool selection.
Operation context supplies a practical temporary default where possible:
- milling G81-G83 -> drill;
- milling G84 -> tap;
- native SINUMERIK CYCLE81/CYCLE82/CYCLE83 -> drill;
- native SINUMERIK CYCLE84 -> tap;
- turning G32/G33/G76/G92 -> thread tool;
- otherwise standard milling or turning fallback geometry.
Native cycle classification uses the controller AST, including modal MCALL, cancellation and tool changes. Cycle names in comments or MSG text do not classify an operation. An operation's type takes priority over a conflicting comment type hint; an automatically matched saved tool keeps its own geometry. The preliminary scan does not execute macros or infer physical dimensions from a toolpath. CLI/API callers can supply a library snapshot through execute_program(..., library_tools=...); execution does not load a local SQLite library implicitly.
Shared GUI/CLI execution builds Program/AST once, resolves tools from that same object before motion execution, and then calculates the trace. Discovery does not run another frontend pass. The Cython/Python scanner still extracts source comments and literal tool candidates; it does not independently execute controller operations.
Finding a saved tool or assigning a default does not guarantee verified compensation. UNVERIFIED describes an unproven compensated path, not merely an unknown tool. G41/G42 can remain unverified with missing geometry, an unsupported tool or an invalid entry/path, including native SINUMERIK named tools without matching numeric geometry. Operation-based defaults existed before automatic library lookup.
No. Discovery intentionally does not evaluate T#1 or T[expr]. Literal tool discovery and full CNC execution are separate concerns.
The turning library uses nine canonical geometry types:
- Diamond 80;
- Diamond 35;
- Square;
- Round;
- Triangle;
- Groove;
- Thread;
- Drill;
- Tap.
OD, ID and Face are UI filters for available tracing orientations, rather than different geometry classes. They do not choose the material-removal side or change Stock Removal results for the same trace and physical geometry.
The milling tool model includes flat, bull-nose, ball, tapered ball, face, slot, chamfer, drill and tap geometry.
The milling editor stores two metric lengths:
fluteLength: cutting length measured from the tip; must be greater than zero.bodyLength: non-cutting length from the end of the cutting portion to the holder; may be zero.
Length to holder is fluteLength + bodyLength and is read-only in the editor. The compatibility field length is derived from this sum; there is no shaftLength. The Inches switch changes display units; SQLite and JSON/CSV exports retain millimetres.
For face and slot mills, fluteLength sets the cutting head height; cuttingHeight is retained only for legacy records. For tapered ball mills, the taper ends at fluteLength, followed by a cylindrical body extending to the holder. Both library and playback previews use this geometry.
The library preview shows the cutting part in gold and the non-cutting body in gray. In 3D, the default cutting color is yellow; the body is near-white in the dark theme and dark gray in the light theme to distinguish it from gray STL models. The tool color option changes only the cutting part. Tools without an explicit length split use one color.
Existing tools with only length keep their total and preview without an inferred split. The editor identifies these records as legacy. Editing unrelated fields keeps the unsplit record; entering cutting/body lengths defines the new partition. Loading the library does not rewrite the database.
Tool comments can supply both dimensions, for example (FLAT END MILL D10 FL25 BL15). Comment dimensions follow the units active at tool selection. A comment providing only L/LENGTH retains an unsplit total. Automatically discovered tools without length dimensions use editable defaults, not measured dimensions.
No. CLI runs use the same temporary source-based tool discovery used for a newly opened program. GUI manual Current Program assignments and the Saved Library are not silently loaded into the CLI execution.
This matters for G41/G42 verification: inferred tool dimensions should be reviewed before treating a compensated CLI trace as authoritative.
The left side is a QScintilla editor with syntax highlighting, line numbers, search/replace and cleanup functions. The right side is an OpenGL trajectory view with axes, grid, camera controls, trajectory picking and playback.
The milling 3D view uses an orthographic CAD projection. Rotating from Top, Front or Left keeps parallel lines parallel and preserves apparent size across depth.
In solid mode, the STL surface hides toolpath segments behind it. The feature-edge wireframe has no solid surface to occlude those segments. This changes only visibility in the plot, not the resolved trajectory geometry. Manage imported models in Settings → STL Objects; the guide below covers transforms, sections, picking and measurements.
The Settings → STL Objects dock edits imported STL scene objects without changing the G-code program. Import a model with File → Import STL. The dock lists each imported model; select a row before applying an operation. Choose Base point, Position, Transform, Circular array, Rectangular array or Section from the operation selector. The four compact buttons at the top apply Undo, Redo, Statistics and Delete to the STL scene.
Use File → Import STL to load an ASCII or binary mesh. File → Recent STL reopens a recent model. Each import appears as a separate row in the dock; selecting a row makes it the target of the operation controls and statistics. Delete removes the selected model. File → Clear STL removes all STL models. These commands affect imported scene objects, not the editor contents or G-code trajectory.
The STL Undo and Redo history is separate from text-editor undo. It records scene edits such as adding another model, changing a base point, moving, rotating, mirroring, scaling, creating arrays, applying or clearing a section, and deleting an object. The first imported model establishes the scene baseline, so Undo does not close the panel or remove that first model. Statistics opens copyable measurements for the selected object. Delete removes only the selected row; use File → Clear STL to remove the complete STL scene.
The Base point selector chooses the point used as the pivot for rotation, mirroring and scaling:
- Center sets it to the center of the source mesh's bounding box.
- Bounding-box corner sets it to the source mesh's minimum X, Y and Z corner and displays the transformed object's axis-aligned bounding box in the Base Point color.
- Origin sets the point to model coordinates
(0, 0, 0). - Custom enables the X/Y/Z fields; enter coordinates in model space and press Set base point.
When the bounding box is displayed, its eight corners are picking points. Hold Shift and left-click a corner in the 3D plot to move the base point there. The picked point becomes larger and cyan; the other seven corner markers remain in the Base Point color. Picking changes the base point to a custom point, while keeping the box visible so another corner can be picked. Choosing Center or Origin exits bounding-box picking.
The Position page shows the current base point's world position. Enter a target X/Y/Z there and use Move base point here to place the pivot at those world coordinates. Moving changes the object's transform while preserving its shape.
On Transform, select an axis and angle to rotate around the current base point. Mirror reflects the object across the plane whose normal is the selected X, Y or Z axis, passing through the base point. Scale applies a uniform factor around that point. These operations preserve the source STL and update the scene object's transform; they do not modify the original file on disk.
Circular array creates the requested number of copies around a selected axis and center, spread over the total angle. With Rotate copies enabled, each copy rotates with its position. When disabled, each copy keeps its orientation and distributes the current base point around the circle. A full 360-degree array spaces copies evenly without duplicating the first copy at the end.
Rectangular array creates copies along X, Y and Z. Set the copy count and step for each axis; the resulting array includes the original object. Array creation is one STL history action and can be undone.
On Section, choose X, Y or Z for the cutting plane, enter its coordinate and choose which side to keep. The initial coordinate is the midpoint of the selected model's world-space bounding box along that axis. Apply section clips the solid in 3D and closes the cut where the mesh produces a closed contour; the cut model remains visible over the source toolpath. Clear section restores the full STL. Applying and clearing a section are undoable STL scene actions.
Statistics reports surface area, volume, center of mass, world-space coordinate bounds and per-axis lengths. Bounds are written explicitly as Xmin, Xmax and Length (and likewise for Y and Z). The Inches checkbox at the lower left of the dialog converts all reported lengths, coordinates, area and volume while leaving the mesh unchanged. Unchecked values display in millimetres; checked values use inches, square inches and cubic inches.
STL files do not encode a unit system, so these labels are display units and do not determine the source model's real-world scale. Surface area and bounding box are available for open meshes. Volume and center of mass require a closed mesh with consistently oriented faces; otherwise the dialog reports them as undefined.
Use Edit → Uppercase (Ctrl+Shift+U) or Edit → Lowercase (Ctrl+U), or their toolbar buttons, to convert selected text. With no selection, they convert the entire editor document. Their shortcuts can be changed in Options.
Select one or more blocks and press Ctrl+/ to add / at the start of each selected nonempty block. Press Ctrl+Shift+/ to remove one leading / from each selected block. Without a selection, these commands do nothing. Both shortcuts are fixed and cannot be assigned to another command. The slash is the FANUC optional block skip marker; whether such blocks execute depends on the Block Skip setting.
Use File → Print (Ctrl+P) or the Print button in the File toolbar. The app prints sharp vector lines in the current camera orientation, fitted to a landscape page. Printing ignores the playback slider and does not hide lines behind an imported STL. In Options → Plot, you can show or hide rapid moves, render them dashed or solid, and color all moves by tool; Print follows those choices. FAQ opens with F3, and Grid toggles with F4 by default.
Top, Front and Left are orthographic views. The ordinary 3D view is perspective. Starting free orbit from a fixed view returns to perspective.
Playback advances through resolved logical motions from the current ExecutionResult. It does not re-parse each source line as the slider moves.
They move by one logical motion, including generated motions from cycles and Macro B-expanded execution.
One source block can emit many motions. Examples include:
- turning cycles;
- milling canned cycles;
- Macro B loops that execute the same source line repeatedly;
- compensated transition geometry.
Playback tracks execution occurrence and source ownership separately.
Use Shift+Click near the trajectory. The application selects the owning source block and moves the logical-motion slider to the corresponding motion.
Normal execution/plot refresh is intended to update the result without using editor caret movement as a side effect. Playback/navigation can intentionally select source locations.
Auto Update has a sampled-segment limit. Large edits may be left pending until explicit Refresh so typing remains responsive.
If source changes while a refresh is running, the stale calculation is cancelled/ignored and a new refresh is queued.
The execution dialog covers the expensive source-to-result pipeline, including reading, parsing, execution, tool discovery, trace sampling and final plot publication. Cancellation is cooperative and checked throughout the execution budget.
The GUI contains:
- Hole Calculator;
- Pocket Calculator;
- Snippets.
Hole and Pocket Calculator are milling-only. Snippets is available in both machine modes.
It generates coordinate blocks for circular or rectangular/grid hole patterns. It does not invent the complete surrounding drilling-cycle safety logic.
It can generate circular or rectangular milling fragments with configurable stepover, depths, safe/reference Z, feed, direction, clearing strategy, helical entry and finishing pass.
The generated fragment is a starting point, not a machine-safety certification.
On Windows, snippets are normally stored in:
%LOCALAPPDATA%\easy-gcode-plot\snippets.db
Older text snippets can be imported once while the original files are retained as backup.
An unreadable or invalid UTF-8 legacy snippet is skipped with a log warning; valid files are still imported. The skipped original remains in the backup directory. Invalid ordering metadata falls back to filename order.
Open Settings → Options → General. In Language, choose English or Russian, then press OK. Restart Easy G-Code Plot to apply the language change; the application displays a restart notice. This setting changes the interface language, not the CNC dialect used to execute a program.
Open Settings → Options → General, select Light or Dark in Theme, and press OK. The theme is applied immediately without restarting. Language and theme choices are saved in the application configuration.
Open Settings → WCS. This is a separate dialog from Options.
| Setting | How to use it |
|---|---|
| G54–G59 | Enter the X/Y/Z work offsets for each system. The program selects the active system with its G54–G59 command; editing a row does not insert that command into the program. |
| Home (G28) | Enter the configured reference-return coordinates and use the home configuration checkbox to indicate whether they are configured. These values are used by the modeled G28 return. |
| Turning X/Z | In turning mode, X fields use diameter values; Y fields are disabled. Z is an axial coordinate. |
| Milling X/Y/Z | In milling mode, all three coordinate fields are available and X is a linear coordinate. |
| Inches | Switch the displayed and entered lengths between millimetres and inches. Existing physical values are converted rather than reinterpreted as another unit. |
Press OK to apply the values and recalculate the program. Cancel leaves the stored values unchanged. G54.1 extended offsets have no fields in this dialog; they remain zero unless set by supported program commands such as G10 L20.
In turning mode, open Settings → Stock. Enter the initial blank dimensions before starting Stock Removal.
| Control | Meaning |
|---|---|
| Outside diameter | Initial outside diameter of the blank. |
| Inside diameter | Initial bore diameter; use zero for a solid blank. |
| Length | Axial length of the blank. |
| Stock front Z | Absolute Z coordinate of the front face. The rear face is at front Z − length; this field is not just an allowance thickness. |
| Accuracy | Stock-model resolution. Higher accuracy gives a finer model and requires more processing time. |
| Inches | Display and enter dimensions in inches instead of millimetres, preserving their physical size. |
| Run Stock Removal when Play is pressed | Enable material-removal playback when pressing Play. |
| Reset to Auto | Return to dimensions estimated from the current program's cutting trace. |
Press OK to apply manual dimensions; Cancel discards the dialog edits. Manual dimensions remain active until Reset to Auto, New, or opening another program restores automatic sizing. Stock Removal requires a calculated, complete turning program and configured tool geometry. See Turning Stock Removal for automatic sizing and supported tools.
No. Material removal is currently implemented for turning only. Milling does not yet have stock-removal simulation.
For milling reference geometry, load an STL model and open Settings → STL Objects. The panel provides model positioning, rotation, copying, arrays, sections and statistics. It displays reference models alongside the toolpath; it does not subtract milling tool motions from the STL. See the Interface, editor and playback section for the panel workflow.
It is an axisymmetric material-removal preview based on the resolved turning trace and configured cutter geometry.
It is not a machine simulation.
The resolved G1/G2/G3 cutting trace provides the minimum outside diameter and length. Rapid G0 outliers are ignored, cycle-generated cutting motions are included, and G18 arc extrema are evaluated analytically.
Yes. Settings → Stock allows explicit outside diameter, inside diameter, stock length, absolute front-face Z and accuracy/resolution. See How do I set turning stock dimensions? for the fields and playback setting.
Manual values persist until Reset to Auto, New or opening another program returns the stock model to program-derived sizing.
The supported turning tool geometries include the nine canonical tool-library types. Stock Removal follows the resolved trace, tracing orientation and physical cutter geometry. OD/ID/Face checkboxes only filter the tracing choices in the tool editor; changing these filters does not change removal for the same trace and cutter geometry.
The cutter's bounded swept footprint removes only the material it intersects. Separate remaining material rings are retained, including the outside wall during G71 boring. Stepping backward and replaying the same motions restores the same stock section. For grooves, Groove geometry selects radial or face geometry independently of these checkboxes.
Synchronized G32/G33, modal G92 and G76 cutting motions use a deterministic longitudinal thread-section model rather than sweeping the complete insert body as a generic solid.
The programmed X defines root depth, F defines pitch/lead, and configured thread geometry shapes the section.
The displayed thread insert is a separate fixed silhouette shared by Tool Library and the Stock Removal overlay: a triangular body with three small 60-degree cutting teeth and recessed shoulders. Its active tracing point is anchored to the programmed tool position. In the standard lathe view, the external P8 vertex points down and the internal P6 vertex points up.
Only the insert diameter scales this silhouette. The reference contour is D12; entering D20 scales every coordinate by 20 / 12, approximately 1.667. EX, RC and the thread profile angle do not deform the displayed body. The angle remains part of the removal calculation but is hidden in the editor; the library summary shows the tracing orientation. These display changes do not rewrite SQLite tool records.
No. It does not model chuck, turret, fixtures, acceleration or full machine geometry.
Statistics are derived from the resolved trace and include:
- logical motion counts;
- length breakdown;
- known and unknown machining time;
- average feed;
- assumed rapid speed;
- XYZ bounds;
- per-tool sections.
The Statistics window displays an HTML summary. Use the tool selector to switch between the whole program and one tool. Export HTML saves the summary and all tool sections with the same selector and the current display units. Only the exported report adds a static SVG projection below the table: XY for milling, XZ for turning. The tool selector also filters the drawing. The GUI export uses the same prepared geometry, page fitting and line styles as Print. Every motion is included. The NC source is not embedded.
The Inches display switch converts displayed values without changing stored physical geometry. CLI equivalent: python -m app analyze program.nc --html statistics.html (add --inches for imperial display).
The kernel avoids fabricating a physical feed rate. A common case is feed-per-revolution motion without a known spindle RPM.
Tokens displays parsed/evaluated words, source position, execution status and diagnostics. Suspicious or unsupported rows are highlighted and can be exported to CSV.
Macro Variables shows the variable snapshot at the current logical playback position.
It follows:
- assignments;
- loops;
- G65 local scopes;
- M98 execution inside a macro;
- restored caller locals after M99.
It uses existing execution snapshots and does not re-run the CNC program while the playback slider moves.
If no execution result exists, there is no variable history to show. If the source editor has changed since the displayed execution result, the result is stale and the variable inspector waits for Refresh rather than mixing new source with old runtime state.
The program has three NC/geometry export families:
- FULL — source-preserving NC normalization;
- EXPANDED — resolved geometry/state through a controller post profile;
- DXF — toolpath geometry.
Tool List and Statistics reports are separate report exports, not NC export modes.
No. FULL uses the exact source together with its authoritative execution map. EXPANDED and DXF consume resolved execution geometry/state. None of them runs a second CNC interpreter.
FULL preserves ordinary source blocks, comments, modal commands, controller dialect and supported cycles. Flow/label-dependent constructs are unfolded from the execution map before renumbering: evaluated Macro B, IF/GOTO/WHILE, G65 and M98/M99 calls, and FANUC turning G70–G76. FULL does not convert the program to another controller.
EXPANDED is the controller-conversion path. One generic postprocessor emits resolved geometry and machine state through a JSON profile. Cycles, variables and subprogram flow have already been executed. Target profiles define syntax, mandatory frames, capabilities and defaults; they do not disable user output options.
Bundled profiles are fanuc_mill, fanuc_mill_multiaxis, fanuc_lathe_a, fanuc_lathe_b, sinumerik_iso, sinumerik_840d and sinumerik_840d_multiaxis; an external JSON path can be supplied with --post-profile. The *_multiaxis profiles declare supports.axes X/Y/Z/A/B/C and emit explicit resolved rotary coordinates; the three-axis profiles stay XYZ-only and still reject rotary geometry.
Auto (source controller) is not a separate capability mode. It automatically selects the post profile that matches the source controller and dialect: FANUC turning uses the Type A/B lathe profile, FANUC milling uses fanuc_mill, SINUMERIK ISO uses sinumerik_iso and native SINUMERIK uses sinumerik_840d. EXPANDED always re-serializes the resolved execution, so even "Auto" is a conversion; it simply does not require you to name a target.
Modal Feed controls whether F is restated: Yes emits F only when the feed or feed mode changes, No restates F on every cutting motion.
Yes. EXPANDED treats Target CNC as the target syntax/post profile, not as a capability switch. Coordinates (G90/G91), sequence numbers, delimiter, leading zero, modal feed, decimal precision, force decimal, plus sign, arc output and start/end program text remain available and are honored for FANUC → FANUC, FANUC → SINUMERIK ISO, FANUC → SINUMERIK native and SINUMERIK → FANUC. A profile default applies only when you did not choose a value. If a profile declares a mandatory prefix (for example G290/G291), that prefix stays physically first and your start text follows it. A profile is only consulted for genuine capability limits: rotary/TWP/TCP, a missing axis or an unsupported arc/feed state.
DXF contains the available resolved motion geometry. Rapid and cutting motions use separate layers. Turning uses the plot-aligned Z/X representation; milling writes 3D lines and analytical arcs/circles where representable, with sampled polylines for geometry that cannot be represented as one DXF arc.
No. The DXF writer consumes motion geometry and does not interpret controller words or NC formatting options.
Shared export options include:
- absolute/incremental coordinates where supported;
- sequence numbers;
- sequence start and increment;
- sequence-number spacing;
- spaces/no spaces between words;
- leading zeroes (
G01versusG1); - comments/no comments;
- safety line (the profile's declared safe restart block);
- decimal precision, force decimal and plus sign;
- start and end program text;
- milling arc representation.
For EXPANDED these options are user-owned: the target profile supplies syntax and a default only for values you do not set. A profile-defined mandatory frame stays first and your start text follows it.
The profile's format.words object gives every frame token an order and a required flag: motion, X, Y, Z, A, B, C, I, J, K and R. required=true emits the address whenever it has a resolved value (for example Y0 instead of omitting zero Y); required=false allows the serializer's normal omission of an unchanged value. motion.required=false makes the motion code modal, so G1 is restated only when the motion changes. Per-word decimals/sign are stored in the same object. An axis entry is only accepted when that axis is declared in supports.axes, and F is deliberately excluded because feed is controlled by Modal Feed. Address requiredness is a property of a specific post/controller, so it lives only in the profile and has no separate GUI/CLI switch.
The CLI contract exposes:
auto
ijk-relative
ijk-absolute
radius
linearized
auto uses the post profile convention. The four explicit modes are relative IJK, absolute IJK, radius and linearized. Source arc syntax has already been resolved before posting. Native SINUMERIK profiles render absolute centers as I=AC(...) / J=AC(...) / K=AC(...) and radius arcs as CR=.
It is emitted as two exact semicircular R arcs.
Yes. Unit conversion is applied to resolved geometry/state at the postprocessor boundary. Coordinates, arc geometry, I/J/K or radius output, feeds and supported controller state are emitted in the requested units and replay-tested by the export suite.
FULL remains source-preserving and therefore accepts only --units auto.
No. CLI Full Program export currently accepts only --units auto.
Semantic unit normalization is an Expanded Execution feature.
DXF can be emitted in millimetres or inches. auto keeps the current default DXF behavior, which is millimetres.
Yes. --no-comments removes source comments from FULL and suppresses source comments carried into EXPANDED. EXPANDED comment syntax comes from the selected post profile.
Yes. The CLI export service writes to a temporary file in the output directory and then replaces the final output path. A failed write does not intentionally leave a partially written final file.
No. Source and output must be different paths.
Arc-center interpretation follows the executed controller mode: native and ISO-M (G291) use incremental IJK centers; native I=AC/J=AC/K=AC explicitly selects absolute centers. Mixed G290/G291 input resolves each arc in its active mode; document arc settings and automatic detection do not override these semantics. Configured native rotary axes are supported by the bounded TCP/indexing subset; rotary A/B/C in G291 remains rejected.
Structured execution and CLI/batch reports include source_dialect (fanuc or sinumerik) independently of the shared fanuc_mill geometry language. This identifies the source family, not one controller mode for the entire mixed program. Unsupported SINUMERIK G/M diagnostics contribute concrete codes to batch summaries; unsupported syntax and features do not become fabricated G/M entries.
The SINUMERIK scope is visualization of trajectories using native commands and cycles emitted by CAM postprocessors. Full support for the complex internal Siemens macro language is outside scope; implementing it is not feasible for a project maintained by one person. Executing subprograms from SDI mode is currently unavailable. Opening an SPF file is supported as a document, but arbitrary Siemens subprogram invocation is not.
MPF/SPF documents preserve the selected rotary profile. Settings and Options remain available. Native CYCLE800/TRAORI supports the angled AC/BC table profiles; incompatible profiles, axes and ISO-M rotary commands produce kernel diagnostics.
The application supports a bounded native Siemens milling subset (G290, also the initial mode of MPF/SPF files) and ISO Dialect M (G291). Both use the shared milling kernel and resolved trace. SINUMERIK ISO Dialect T is not supported.
| Native function | Current behavior |
|---|---|
G0/G1, G2/G3, G17/G18/G19 |
XYZ positioning, linear moves and arcs in the selected plane; CR= radius arcs, including negative radius for a major arc |
G90/G91, G54–G59 |
Absolute/incremental coordinates and work offsets |
G70/G71 |
Inch/metric lengths; feed units remain unchanged |
G700/G710 |
Inch/metric lengths and feed units; modal numeric F is retained |
G93 |
Inverse-time feed: each cutting motion takes 1/F minutes, including rotary TCP motion; F must be positive. Reprogram F when switching G93/G94/G95. Cycles and cutter compensation are unsupported in G93 |
G40/G41/G42 |
Modeled cutter-radius compensation using the configured tool |
DIAMON/DIAMOF/DIAM90 |
Warning-only; all coordinates are executed with DIAMOF semantics |
CHF/CHR/RND/RNDM/FRC/FRCM |
Parsed with warnings; no geometry/feed changes. Chamfers, rounding and corner feed are not simulated. RNDM=0 is recognized without geometric effect; resolved NC export is rejected |
G60/G64 |
Exact-stop / continuous-path metadata; acceleration, stop time and blending are not simulated |
G500 |
Modal work-offset deactivation with coordinate rebasing; zero G500/base frame by default, API wcs_offsets[500] can supply translation; OEM base-frame rotations, mirroring and scaling are not modeled |
DEF REAL, direct scalar assignments |
Bounded underscore-named DEF REAL scalars used by CAM setup and direct scalar assignments are accepted |
T, M6, D0..D12, S, basic M codes |
Tool change, modeled cutting-edge selection/cancellation, spindle and coolant signals; controller-specific offset tables are not simulated |
Named tools with M6 |
Named tool changes are accepted; if cutter geometry is unavailable, G41/G42 remains unverified rather than assuming a radius |
G0 SUPA ... D0 |
Nonmodal absolute XYZ and configured A/B/C positioning, independent of G91. In the application's reference-coordinate model, zero XYZ addresses use the configured G28/SUPA return coordinates, as FANUC G53 does. WCS and the current rotary frame determine the displayed return. Rotary zero means A/B/C=0; SUPA G0 B0 C0 D0 requires a compatible BC profile |
G64, MSG(...), WORKPIECE(...), ; comments |
Path-control/display metadata and comments; no blending or stock geometry is generated from these declarations |
SETMS(1), FNORM, COMPOF, CYCLE832 |
Accepted CAM setup/control statements; CYCLE832 is ignored without geometry or display events |
MCALL CYCLE81/82/83/84(...) |
Modal Z drilling/tapping in G17/G40, triggered by subsequent XY blocks; bare MCALL cancels the cycle |
CYCLE81/82 |
Drilling and rapid return, with modeled seconds-based dwell for CYCLE82; safety plane is RFP + SDIS, return plane is RTP; the four-argument CYCLE81 form is accepted |
CYCLE83 |
Modeled first depth, amount degression, minimum peck depth, chip-breaking/full-retract options and reentry clearance |
CYCLE84 |
Single-pass metric right-hand tapping in G94: explicit positive PIT, _PITA=0/1, SDAC=3, Z axis and positive SST equal to programmed S; equal SST1 or zero/omitted. Feed = pitch × rpm; feed withdrawal to RFP+SDIS, rapid return to RTP, optional dwell in seconds |
TRAORI / TRAFOOF |
GUI/CLI/kernel TCP via the common angled AC/BC table core; G0/G1/G2/G3 with configured numeric A/B/C and R references; incremental IC supported; DC selects the shortest absolute rotary approach, while an exactly 180-degree ambiguity is rejected |
CYCLE800 |
GUI/CLI/kernel static frames: modes 57/54/39/27/30/45, ST200000/200001/220000/220001, DIR-1/0/1; legacy 15-argument ST0/R_DATA calls are accepted; active-frame reset via empty/bare call or TC="0" |
Native CR radius arcs require a SINUMERIK source document: use .mpf/.spf. A .nc or unsaved document uses FANUC syntax and cannot interpret CR= as a native radius address. Native X/Y/Z=IC(...) is incremental independently of G90/G91. MSG() is accepted.
CYCLE84 accepts the 24-argument CAM call and shortened numeric declarations. Depth uses DP or positive relative DPR in compatibility mode; explicit absolute-depth AMODE=2/1001002 requires DP. Deep tapping, MPIT/thread tables, nonmetric pitch units, spindle orientation/technology options, left-hand tapping and unequal entry/withdrawal speeds are outside this subset and produce diagnostics. Spindle synchronization/reversal is represented by logical signals, without angular spindle simulation. The parameters follow Siemens section 1.7; paired fixtures tapping_sin840d.mpf / tapping_fanuc.nc verify G84 geometry and native trace replay.
Cython accelerates contiguous literal position runs, with per-block capability validation before state changes. Controller-specific declarations and G290/G291 switches interrupt the current run, after which eligible positions resume acceleration. Positions inside an active MCALL cycle stay on the Python reference path until cancellation. Metadata or a native cycle elsewhere in the file does not disable acceleration for the whole program.
Numeric R assignments (R1=500) and direct references in F/S/XYZ/IJK=Rn, CR=Rn, TURN=Rn and supported cycle parameters are available. Siemens R state is independent of FANUC # variables and is fresh for each execution. Undefined references fail before the block changes state; cycle references are validated at declaration and each hole. Arithmetic such as R1=R2+10 or F=R1*0.8, arrays, system variables, Siemens control flow and arbitrary subprogram calls remain unsupported. SPF recognition does not enable subprogram execution.
Native TURN=n adds integer 0..999 complete revolutions to the base G2/G3 arc (IJK or CR, G40, no active MCALL), according to Siemens. The trace keeps one analytical arc/helix with the total sweep. Rendering, playback and statistics retain those turns; DXF uses a sampled polyline, and FANUC/ISO exporters split arcs only during serialization. The existing stock material-removal timeline supports turning; this release does not add milling stock removal. Standalone native G4 F... uses seconds and leaves modal feed unchanged; spindle-revolution dwell is not modeled.
The GUI/CLI/kernel also supports a bounded TRAORI/TRAFOOF TCP subset on 5ax_table_ac_angled and 5ax_table_bc_angled. Configured numeric A/B/C assignments and direct R references follow G90/G91; rotary TCP arcs retain analytical Cartesian geometry and orientation endpoints. The GUI preserves rotary selection and executes native AC/BC programs through the same kernel. CYCLE800 builds its own Siemens rotation matrix and uses the common TWP solver/rebasing. FR0/1/2 are logical retract requests, with no OEM retract trajectory; FR_I must be zero/blank and DMODE0/1 is supported. DIR chooses the principal first-table-joint branch. IC(numeric/direct R) is incremental independently of G90/G91. ORI*, TRANS/AROT, FGROUP, FL[], FGREF[], SPOS, CUT3DC/CUT3DF/CUT3DFF and path-control extensions are parsed with unverified warnings; their effects are not simulated. Arbitrary Siemens subprogram calls remain fail-closed. Cancel TCP before G290/G291; active TCP transitions are rejected. Native MCALL and G41/G42 cannot be activated under TCP, and active MCALL must be cancelled before rotary positioning. No multi-axis controller conversion is enabled.
EXPANDED profiles are tested by re-executing output and comparing geometry, feeds and machine signals. FULL preserves the source dialect.
In G291, common integer milling G codes, unit selection, coordinate systems, selected canned cycles and G50/G51 are accepted. Extended work offsets use G54 P1..P48; source G54.1 and other decimal G codes are rejected, though G54 Pn is normalized internally to the milling kernel's G54.1 Pn form. Ordinary G91 incremental positioning is supported. G68 is limited to a standalone 2D form with G90 active, only the center axes of the active plane and R, and no I/J/K; incremental-angle and 3D-vector forms are rejected. G69 is supported. Macro B flow and unsupported ISO functions stop with diagnostics. G51 uses the modeled P/1000 scale weighting; machine-specific alternative weighting is not modeled.
G290 selects the native subset above; G291 selects ISO-M. Switches must occupy standalone blocks. Cancel native cutter compensation and MCALL before G291; cancel incompatible ISO cycles, transforms and extended offsets before G290.
The GUI Open/Save filters include .mpf and .spf. The CLI and batch scanner include both extensions by default and select SINUMERIK for every .mpf/.spf file independently of its contents; execution starts in native mode and processes standalone G290/G291 switches. Use --lang fanuc_mill for milling analysis; the language option selects the milling geometry model and does not turn on full Siemens support. Mixed folders can still use --extensions to control discovery.
Yes. Choose EXPANDED EXECUTION and the target controller. The postprocessor consumes resolved kernel geometry; sinumerik_iso emits ISO-M with G291, and sinumerik_840d emits native with G290.
.\easy_gcode_plot_cli.exe export fanuc_part.nc --lang fanuc_mill --mode expanded --post-profile app\gcode\export\posts\sinumerik_iso.json -o iso_part.mpfYes, for supported three-axis geometry. Parameters and CYCLE81/82/83/84 have already been executed by the kernel; EXPANDED emits the resulting motions, feeds, dwell and machine signals. Source MCALL and cycle definitions are absent from the output. Rotary/TWP/TCP and unverified geometry-changing commands are rejected.
.\easy_gcode_plot_cli.exe export native_part.mpf --lang fanuc_mill --mode expanded --post-profile app\gcode\export\posts\fanuc_mill.json -o fanuc_part.ncFULL answers “keep this controller program, but normalize it safely.” It preserves ordinary source structure and the source controller/dialect; only execution-flow constructs that cannot safely survive renumbering are unfolded.
EXPANDED answers “emit this executed three-axis result for this controller.” It serializes resolved geometry/state through one of the JSON post profiles. Physical XYZ uses one zero-offset G54 frame; source cycles, macro variables and subprogram calls are not recreated.
.\easy_gcode_plot_cli.exe batch-export C:\Fanuc --lang fanuc_mill --mode expanded --post-profile app\gcode\export\posts\sinumerik_iso.json -o C:\SiemensISO
.\easy_gcode_plot_cli.exe export native_part.mpf --lang fanuc_mill --mode full -o normalized.mpfGUI and CLI use the same FULL / EXPANDED / DXF split. Target-controller selection belongs to EXPANDED. Actual rotary/TWP/TCP geometry is rejected by the current controller postprocessor; a selected kinematics profile by itself does not make an XYZ-only program multi-axis. DXF is an independent geometry output and has no NC post profile.
No. SINUMERIK turning/lathe is not supported yet, in either native mode or ISO Dialect T. Siemens turning execution and conversion to/from FANUC turning are unavailable. SINUMERIK support described here is milling; the supported FANUC turning kernel is a separate mode.
Yes.
The standalone CLI is an interface over the same parser, Macro B runtime, machine execution, cycles, compensation and export modules.
Current commands are:
parse
trace
analyze
batch
export
batch-export
parse executes one program through the normal kernel and prints a readable summary of instructions, motions and diagnostics.
Example:
.\easy_gcode_plot_cli.exe parse program.nc --lang fanuc_turntrace executes one program and can write detailed JSON including resolved motions.
JSON and HTML destinations must differ from the source program and from each other, including aliases of the same file. Collisions are rejected before writing. Input decoding and read/write failures return exit code 2 with an error message. JSON output is committed atomically. GUI program and Tool List export also reject the open source as a destination; use Save/Save As to save source edits.
.\easy_gcode_plot_cli.exe trace program.nc --lang fanuc_turn -o trace.jsonThe exported HTML report always uses a light theme. The Statistics dialog follows the application theme. GUI report and program exports display success or failure notifications after writing. Playback tail highlighting follows the current logical motion, including all its sampled arc segments, using the current-move color from Options; it also works while stepping backwards and during Stock Removal playback.
analyze executes one program and prints trace statistics plus diagnostics. With -o, it writes analysis JSON.
.\easy_gcode_plot_cli.exe analyze program.nc --lang fanuc_mill -o analysis.jsonbatch analyzes every discovered NC file under a directory and writes JSON/CSV reports.
Add --html C:\Reports\html to save a separate statistics report with a tool selector and static XY/XZ SVG for each input, using the same API as single-file analyze. Subdirectories and full filenames are preserved; --inches changes report units. Without --lang, .mpf/.spf select milling SINUMERIK and other files keep the turning default. Explicit --lang overrides this for the whole batch.
.\easy_gcode_plot_cli.exe batch C:\Programs --lang fanuc_mill -o C:\Reportsexport executes one file and sends it through the shared NC/DXF export service.
.\easy_gcode_plot_cli.exe export program.nc --lang fanuc_turn -o expanded.ncbatch-export discovers a directory tree and calls the same single-file export service for every input program.
For indexed A/B programs, choose a profile with --kinematics PROFILE_ID when all files use one machine, or pass --kinematics-map profiles.json for different machines. Both batch and batch-export accept the map. It is a JSON object from input-relative paths to profile IDs, for example {"a.nc":"4ax_table_a","sub/b.nc":"4ax_table_b"}. Use --mode full to preserve the rotary NC words. Without a profile, affected files fail with ROTARY_KINEMATICS_REQUIRED; indexed expanded NC export is also rejected. Full indexed NC is preserved verbatim, so formatting options that would otherwise be ignored are rejected. DXF uses resolved geometry and the selected profile.
.\easy_gcode_plot_cli.exe batch-export C:\Programs --lang fanuc_mill -o C:\NormalizedNo. They use the same ExportRequest, validation and export_file() pipeline.
Directory export is orchestration around the single-file service.
fanuc_turn
fanuc_mill
There is no separate sinumerik --lang value. SINUMERIK MPF/SPF input is detected from its extension independently of its contents, then the milling kernel is selected with --lang fanuc_mill.
Normal successful/acceptable CLI execution returns zero. Failed/incomplete single execution, batch ERRORS, batch NO_FILES and export failures return a nonzero code (currently 2 for the command-level error states).
Use:
.\easy_gcode_plot_cli.exe --helpor command-specific help, for example:
.\easy_gcode_plot_cli.exe batch-export --helpTop-level help also prints the subcommand help sections.
Each discovered file is executed through the same authoritative analysis setup as single analyze.
Per-file reports include:
- status;
ok/complete;- file size and line count;
- motion count;
- executed-block count;
- diagnostic counts;
- unsupported G-codes;
- unsupported M-codes;
- full diagnostic records;
- elapsed time.
For rotary milling, JSON reports also include kinematics_definition and kinematics_fingerprint (SHA-256). They capture the effective profile used by that execution, including normalized table/head axis vectors and their order. CSV reports store the same definition as JSON text. A profile ID alone is not enough to reproduce a calculation when user overrides differ. Reporting does not reload the current catalog after execution.
CLEAN
WARNINGS
ERRORS
NO_FILES
CLEAN means no diagnostics were emitted.
WARNINGS means execution is valid/complete but diagnostics remain.
ERRORS means at least one file is invalid/incomplete or contains an error-level diagnostic.
NO_FILES means discovery found no matching programs.
.nc
.cnc
.ptp
.mpf
.spf
.tap
.txt
Scanning is recursive unless --top-level-only is supplied.
Yes, when the default extension set is used. The scanner also recognizes likely text CNC programs whose first data contains an O-program header or multiple G/M blocks.
Binary-looking files are not treated as NC text.
Yes. Paths are sorted by normalized relative path so the report order does not depend on filesystem enumeration order.
Yes:
--extensions .nc,.tapWhen a custom extension set is supplied, content-based discovery of arbitrary filenames is intentionally not used.
The report aggregates:
- file status counts;
- total diagnostics;
- error and warning totals;
- diagnostic-code frequencies;
- unsupported G-code occurrence/file counts;
- unsupported M-code occurrence/file counts;
- total elapsed time.
The default report names are:
batch_report.json
batch_report.csv
CSV is UTF-8 with BOM for convenient spreadsheet opening.
A read/decode failure becomes a per-file FILE_PROCESSING_ERROR, and processing continues.
Unexpected internal analyzer failures are not intentionally swallowed as fake user diagnostics. Programming regressions should remain visible.
There are no separate preset scripts for ordinary batch analysis. Run the CLI command directly so the input directory and report destination are explicit.
batch-export applies one validated export contract to a complete directory tree.
Typical uses include:
- expanding execution;
- normalizing sequence numbers;
- adding/removing spaces;
- removing comments;
- converting supported resolved programs between mm and inch;
- changing milling arc representation;
- generating a directory of DXF trajectories.
No. Output must be a separate directory.
The output directory may not be the input directory or a child of it, preventing recursive self-processing.
Yes.
Example:
input/
part1.nc
machine_a/
part2.tap
NC output becomes:
output/
part1.nc
machine_a/
part2.nc
DXF output uses .dxf.
The batch is rejected before writing ambiguous outputs. For example, two sibling inputs whose different source extensions would both become the same .nc destination are detected as a collision.
Normal per-file read/export/value failures become an ERRORS file entry and processing continues.
A successfully executed file with diagnostics is exported and marked WARNINGS under the current policy.
An execution that is not ok or not complete does not produce an output file.
The output root contains:
batch_export_report.json
batch_export_report.csv
The manifest includes source/output relative paths, status, motion counts, execution counts, diagnostics, effective output units, effective milling arc type and elapsed time.
Per file:
EXPORTED
WARNINGS
ERRORS
Overall:
CLEAN
WARNINGS
ERRORS
NO_FILES
NC has two modes:
expanded
full
DXF is selected with --format dxf; NC-only mode/formatting controls are rejected when explicitly supplied.
Full Program does not accept explicit:
- unit conversion other than
auto; - arc-type selection;
- coordinate-mode conversion;
- modal-feed control.
The goal is to avoid pretending those transformations are semantically equivalent to Expanded Execution. Safety-line, start/end program text, sequence numbering, delimiter and leading-zero options are applied by FULL because they change text framing, not geometry.
No. Explicit sequence start, increment or spacing requires --sequence-numbers.
Yes. The development tree contains four concrete EXPANDED conversion checks for Windows and Linux:
fanuc_mill_to_sinumerik_native
fanuc_mill_to_sinumerik_iso
fanuc_lathe_a_to_b
sinumerik_native_to_fanuc_mill
They run the built CLI with an explicit JSON post profile and write below tmp/test_export. They do not rebuild the application.
%LOCALAPPDATA%\easy-gcode-plot\config.ini
%LOCALAPPDATA%\easy-gcode-plot\tools.db
Snippets use their own SQLite store under Local AppData.
Application/UI preferences include items such as:
- language;
- theme;
- document encoding;
- editor settings;
- Auto Update;
- maximum generated motions;
- compensation options;
- arc tolerance and milling arc autodetection;
- Block Skip behavior;
- plot colors and geometry display;
- stock settings;
- playback speed;
- hotkeys;
- comment style.
No. tools.db is authoritative. Legacy tool JSON in configuration is not used as a fallback write target for a current database.
When logging is enabled:
%LOCALAPPDATA%\easy-gcode-plot\main.log
DEBUG logging includes additional execution, rendering, camera, option and Stock Removal timing information. Slow stock frames are rate-limited so logging does not create an even larger performance problem.
Check:
- selected machine mode;
- execution diagnostics;
- WCS/home configuration;
- whether the program contains supported motion;
- whether a previous unsupported position-changing block left position unknown.
Inspect the first diagnostic. Common causes include:
- undefined variable;
- missing GOTO label;
- missing O-program target;
- unmatched WHILE/END;
- G65 argument error;
- call-depth/resource limit.
Use Tokens/Macro Variables to inspect the execution state at the relevant logical occurrence.
That is intentional. On a G65 block those words are macro arguments, not machine side effects.
Confirm that:
- G41/G42 is active;
- the selected tool was discovered or configured;
- its geometry is valid;
- the contour type is supported.
Inspect diagnostics for an UNVERIFIED compensation state.
G43/G49 and H are tracked, but tool-length offset geometry is not currently applied to the trace.
Check the sign of the second-line U allowance and whether the contour is OD or ID. The project intentionally preserves signed U semantics.
A facing plane can contain multiple disjoint profile spans whose exact selection is controller-dependent. Such a case is rejected as UNSUPPORTED_G72_TYPE_II_SPANS rather than guessed.
The packed P angle must currently be one of:
0, 29, 30, 55, 60, 80
The M-code is not modeled as a machine effect. Batch keeps the geometric trace while warning that the complete real-machine behavior is not verified.
EXPANDED unit conversion operates on resolved geometry/state rather than scaling source text. If conversion is refused, inspect the reported execution/postprocessor diagnostic (for example unsupported rotary/TWP/TCP or incomplete execution). FULL intentionally supports only --units auto.
The output root must be outside the input directory tree. This prevents exported files from being discovered and exported again during the same run.
Use Refresh. Auto Update intentionally avoids continuously rebuilding a trace above the configured automatic sampled-segment threshold.
The editor text changed after the displayed ExecutionResult was created. Refresh before using execution-dependent information such as Macro Variables or export.
The important packages are:
app/gcode/kernel/api/
app/gcode/kernel/frontend/
app/gcode/kernel/geometry/
app/gcode/kernel/runtime/
app/gcode/kernel/turning/cycles/
app/gcode/kernel/milling/
app/gcode/kernel/milling/cycles/
app/gcode/kernel/compensation/
The frontend owns:
- comment stripping;
- word lexing;
- Macro B-aware expressions;
- flow-node parsing;
- source blocks;
- AST/model construction;
- native parser acceleration.
The lexer is bracket-aware so Macro B function names and GOTO are not misread as CNC address words.
Runtime owns shared execution mechanics such as:
- Macro flow;
- G65 local scope;
- M98/M99 dispatch;
- modal-group validation;
- signals and structural events;
- cycle contracts;
- resource limits;
- turning trace construction;
- cycle expansion orchestration.
Each major cycle has a focused implementation under turning/cycles/, while common dispatch/expansion machinery lives under runtime. This keeps G70-G76 geometry testable without building one monolithic interpreter function.
Milling state, motion execution, polar programming and canned-cycle execution live under the milling package. Native milling execution accelerates selected motion paths without creating different semantics.
Turning tool-nose and milling cutter-radius compensation are deterministic geometry layers applied to resolved source motions.
They do not belong to the OpenGL renderer.
The package is intentionally small:
common.py— shared export options, motion formatting and unit scaling;full.py— source-preserving FULL normalization using source + execution map;expanded.py— the single JSON-profile postprocessor for resolved geometry/state;dxf.py— DXF geometry output;posts/*.json— the five bundled controller profiles.
Single-file CLI orchestration lives in app/gcode/export_file.py; batch_export.py only applies that contract to a directory tree. No export path contains a second G-code interpreter.
It is the shared application setup path used to execute a program with the same tool-discovery and kernel configuration used by GUI/CLI workflows.
It performs deterministic file discovery and repeatedly invokes authoritative execution to construct analysis reports. It does not contain a second G-code analyzer.
It is directory orchestration around the same export_file() service used by single-file CLI export.
The project builds native extensions for:
- frontend parsing;
- selected milling execution paths;
- tool discovery.
The Python contract remains authoritative. Native and Python paths are regression-tested for parity where applicable. app.native caches parser, discovery and executor availability and import reasons. Source checkouts support fallback; frozen releases require all three extensions and fail explicitly if one is absent or its DLL cannot load. No runtime build or dependency installation is performed.
parser_statistics() exposes total/native/fallback blocks for the most recent successful parse in the current context, counting actual fallback callbacks. Uncommon source line separators and oversized literal words use the Python reference parser to preserve parity; ordinary LF/CRLF numeric programs keep the native scanner.
CLI parse/trace/analyze/batch do not load ezdxf. The DXF backend is imported only when DXF export is executed; a missing backend produces a controlled export error.
The kernel imports no Qt bindings: per-user profile paths come from app.paths, while GUI settings remain in app.settings. Execution and parsing do not change process-global garbage-collection settings; execution budgets remain local to their context.
Parsed Block objects are authoritative. A compiled Block-to-AST builder accelerates the same contract as the portable Python builder: AST nodes and first-occurrence N/O label maps are built in one pass. Repeated immutable words share a bounded construction-local cache. The native parser installs its freshly derived canonical AST through a private constructor without rebuilding it; public Program(blocks, ast) construction still rejects disagreement. AST nodes and words remain frozen, and label maps remain immutable defensive copies. Parsing never changes process-global GC settings. Relative synthetic performance guards compare compiled and portable AST construction and their complete parsing pipelines; run them with pytest tests/core/test_ast_acceleration.py -m performance after building the native extension. Application code imports canonical frontend/API/runtime modules; historical aliases remain available for external compatibility.
The core immutable public types include:
Diagnostic;SemanticInstruction;TraceMotion;ArcGeometry;MachineSignal;ExecutionEvent;ExecutionStep;ExecutionResult.
It records one executed occurrence of a source block and includes information such as:
- source block index;
- number of emitted motions;
- unit scale;
- diameter/radius mode;
- absolute/incremental state;
- evaluated words;
- signals;
- position;
- active WCS;
- feed/spindle state;
- Macro B variable snapshot;
- execution events.
This occurrence-level model is essential for loops and subprograms where one source line executes multiple times.
Events describe structural facts that are not ordinary geometry, including program/subprogram boundaries, tool changes and reference returns.
Export can therefore preserve structural execution order without reconstructing it from motion geometry.
Tests are grouped by domain, including:
tests/core/
tests/dialects/
tests/stock/
tests/tooling/
tests/export/
tests/gui/
tests/render/
tests/meta/
The fixture corpus contains representative turning, milling, Macro B, cycle, compensation, WCS and export programs.
uv sync --group dev
uv run pytest
uv run ruff check .
uv run ruff format --check .Project scripts add resource/generated-file and complexity checks around the standard lint commands.
On Windows, run the full test suite and project lint checks from the repository root:
.\scripts\ps1\test.ps1
.\scripts\ps1\lint.ps1The launchers configure the environment automatically: scripts\ps1\start-sandbox.ps1 on Windows, or bash scripts/sh/start-sandbox.sh on Linux/macOS. They run the visible demo by default. Use -Automated / --automated for offscreen mode and -DelayMs 1500 / --delay-ms 1500 to adjust demo pacing. The PowerShell launcher restores previous environment values; the Bash launcher sets overrides only for its child process.
Run the automated sandbox from the repository root in PowerShell:
.\scripts\ps1\test.ps1 tests/gui/test_daily_workflow_smoke.py -q -sFor a visible, paced demo, enable both the Windows Qt platform and demo mode:
$env:QT_QPA_PLATFORM = "windows"
$env:EASY_GCODE_SMOKE_DEMO = "1"
try {
.\scripts\ps1\test.ps1 tests/gui/test_daily_workflow_smoke.py -q -s
}
finally {
Remove-Item Env:QT_QPA_PLATFORM -ErrorAction SilentlyContinue
Remove-Item Env:EASY_GCODE_SMOKE_DEMO -ErrorAction SilentlyContinue
}Setting only QT_QPA_PLATFORM=windows shows the window but does not enable presentation pauses or the final demo summary dialog. The default EASY_GCODE_SMOKE_DELAY_MS is 1000 ms: actions pause for 1 second, major stages/dialogs for 2 seconds, and the final summary for 4 seconds. You can adjust the pacing:
$env:EASY_GCODE_SMOKE_DELAY_MS = "1500"Both modes execute the same assertions. The scenario opens these existing inputs without moving or changing them:
- FANUC milling:
tests/fixtures/milling/fanuc/flange_plate_benchmark.nc, without STL; dark theme, grid/colors and settings persistence, Statistics with a per-tool selector and SVG HTML export, expanded FANUC export and kernel replay. Line width stays unchanged. - FANUC turning:
tests/fixtures/turning/lathe_cycles_example.nc; G71/G76 and real Stock Removal with deterministic rewind/replay. Saved-library geometry takes priority over automatic discovery. - SINUMERIK 3+2:
tests/fixtures/milling/sinumerik/5ax_test.mpfwithstl/test6.stland the AC profile. STL Objects: Base Point Origin, Position Z=-100, Move Here. - SINUMERIK impeller:
tests/fixtures/milling/sinumerik/impeller.mpfwithstl/test7.stland5ax_table_bc_angled. STL Objects: Transform rotates Z by +90 degrees, then Section Y at zero, Apply, Undo, and STL edges only. The sandbox editor uses saved T60 taper-ball-mill geometry with D1. Play briefly, then seek in 10% slider steps through completion. Turning Stock Removal and the flange benchmark retain complete continuous playback.
Pytest isolates settings, the tool library and all output files in temporary directories. The sandbox's fixed T0303 P2 record is in that temporary library, not the user's configured SQLite. File pickers receive predetermined paths; application dialogs and actions remain real. Unexpected message boxes fail the stage instead of hanging. Assertions inspect widget/model/scene state, not OpenGL pixels. Both modes print stage results; demo mode also displays a timed final summary and identifies the failed stage if an assertion fails.
See GUI sandbox for the complete stage contracts and platform notes.
No. .ui and .qrc sources are authoritative. Regenerate through the project scripts.
Windows:
.\scripts\ps1\generate-qt.ps1Generated modules are build artifacts.
.\scripts\ps1\build.ps1The build produces separate GUI and CLI executables plus SHA-256 checksum files.
bash scripts/sh/build.shFor console-only packaging after tests have already passed:
bash scripts/sh/build.sh --console --skip-tests
./dist/easy_gcode_plot_cli --help
(cd dist && sha256sum -c easy_gcode_plot_cli.sha256)Yes. Native/release tooling uses a persistent .venv-build rather than replacing or pruning the developer .venv.
The native build checks tracked .pyx and dependency state and can reuse the build environment when nothing relevant changed.
The release workflow runs the full tests and static checks on Linux and Windows before packaging. Both packaged CLIs are smoke-tested with --help; Linux is archived with a SHA-256 sidecar, Windows publishes GUI/CLI hashes, and the release job downloads both artifacts before creating or updating the tagged GitHub Release.
No. Windows and Linux artifacts are platform-specific builds even though they share the same Python/kernel implementation and CLI contract.
Easy G-Code Plot is distributed under the MIT License. See LICENSE.md for the full text.