Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions docs/src/gcode/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1161,6 +1161,68 @@ The formatting string does not need to be right beside the parameter.
If the formatting string is created with the wrong pattern it will be
printed as characters.

[[gcode:workpiece]]
== Workpiece

(((Workpiece)))
A '(WORKPIECE,...)' comment declares the stock the program is cut from. The
G-code preview draws it as a wireframe outline around the toolpath; it has no
effect on machine behaviour, on the program extents, or on zoom-to-fit.

Three shapes are understood:

[source,ngc]
----
(WORKPIECE,BOX,XMIN=0,YMIN=0,ZMIN=-40,XMAX=100,YMAX=100,ZMAX=0)
(WORKPIECE,CYLINDER,AXIS=Z,X=0,Y=0,ZMIN=-40,ZMAX=0,DIAMETER=80)
(WORKPIECE,TUBE,AXIS=Z,X=0,Y=0,ZMIN=-40,ZMAX=0,DIAMETER=80,INNER_DIAMETER=40)
----

Keys may appear in any order and are case-insensitive, as are the shape names.

.Keys
[width="90%",options="header",cols="2,1,4"]
|===
|Key |Shapes |Meaning
|'XMIN' 'YMIN' 'ZMIN' 'XMAX' 'YMAX' 'ZMAX' |BOX |The two opposite corners. All
six are required, and no 'MIN' may exceed its 'MAX'.
|'AXIS' |CYLINDER, TUBE |The axis of revolution, 'X', 'Y' or 'Z'. Optional,
default 'Z'.
|'<axis>MIN' '<axis>MAX' |CYLINDER, TUBE |The extent along 'AXIS' - so
'ZMIN'/'ZMAX' for 'AXIS=Z'. Both required.
|the other two axis letters |CYLINDER, TUBE |Where the axis sits in the other
two directions - 'X' and 'Y' for 'AXIS=Z'. Optional, default 0.
|'DIAMETER' |CYLINDER, TUBE |The outside diameter; required, and always a
diameter, never a radius, regardless of lathe diameter mode (G7).
|'INNER_DIAMETER' |TUBE |The bore diameter; required, and must be greater than
zero and less than 'DIAMETER'.
|'UNITS' |all |'MM' or 'INCH'. Optional; without it the values are read in the
units modal at the comment (G20/G21).
|===

Several '(WORKPIECE,...)' comments are additive: each one adds a piece of
stock, so a fixture holding several parts can be described with one comment
per piece.

The coordinates are read in the coordinate system active where the comment
appears - the G92 offset, the G5x XY rotation and the G5x offset in force at
that line, exactly as for a move endpoint on the same line. There is no key to
name a coordinate system; a post processor must therefore emit the comment
'after' the work offset it belongs to:

[source,ngc]
----
G54
(WORKPIECE,BOX,XMIN=0,YMIN=0,ZMIN=-40,XMAX=100,YMAX=100,ZMAX=0)
----

Unknown keys are ignored, so a comment written for a later version of LinuxCNC
still draws what this one understands. Anything else malformed - a missing
required key, a value that is not a number, an unrecognised shape - is ignored
with a warning, and the rest of the file is interpreted normally. A workpiece
declared between '(AXIS,hide)' and '(AXIS,show)' is still drawn: those comments
suppress moves, and the stock is not a move.

[[gcode:file-requirements]]
== File Requirements

Expand Down
3 changes: 3 additions & 0 deletions docs/src/gui/axis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,9 @@ preview on certain parts that are already working OK).

This display can be useful in the AXIS preview when (debug,message) comments are not displayed.

The preview can also draw the stock the program is cut from; see the
<<gcode:workpiece,Workpiece>> section.

[[axis:touchoff-actual]]
=== Touch Off using Actual Position
The Touch Off feature can optionally incorporate the actual axis position value into the calculation for the offset. This is primarily used in cases where a non-motorized axis such as the quill in a milling machine provides feedback to LinuxCNC via an encoder, but there is no motor to control movement. This allows AXIS to provide a DRO display for such an axis with working touch off capability.
Expand Down
8 changes: 8 additions & 0 deletions lib/python/qtvcp/widgets/gcode_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,14 @@ def getShowOffsets(self):
return self.show_offsets
_offsets = Property(bool, getShowOffsets, setShowOffsets)

# show workpiece
def setShowWorkpiece(self, state):
self.show_workpiece = state
self.update()
def getShowWorkpiece(self):
return self.show_workpiece
_workpiece = Property(bool, getShowWorkpiece, setShowWorkpiece)

# show small origin
def setShowSmallOrigin(self, state):
self.show_small_origin = state
Expand Down
36 changes: 36 additions & 0 deletions lib/python/rs274/glcanon.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,20 @@ def __init__(self, colors, geometry, is_foam=0, foam_w=1.5, foam_z=0.0):
self.notify = 0
self.notify_message = ""
self.highlight_line = None
# Stock outlines declared by (WORKPIECE,...) comments, in the order
# declared - they are additive, one entry per comment, because a
# fixture may hold several pieces. A canon is built per file load, so
# nothing else ever clears this.
self.workpieces = []

def comment(self, arg):
if arg.startswith("WORKPIECE,"):
# Recorded even while (AXIS,hide) is in force: hide suppresses
# moves, and the stock is not a move.
workpiece = glcanon_scene.Workpiece.from_comment(arg, self)
if workpiece is not None:
self.workpieces.append(workpiece)
return
if arg.startswith("AXIS,") or arg.startswith("PREVIEW,"):
parts = arg.split(",")
command = parts[1]
Expand Down Expand Up @@ -655,6 +667,8 @@ class GlCanonDraw:
'axis_y': (1.00, 0.20, 0.20),
'grid': (0.15, 0.15, 0.15),
'limits': (1.0, 0.0, 0.0),
'workpiece': glcanon_scene.WORKPIECE_COLOR,
'workpiece_alpha': glcanon_scene.WORKPIECE_ALPHA,
}
def __init__(self, s=None, lp=None, g=None):
self.stat = s
Expand Down Expand Up @@ -1117,6 +1131,27 @@ def get_grid(self):
if self.canon and self.canon.grid: return self.canon.grid
return 5./25.4

def get_show_workpiece(self):
"""Whether (WORKPIECE,...) stock outlines are drawn.

Defaulted here rather than required of every host: the other show_*
getters predate this widget and each of the hosting GUIs defines its
own, so a host that has never heard of the flag keeps drawing stock,
and any host can toggle it by setting self.show_workpiece."""
return getattr(self, 'show_workpiece', True)

def get_workpieces(self):
"""The stock the loaded program declared, as rs274.glcanon_scene
.Workpiece records - the declared params, the outline in machine
coordinates, and the outline as drawn. Empty until a program is
loaded.

The supported way for a hosting GUI to read them: self.canon is None
before the first load and is replaced by every one, so a handler that
took it once would go stale silently.
"""
return getattr(self.canon, 'workpieces', []) if self.canon else []

def draw_grid(self):
"""Draw the ground grid. Override point: plasmac2 replaces this method
on the instance and calls back into draw_grid_permuted."""
Expand Down Expand Up @@ -1243,6 +1278,7 @@ def frame_context(self) -> glcanon_scene.FrameContext:
show_relative=self.get_show_relative(),
show_metric=self.get_show_metric(),
show_small_origin=self.show_small_origin,
show_workpiece=self.get_show_workpiece(),
program_alpha=self.get_program_alpha(),
grid_size=self.get_grid_size(),
highlight_line=self.get_highlight_line(),
Expand Down
Loading