-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathstep.py
More file actions
137 lines (109 loc) · 4.8 KB
/
step.py
File metadata and controls
137 lines (109 loc) · 4.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
from gcode_geom import GSegment, GPoint, GHalfLine
from python_gcode.gcline import GCLine
from python_gcode.gcode_printer import GCodePrinter
from util import unprinted
from logger import rprint, rich_log
import logging
class Step:
def __init__(self, steps_obj, name='', debug=True):
self.name = name
self.debug = debug
self.steps_obj = steps_obj
self.printer = steps_obj.printer
#State
self.gcsegs:list[GSegment] = []
self.number = -1
self.valid = True
self.anchoring = False #Does this step create a thread anchor?
self.original_thread_path: GHalfLine = self.printer.thread_path.copy()
self.thread_path: GHalfLine|None = None
self.target:GPoint|None = None
def __repr__(self):
return(f'<Step {self.steps_obj.layer.layernum}.{self.number}'
+ (f' ({len(self.gcsegs)} segments)>:' if self.gcsegs else '>')
+ f' [light_sea_green italic]{self.name}[/]>'
)
def gcode(self, gcprinter:GCodePrinter) -> list[GCLine]:
"""Render the gcode involved in this Step, returning a list of GCLines.
There are two possibilities:
1. Thread movement: the angle of the thread has changed. We need to
find out how to move the ring to achieve this angle change, taking into
account the bed position. This is partially taken care of in the
Printer (sub-)class.
2. Printing: we print some stuff. To do so, we sort `add()`-ed gcode
lines by line number. If there are breaks in line number, check whether
the represented head position also has a break. If so, add gcode to
move the head correctly.
self.gcsegs is made of GSegment objects, each of which should have a .gc_line1
and .gc_line2 member which are GCLines.
"""
if self.thread_path is None:
raise ValueError('Attempt to call gcode() before Step context has exited')
if self.original_thread_path != self.thread_path:
rprint([f'[yellow]————[/]\nStep {self}:\n\t' +
self.original_thread_path.repr_diff(self.thread_path)])
#If there are no gcsegs, it must be a thread move.
if not self.gcsegs:
if self.thread_path == self.original_thread_path:
rprint('No thread movement and no gcsegs')
return []
#If the angle changed, the ring should move to reflect that
else:
if self.target is None:
raise ValueError('No gcsegs and no target')
return gcprinter.set_thread_path(self.thread_path, self.target)
#Sort gcsegs by the first gcode line number in each
self.gcsegs.sort(key=lambda s:s.gc_lines.first.lineno)
gcode = []
for seg in self.gcsegs:
gcprinter.curr_gcseg = seg
#gc_lines always starts and ends with an xymove but could have other
# stuff in-between, such as more xymoves or comments or other commands.
moves = [s for s in seg.gc_lines if s.is_xymove]
#In a GSegment with more than two X/Y Move lines, there should only ever
# be one Extrude line, which is always the last line. Execute every
# line, as the XY move will put the head in the right place for the
# extrude.
if len(moves) > 2:
gcode.extend(gcprinter.execute_gcode(seg.gc_lines.data[:-1]))
extrude_line = seg.gc_lines.data[-1]
#For GSegments with exactly two xymoves; the first might be an extruding move
else:
l1 = seg.gc_lines.data[0]
extrude_line = seg.gc_lines.data[-1]
#The first line should never execute an extrusion move, but we might need
# to use its coordinates to position the print head in the right place.
if l1.is_xymove and gcprinter.xy != l1.xy:
if l1.is_xyextrude:
l1 = l1.as_xymove(fake=True)
if gcprinter.prev_loc.z != l1.z:
l1 = l1.copy(args={'Z': gcprinter.prev_loc.z})
gcode.extend(gcprinter.execute_gcode(l1))
assert(extrude_line.is_extrude)
gcode.extend(gcprinter.execute_gcode(extrude_line, anchoring=self.anchoring))
return gcode
def add(self, gcsegs:list[GSegment], anchoring=False):
"""Add the GSegments in `gcsegs` to the list of segments that should be
printed in this step. Set `anchoring` to True to add the `fixed` property to
each of the passed lines."""
rprint(f'Adding {len(unprinted(gcsegs))}/{len(gcsegs)} unprinted gcsegs to Step')
if anchoring: rprint(f" -- This is a anchoring step (#{self.number})!")
for seg in unprinted(gcsegs):
self.anchoring = anchoring
self.gcsegs.append(seg)
seg.printed = True
def __enter__(self):
if self.debug is False: rich_log.setLevel(logging.CRITICAL)
return self
def __exit__(self, exc_type, value, traceback):
if self.debug is False: rich_log.setLevel(logging.DEBUG)
#Save state
self.thread_path = self.printer.thread_path.copy()
if self.printer.target is not None:
self.target = self.printer.target.copy()
#Die if there's an exception
if exc_type is not None:
print(f'Exception on Step.__exit__: {exc_type}')
return False
#Tell parent Steps object we exited
self.steps_obj.step_exited(self)