forked from TengerTechnologies/Bricklayers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbricklayers.py
143 lines (126 loc) · 6.95 KB
/
bricklayers.py
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
138
139
140
141
142
143
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Copyright (c) [2025] [Roman Tenger]
import re
import sys
import logging
import os
import argparse
# Get the directory where the script is located
script_dir = os.path.dirname(os.path.abspath(__file__))
# Configure logging to save in the script's directory
log_file_path = os.path.join(script_dir, "z_shift_log.txt")
logging.basicConfig(
filename=log_file_path,
filemode="w",
level=logging.INFO,
format="%(asctime)s - %(message)s"
)
def process_gcode(input_file, layer_height, extrusion_multiplier):
current_layer = 0
current_z = 0.0
perimeter_type = None
perimeter_block_count = 0
inside_perimeter_block = False
z_shift = layer_height * 0.5
logging.info("Starting G-code processing")
logging.info(f"Input file: {input_file}")
logging.info(f"Z-shift: {z_shift} mm, Layer height: {layer_height} mm")
# Read the input G-code
with open(input_file, 'r') as infile:
lines = infile.readlines()
# Identify the total number of layers by looking for `G1 Z` commands
total_layers = sum(1 for line in lines if line.startswith("G1 Z"))
# Process the G-code
modified_lines = []
for line in lines:
# Detect layer changes
if line.startswith("G1 Z"):
z_match = re.search(r'Z([-\d.]+)', line)
if z_match:
current_z = float(z_match.group(1))
current_layer = int(current_z / layer_height)
perimeter_block_count = 0 # Reset block counter for new layer
logging.info(f"Layer {current_layer} detected at Z={current_z:.3f}")
modified_lines.append(line)
continue
# Detect perimeter types from PrusaSlicer comments
if ";TYPE:External perimeter" in line or ";TYPE:Outer wall" in line:
perimeter_type = "external"
inside_perimeter_block = False
logging.info(f"External perimeter detected at layer {current_layer}")
elif ";TYPE:Perimeter" in line or ";TYPE:Inner wall" in line:
perimeter_type = "internal"
inside_perimeter_block = False
logging.info(f"Internal perimeter block started at layer {current_layer}")
elif ";TYPE:" in line: # Reset for other types
perimeter_type = None
inside_perimeter_block = False
# Group lines into perimeter blocks
if perimeter_type == "internal" and line.startswith("G1") and "X" in line and "Y" in line and "E" in line:
# Start a new perimeter block if not already inside one
if not inside_perimeter_block:
perimeter_block_count += 1
inside_perimeter_block = True
logging.info(f"Perimeter block #{perimeter_block_count} detected at layer {current_layer}")
# Insert the corresponding Z height for this block
is_shifted = False # Flag for whether this block is Z-shifted
if perimeter_block_count % 2 == 1: # Apply Z-shift to odd-numbered blocks
adjusted_z = current_z + z_shift
logging.info(f"Inserting G1 Z{adjusted_z:.3f} for shifted perimeter block #{perimeter_block_count}")
modified_lines.append(f"G1 Z{adjusted_z:.3f} ; Shifted Z for block #{perimeter_block_count}\n")
is_shifted = True
else: # Reset to the true layer height for even-numbered blocks
logging.info(f"Inserting G1 Z{current_z:.3f} for non-shifted perimeter block #{perimeter_block_count}")
modified_lines.append(f"G1 Z{current_z:.3f} ; Reset Z for block #{perimeter_block_count}\n")
# Adjust extrusion (`E` values) for shifted blocks on the first and last layer
if is_shifted:
e_match = re.search(r'E([-\d.]+)', line)
if e_match:
e_value = float(e_match.group(1))
if current_layer == 0: # First layer
new_e_value = e_value * 1.5
logging.info(f"Multiplying E value by 1.5 on first layer (shifted block): {e_value:.5f} -> {new_e_value:.5f}")
line = re.sub(r'E[-\d.]+', f'E{new_e_value:.5f}', line).strip()
line += f" ; Adjusted E for first layer, block #{perimeter_block_count}\n"
elif current_layer == total_layers - 1: # Last layer
new_e_value = e_value * 0.5
logging.info(f"Multiplying E value by 0.5 on last layer (shifted block): {e_value:.5f} -> {new_e_value:.5f}")
line = re.sub(r'E[-\d.]+', f'E{new_e_value:.5f}', line).strip()
line += f" ; Adjusted E for last layer, block #{perimeter_block_count}\n"
else:
new_e_value = e_value * extrusion_multiplier
logging.info(f"Multiplying E value by extrusionMultiplier")
line = re.sub(r'E[-\d.]+', f'E{new_e_value:.5f}', line).strip()
line += f" ; Adjusted E for extrusionMultiplier, block #{perimeter_block_count}\n"
elif perimeter_type == "internal" and line.startswith("G1") and "X" in line and "Y" in line and "F" in line: # End of perimeter block
inside_perimeter_block = False
modified_lines.append(line)
# Overwrite the input file with the modified G-code
with open(input_file, 'w') as outfile:
outfile.writelines(modified_lines)
logging.info("G-code processing completed")
logging.info(f"Log file saved at {log_file_path}")
# Main execution
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Post-process G-code for Z-shifting and extrusion adjustments.")
parser.add_argument("input_file", help="Path to the input G-code file")
parser.add_argument("-layerHeight", type=float, default=0.2, help="Layer height in mm (default: 0.2mm)")
parser.add_argument("-extrusionMultiplier", type=float, default=1, help="Extrusion multiplier for first layer (default: 1.5x)")
args = parser.parse_args()
process_gcode(
input_file=args.input_file,
layer_height=args.layerHeight,
extrusion_multiplier=args.extrusionMultiplier,
)