Skip to content

Commit f03747f

Browse files
authored
Add config to flip page orientation (#28)
Added `horizontal_flip` and `vertical_flip` config options. This improves handling of plotter which have inverted axis orientation over the previous `invert_y` + `offset_y` solution.
1 parent 595b15b commit f03747f

File tree

3 files changed

+44
-21
lines changed

3 files changed

+44
-21
lines changed

README.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Vpype plugin to generate gcode and other text output.
33
See: https://github.com/abey79/vpype
44

55

6-
Gcode vpype plugin. Write gcode files for the vpype pipeline. The output format can be customized by the user heavily to an extent that you can also output non gcode ascii text files.
6+
Gcode vpype plugin. Write gcode files for the vpype pipeline. The output format can be customized by the user heavily to an extent that you can also output non gcode ascii text files.
77

88
* `gwrite` write geometries as gcode to a file
99

@@ -41,7 +41,7 @@ The goal of this project is to allow all hobbyists needing gcode writing to have
4141
Breaking changes are fine. Anything that will make this code more likely to end up in vpype properly and this particular library getting deprecated will be highly likely to be done.
4242

4343
# Profiles
44-
This plugin supports different output profiles which configure the way the resulting output is formatted. Output profiles are flexible in a way that they can also be used to generate non gcode files, i.e. JSON or CSV files.
44+
This plugin supports different output profiles which configure the way the resulting output is formatted. Output profiles are flexible in a way that they can also be used to generate non gcode files, i.e. JSON or CSV files.
4545

4646
## Predefined Profiles
4747
There are several predefined output profiles as part of the release:
@@ -91,8 +91,10 @@ These parameters define the transformation between *vpype*'s and the target's co
9191
- `scale_y`: Apply a scaling factor on the Y axis. Use `-1` to invert the direction.
9292
- `offset_x`: Apply an offset to the X axis. This offset is expressed in the unit defined by `unit`.
9393
- `offset_y`: Apply an offset to the Y axis. This offset is expressed in the unit defined by `unit`.
94-
- `invert_x`: Invert or mirror all points right-to-left without changing the position within the document space.
95-
- `invert_y`: Invert or mirror all points top-to-bottom without changing the position within the document space.
94+
- `horizontal_flip`: Flip the document right-to-left. Requires the document page size to be set.
95+
- `vertical_flip`: Flip the document to-to-bottom. Requires the document page size to be set. This will correctly transform the document from the standard SVG top-left origin to the standard gcode bottom-left origin.
96+
- `invert_x`: Flip all points right-to-left without changing the position within the document.
97+
- `invert_y`: Flip all points top-to-bottom without changing the position within the document.
9698

9799
### Output Format
98100
All of the options below default to an empty text which means no output is generated. However, if `segment_first` or `segment_last` is omitted the code from `segment` is used. If there is only one segment, `segment_first` takes priority over `segment_last`.
@@ -113,7 +115,7 @@ All of the options below default to an empty text which means no output is gener
113115
For example every element accepts the value of `index`. You would encode that in the text as `{index:d}` the d denotes an integer value. If you need to have a `{` value in your text you would encode that as `{{` likewise you would encode a `}` as `}}`.
114116

115117
- `document_start` and `document_end` accept the following:
116-
- `filename` file name of the file being saved
118+
- `filename` file name of the file being saved
117119

118120
- `layer_start`, `layer_end` and `layer_join` accept the following:
119121
- `x` the last_x position before this layer, this is 0 for the first layer
@@ -135,12 +137,12 @@ For example every element accepts the value of `index`. You would encode that in
135137
- `index` same as `lines_index`
136138
- `index1` same as `lines_index1`
137139
- `lines_index` the current line index within this layer starting from 0
138-
- `lines_index1` the current line index within this layer number starting from 1
140+
- `lines_index1` the current line index within this layer number starting from 1
139141
- `layer_index` the current layer index starting from 0
140142
- `layer_index1` the current layer number starting from 1
141143
- `layer_id` values for the current vpype layer ID that contains this line
142144
- `filename` file name of the file being saved
143-
145+
144146
- `segment_first`, `segment`, `segment_last` accept the following:
145147
* `index`: index of the particular coordinate pair. eg `{index:d}`
146148
* `x` absolute position x in floating point number. eg `{x:.4f}`
@@ -160,7 +162,7 @@ For example every element accepts the value of `index`. You would encode that in
160162
* `segment_index` the current segment within this line starting from 0
161163
* `segment_index1` the current segment within this line starting from 1
162164
* `lines_index` the current line index within this layer starting from 0
163-
* `lines_index1` the current line index within this layer number starting from 1
165+
* `lines_index1` the current line index within this layer number starting from 1
164166
* `layer_index` the current layer index starting from 0
165167
* `layer_index1` the current layer number starting from 1
166168
* `layer_id` values for the current vpype layer ID that contains this line
@@ -207,7 +209,7 @@ line 8 segment count: 1
207209
line 9 segment count: 1
208210
line 10 segment count: 1
209211
```
210-
212+
211213
Alternatively, default values for string-based variable may be provided using the command line using the `--default` option:
212214

213215
```
@@ -289,7 +291,7 @@ default_profile = "gcode"
289291
```
290292

291293
## Coordinate System
292-
`Vpype-Gcode` uses the standard coordinate system of vpype which uses the SVG spec' system. The origin point is located in the upper-left hand corner. Positive y values are towards the bottom. If you wish to change the coordinate system you should use `invert_y` and `invert_x` equals `true` in your profile. This will mirror the work horizontally or vertically within the same euclidean space. For example the native Coordinate system of gcode is origin point in the bottom left. This requires that for gcode profiles be marked as `invert_y`.
294+
`Vpype-Gcode` uses the standard coordinate system of vpype which uses the SVG spec' system. The origin point is located in the upper-left hand corner. Positive y values are towards the bottom. If you wish to change the coordinate system you should use `vertical_flip` and `horizontal_flip` equals `true` in your profile (or `invert_y` and `invert_x` in the uncommon situation where the document page size is not known). For example the native coordinate system of gcode is origin point in the bottom left with positive y values toward the top. This system requires gcode profiles be marked with `vertical_flip = true`.
293295

294296
```toml
295297
[gwrite.gcode]
@@ -298,7 +300,7 @@ segment_first = "G00 X{x:.4f} Y{y:.4f}\n"
298300
segment = "G01 X{x:.4f} Y{y:.4f}\n"
299301
document_end = "M2\n"
300302
unit = "in"
301-
invert_y = true
303+
vertical_flip = true
302304
info= "This gcode profile is correctly inverted across the y-axis"
303305
```
304306

@@ -410,7 +412,7 @@ New release should be created with the following workflow:
410412

411413
# Credits
412414

413-
* [tatarize](https://github.com/tatarize) - Wrote the bulk of the plug-in.
415+
* [tatarize](https://github.com/tatarize) - Wrote the bulk of the plug-in.
414416
* [abey79](https://github.com/abey79) - Helped with advice that largely pushes us towards the integration goals as well as his very solid suggestion to use .format() which greatly expands the expected formats.
415417
* [theomega](https://github.com/theomega) - Basically rewrote the thing into the dapper codebase you see today. Rather than the 4 hours I figured I'd kill on this.
416418
* [ithinkido](https://github.com/ithinkido) - For his many insightful comments and determination to make this project as good as it can be.

vpype_gcode/bundled_configs.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ segment_first = "G00 X{x:.4f} Y{y:.4f}\n"
55
segment = "G01 X{x:.4f} Y{y:.4f}\n"
66
document_end = "M2\n"
77
unit = "in"
8-
invert_y = true
8+
vertical_flip = true
99
info= "This gcode profile is correctly inverted across the y-axis"
1010

1111
[gwrite.gcodemm]
@@ -14,7 +14,7 @@ segment_first = "G00 X{x:.4f} Y{y:.4f}\n"
1414
segment = "G01 X{x:.4f} Y{y:.4f}\n"
1515
document_end = "M2\n"
1616
unit = "mm"
17-
invert_y = true
17+
vertical_flip = true
1818
info= "This gcode profile is correctly inverted across the y-axis"
1919

2020
[gwrite.gcode_relative]
@@ -23,7 +23,7 @@ segment_first = "G00 X{dx:.4f} Y{dy:.4f}\n"
2323
segment = "G01 X{dx:.4f} Y{dy:.4f}\n"
2424
document_end = "M2\n"
2525
unit = "in"
26-
invert_y = true
26+
vertical_flip = true
2727
info= "This gcode profile is correctly inverted across the y-axis"
2828

2929
[gwrite.csv]
@@ -58,15 +58,15 @@ layer_end = "</g>"
5858

5959
[gwrite.HPGL-R]
6060
document_start = "IN;"
61-
layer_start = "SP{layer_id:d};PA;PU0,0;PR;"
61+
layer_start = "SP{layer_id:d};PA;PU0,0;PR;"
6262
segment_first = "PU{dx:.0f},{dy:.0f};PD"
6363
segment = "{dx:.0f},{dy:.0f},"
6464
segment_last ="{dx:.0f},{dy:.0f};"
6565
document_end = ";SP0;IN\n"
6666
scale_x = 40
6767
scale_y = 40
6868
unit = "mm"
69-
invert_y = true
69+
vertical_flip = true
7070
info = """Output HPGL relative co-ordinates NB. This will not take care of page margins etc within the machine.
7171
7272
Ensure that the svg layout is landscape.
@@ -82,7 +82,7 @@ document_end = "F0\n"
8282
scale_x = 10
8383
scale_y = 10
8484
unit = "mm"
85-
invert_y = true
85+
vertical_flip = true
8686
info = """Will output relative coordinates.
8787
8888
Make sure your input layout matches the paper loaded.
@@ -99,7 +99,7 @@ document_end = "F0\n"
9999
scale_x = 10
100100
scale_y = 10
101101
unit = "mm"
102-
invert_y = true
102+
vertical_flip = true
103103
info = """Make sure your input layout matches the paper loaded.
104104
i.e. landscape svg when landscape paper in the machine
105105

vpype_gcode/gwrite.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,31 @@
1414
vp.config_manager.load_config_file(str(Path(__file__).parent / "bundled_configs.toml"))
1515

1616

17-
def invert_axis(document: vp.Document, invert_x: bool, invert_y: bool):
17+
def invert_axis(
18+
document: vp.Document,
19+
invert_x: bool,
20+
invert_y: bool,
21+
whole_page: bool = False,
22+
unit_scale: float = 1.0,
23+
) -> vp.Document:
1824
"""Inverts none, one or both axis of the document.
1925
This applies a relative scale operation with factors of 1 or -1
2026
on the two axis to all layers. The inversion happens relative to
27+
the center of the page, if whole_page is true, otherwise to
2128
the center of the bounds.
2229
"""
2330

24-
bounds = document.bounds()
31+
if whole_page and document.page_size is None:
32+
raise RuntimeError("Cannot flip a document with an undefined page size")
33+
34+
if whole_page:
35+
# This is called after the document has been scaled, but the page size
36+
# is not adjusted, so we need to adjust it here
37+
(x, y) = document.page_size
38+
bounds = (0.0, 0.0, x / unit_scale, y / unit_scale)
39+
else:
40+
bounds = document.bounds()
41+
2542
if not bounds:
2643
return document
2744

@@ -117,9 +134,13 @@ def gwrite(
117134

118135
invert_x = config.get("invert_x", False)
119136
invert_y = config.get("invert_y", False)
137+
flip_x = config.get("horizontal_flip", False)
138+
flip_y = config.get("vertical_flip", False)
120139
# transform the document according to inversion parameters
121140
if invert_x or invert_y:
122141
document = invert_axis(document, invert_x, invert_y)
142+
if flip_x or flip_y:
143+
document = invert_axis(document, flip_x, flip_y, whole_page=True, unit_scale=unit_scale)
123144

124145
# prepare
125146
current_layer: vp.LineCollection | None = None

0 commit comments

Comments
 (0)