PORTING for Bambu Studio / Prusa Slicer / Orca Slicer made with AI.. but AI isn't so intelligent….
We calculate the final price from your selected file. You review and accept it before payment.
Saved on this device.
PORTING for Bambu Studio / Prusa Slicer / Orca Slicer made with AI.. but AI isn't so intelligent….
- Rating
- 0 / 5
- Likes
- 0
- Downloads
- 5
- Makes
- 0
- Views
- 53
- Reviews
- 0
Updated at source:
Model information
- Source
- Printables
- Category
- Other Printer Parts & Upgrades
- License
- GNU General Public License v2.0
#!/usr/bin/env python3
# PenColorizer.py - Adapted for Orca Slicer / Bambu Studio post-processing
# Adds pen changing & offset drawing logic for multi-pen plotting on 3D printer
import re
import sys
import os
class PenColorizer:
def init(self):
# These were your settings — you can make them command-line args later if needed
self.penstartx = 28.0
self.penstarty = 238.0 # note: this was called FirstPenZPosition, but used as Y!
self.xoffset = 36.1
self.yoffset = 45.8
self.zoffset = 3.2
self.extra_retraction = 5.5
self.interlace = True # only draw every second "color"/tool
self.last_z = 0.2
def get_pen(self, pen):
penside = pen % 2
penoffset = float(pen // 2) * 68.0
if penside == 0:
return [
f";Get pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ;go under pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; move pen right",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen"
]
else:
return [
f";Get pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ;go under pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; move pen right",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen"
]
def put_pen(self, pen):
penside = pen % 2
penoffset = float(pen // 2) * 68.0
if penside == 0:
return [
f";put pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; go under pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty:.3f} ; move pen left",
f"G0 X{self.penstartx + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen",
"G0 F5000 ; set speed fast",
""
]
else:
return [
f";put pen {pen}",
"G0 F5000 ; set speed fast",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; go under pen",
f"G0 X{self.penstartx + 20.5 + penoffset:.3f} Y{self.penstarty:.3f} ; lift pen",
"G0 F2000 ; set speed slow",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty:.3f} ; move pen left",
f"G0 X{self.penstartx + 41.0 + penoffset:.3f} Y{self.penstarty - 152.0:.3f} ; lower pen",
"G0 F5000 ; set speed fast",
""
]
def offset_gcode(self, line, extra_z=0.0):
if not (line.startswith('G0') or line.startswith('G1')):
return line
parts = []
cmd = line.split(' ', 1)[0]
parts.append(cmd)
coords = re.findall(r'([XYZF])(-?\d*\.?\d+)', line)
f_found = False
for axis, value in coords:
val = float(value)
if axis == 'F':
parts.append(f"F3600") # hard-coded as in original
f_found = True
elif axis == 'X':
parts.append(f"X{val + self.xoffset:.3f}")
elif axis == 'Y':
parts.append(f"Y{val + self.yoffset:.3f}")
elif axis == 'Z':
parts.append(f"Z{val + self.zoffset + extra_z:.3f}")
if not f_found and 'F' in line: # fallback
parts.append("F3600")
return ' '.join(parts)
def lift_gcode(self, line, extra_z=0.0):
if not (line.startswith('G0') or line.startswith('G1')):
return line
parts = []
cmd = line.split(' ', 1)[0]
parts.append(cmd)
coords = re.findall(r'([XYZF])(-?\d*\.?\d+)', line)
for axis, value in coords:
val = float(value)
if axis == 'F':
parts.append(f"F{val:.0f}")
elif axis == 'X':
parts.append(f"X{val:.3f}")
elif axis == 'Y':
parts.append(f"Y{val:.3f}")
elif axis == 'Z':
parts.append(f"Z{val + extra_z:.3f}")
return ' '.join(parts)
def get_first_position_line(self, draw_block):
for ln in draw_block:
if 'G0' in ln or 'G1' in ln:
if 'X' in ln and 'Y' in ln and 'Z' in ln:
return ln
return None
def add_explicit_z(self, lines):
new_lines = []
for line in lines:
if ('G0' in line or 'G1' in line) and 'Z' not in line:
line += f" Z{self.last_z:.3f}"
elif 'Z' in line:
m = re.search(r'Z(-?\d*\.?\d+)', line)
if m:
self.last_z = float(m.group(1))
new_lines.append(line)
return new_lines
def process(self, gcode_text):
data = gcode_text.splitlines(keepends=True)
# We'll process in-place; collect modified lines
output = []
layer_num = -1
cur_tool = 0
last_x, last_y, last_z = 100.0, 100.0, 0.3
is_layer = False
is_prime_tower = False
is_skirt_support_fill = False
draw_buffers = [[] for _ in range(8)] # per "tool"/pen
i = 0
while i < len(data):
line = data[i].rstrip('\r\n')
orig_line = line
if line.startswith(';LAYER:'):
layer_num += 1
is_layer = True
output.append(orig_line)
i += 1
continue
if ';layer_height =' in line:
try:
lh = float(line.split('=')[1].strip())
# you can use lh if needed
except:
pass
output.append(orig_line)
i += 1
continue
if ';TYPE:' in line:
if 'PRIME-TOWER' in line:
is_prime_tower = True
is_skirt_support_fill = False
elif any(t in line for t in ['SKIRT', 'SUPPORT', 'SUPPORT-INTERFACE', 'FILL']):
is_skirt_support_fill = True
is_prime_tower = False
else:
is_skirt_support_fill = False
is_prime_tower = False
output.append(orig_line)
i += 1
continue
draw_this = (cur_tool >= 0 and
not is_skirt_support_fill and
not is_prime_tower and
((layer_num + cur_tool) % 2 == 0 or not self.interlace))
if ('G0' in line or 'G1' in line):
# update last known pos
if 'X' in line:
m = re.search(r'X(-?\d*\.?\d+)', line)
if m: last_x = float(m.group(1))
if 'Y' in line:
m = re.search(r'Y(-?\d*\.?\d+)', line)
if m: last_y = float(m.group(1))
if 'Z' in line:
m = re.search(r'Z(-?\d*\.?\d+)', line)
if m: last_z = float(m.group(1))
e_match = re.search(r'E(-?\d*\.?\d+)', line)
if e_match:
e_val = float(e_match.group(1))
if e_val < 0:
# retract → assume z-hop possible
extra_z_offset = 3.0
else:
extra_z_offset = 0.0
else:
extra_z_offset = 0.0
if draw_this:
draw_buffers[cur_tool].append(self.offset_gcode(line, extra_z_offset))
else:
output.append(orig_line)
elif line.startswith('T'):
try:
cur_tool = int(line[1:]) - 1
except:
cur_tool = 0
output.append(';' + orig_line) # comment out tool change
i += 1
continue
elif any(t in line for t in ['T1','T2','T3','T4','T5','T6','T7','T8']):
output.append(';' + orig_line)
i += 1
continue
# Skip heating in object layers if desired
elif is_layer and any(cmd in line for cmd in ['M104','M109','M105']):
# optionally comment or remove
pass
else:
output.append(orig_line)
i += 1
# Now insert drawing blocks per layer (simplified – you may need to adjust insertion point)
# For simplicity we append at end of each ;LAYER block, but ideally insert before next layer or after inner walls
# This is a simplification – test & adjust insertion logic
final_output = []
in_layer = False
for ln in output:
final_output.append(ln)
if ln.startswith(';LAYER:') and layer_num >= 0:
in_layer = True
# retract before drawing
final_output.append(f"G1 F1500 E-{self.extra_retraction}\n")
for pen in range(8):
block = draw_buffers[pen]
if len(block) < 2: # almost empty
continue
first_pos = self.get_first_position_line(block)
if first_pos:
final_output.append(self.lift_gcode(first_pos, 3.0) + " ; lower pen from above first spot\n")
final_output.extend(self.get_pen(pen))
final_output.extend(block)
if block:
final_output.append(self.lift_gcode(block[-1], 3.0) + " ; raise pen after last spot\n")
final_output.extend(self.put_pen(pen))
# return after drawing
final_output.append(f"G0 X{last_x:.3f} Y{last_y:.3f} Z{last_z + 2.0:.3f}\n")
final_output.append(f"G0 X{last_x:.3f} Y{last_y:.3f} Z{last_z:.3f} ; return to last pos after drawing\n")
final_output.append(f"G1 F1500 E{self.extra_retraction}\n\n")
return ''.join(final_output)
if name == "__main__":
if len(sys.argv) < 2:
print("Usage: python PenColorizer.py <gcode_file>")
print(" The script modifies the file in place.")
sys.exit(1)
input_path = sys.argv[1]
if not os.path.isfile(input_path):
print(f"File not found: {input_path}")
sys.exit(1)
with open(input_path, 'r', encoding='utf-8') as f:
gcode = f.read()
processor = PenColorizer()
modified = processor.process(gcode)
with open(input_path, 'w', encoding='utf-8') as f:
f.write(modified)
print(f"Processed and overwritten: {input_path}")
