Derive per-path line height and extrusion width for Cura gcode - #459
Closed
sophiedeziel wants to merge 4 commits into
Closed
sophiedeziel wants to merge 4 commits into
sophiedeziel wants to merge 4 commits into
Conversation
sophiedeziel
added a commit
that referenced
this pull request
Sep 7, 2026
- State.trackE applies a move's E parameter to the extruder position and returns the extruded filament length: the parameter itself in relative mode, the difference with the tracked position in absolute mode. G92 E resets already set state.e directly and compose naturally with both. - New M82/M83 handlers switch State.relativeExtrusion; the default is absolute, matching the Marlin firmware default. Only the E accounting consults the mode: whether a move extrudes is still classified from the raw E parameter, so no existing rendering changes. - linearMove tracks E on every command, including zero-length retract/prime moves, and resolves the move's physical endpoint before touching the state (groundwork for deriving dimensions from the segment). arcMove keeps the extruder position in sync too, so a linear move after an arc measures its extruded length from the right position.
- SlicerMetadataParser gains derivesExtrusionDimensions and parseFilamentDiameter, both defaulting to no-ops; dialects that announce exact ;WIDTH:/;HEIGHT: comments are unaffected. - CuraMetadataParser opts in: Cura emits no dimension comments at all, so per-path width and height can only be reconstructed from the moves. The volumetric UltiGCode flavor is excluded (its E values are mm3 of material, not mm of filament). - The filament diameter is read from the header ;FLAVOR: line only: Griffin is exclusive to Ultimaker's 2.85mm machines. Cura's own material_diameter setting sits in the ;SETTING_3 blob at the end of the file, after every move it would apply to; using it would reach a one-shot parse before any move executes but a streamed parse only after every move already ran, breaking streamed/one-shot equivalence, so it is deliberately not used. - Parser.parseGCode forwards both as metadata.deriveExtrusionDimensions and metadata.filamentDiameter, evaluated once on the chunk that identified the slicer, like detectSlicerName.
- Job.deriveMoveDimensions runs on every extruding linear move when the metadata asked for derivation, before continuePath — so a derived change breaks the path exactly like a ;WIDTH:/;HEIGHT: comment would, and the derived values take the same render-time precedence over the global fallback (they are the path's own values). - Layer height is the Z step between consecutive extrusion moves; the first move's Z stands in for the first layer. Comparing extrusion Zs only makes z-hop travels invisible; a zero step (ironing) or a step outside 0.01-1.0mm (spiralize's micro-climb, sequential objects) keeps the current height while re-anchoring the reference Z. - Width comes from conservation of volume with a rectangular deposit cross-section — width = deltaE x filament cross-section / (length x height) — matching the box profile ExtrusionGeometry extrudes. The filament cross-section comes from metadata.filamentDiameter (1.75mm when unannounced). Results are quantized to 0.01mm and held within a 2% relative tolerance of the current width so E-value rounding noise cannot shatter the model into micro-paths; implausible results (outside 0.1-2.0mm, or over a segment shorter than 0.05mm) are discarded so the path falls back to the global setting. - All derivation state (extruder position, last extrusion Z, current derived dimensions) lives on Job/State, which persist across streamed chunks: the ingestion-equivalence harness gains a Cura fixture whose layer change and width shift land mid-chunk in every chunked mode. - Round-trip tests generate Cura-style gcode from known target dimensions via the inverted volumetric formula and assert the derived per-path values recover them, covering adaptive layer heights, z-hops, G92 E resets, relative extrusion (M83), ironing and spiralize.
Security review finding: coordinates and E values that are individually finite (and so survive the parser's param validation) can overflow the derivation's intermediate arithmetic — Math.hypot to Infinity, or NaN via Inf - Inf — and Infinity/Infinity makes the width NaN, which a plain less-than range check waves through and latches into the state, breaking the path on every extruding move after it. Guard the length with Number.isFinite and write the width plausibility check in inclusive form (matching the height check) so NaN is rejected.
sophiedeziel
force-pushed
the
cura-derived-dimensions
branch
from
September 7, 2026 06:50
cd83148 to
388e983
Compare
4 tasks done
|
Visit the preview URL for this PR (updated for commit 388e983): https://gcode-preview--pr459-cura-derived-dimensi-w10oi6dl.web.app (expires Wed, 07 Oct 2026 06:51:15 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: 59bd114ae4847b32c2bba0b68620b9069a3e3531 |
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Derives per-path line height and extrusion width for Cura-sliced files, which announce no
;WIDTH:/;HEIGHT:comments — heights come from the Z steps between extrusion moves, widths from conservation of volume (ΔE × filament cross-section / (length × height), rectangular deposit matching whatExtrusionGeometryrenders).Stacked on #458.
Five first-layer lines printed at 1.2 / 0.9 / 0.6 / 0.4 / 0.25 mm, same camera in both shots:
Heights come out of the Z steps, so the tower's three tiers stack visibly differently — 0.3 mm at the bottom, 0.2 mm in the middle, 0.1 mm on top:
Design decisions:
State.trackEgive real absolute/relative E accounting (closes Support M82/M83 (absolute/relative extrusion mode) #419); z-hops, ironing, spiralize, G92 E resets and adaptive layer heights are all handled, with implausible results clamped away.;FLAVOR:line (Griffin = Ultimaker 2.85 mm, else 1.75 mm). Cura'smaterial_diametersits in the end-of-file;SETTING_3blob — using it would make streamed and one-shot parses disagree, so it is deliberately not read.Assisted by Claude Code - Fable 5