Skip to content

Instantly share code, notes, and snippets.

@aavogt
Created August 12, 2025 23:48
Show Gist options
  • Select an option

  • Save aavogt/29776e5fc1822ddc0808a4e6e76b238d to your computer and use it in GitHub Desktop.

Select an option

Save aavogt/29776e5fc1822ddc0808a4e6e76b238d to your computer and use it in GitHub Desktop.
offset strip fin using fullcontrol.xyz example for why I started htpl
import fullcontrol as fc
import math
import time
import os
# the main thing is to reduce the temperature
# do I add retraction? Z or E? M207, G10 G11
# do I slow it down?
# do I make them closer together?
# do I add a horizontal line that gets cut off? This way I
# cut right next to the line and it's guaranteed to be open then
# does it make sense to do lines more than once?
# how do I transpose it?
# I can rewrite the whole function swapping x and y
# I can also process the output, swapping x and y
# when I make the lines thin, I don't have enough adhesion
# I need to draw a brim.
# This means the first line has to be much thicker
import inspect
def transposing(fn):
"""def f(x, mx, Y, fYs):
g = transposing(f)
-- g(y, my, X, fXs)
"""
sig = inspect.signature(fn)
param_names = list(sig.parameters.keys())
param_defaults = {k: v.default for k, v in sig.parameters.items() if
v.default is not inspect.Parameter.empty}
def wrapper(*args, **kwargs):
# Map positional arguments to their parameter names
ps = param_defaults.copy()
ps.update(zip(param_names, args))
ps.update(kwargs)
# Replace x with y and y with x in the combined
for k in list(ps.keys())[4:7]:
kl = list(k)
for i in range(len(kl)):
def recase(d):
if kl[i].isupper():
return d.upper()
else:
return d
match kl[i].lower():
case 'x':
kl[i] = recase('y')
case 'y':
kl[i] = recase('x')
kn = ''.join(kl)
# only swap once
if kn < k:
ps[kn], ps[k] = ps[k], ps[kn]
print(ps)
print(param_defaults)
result = fn(**ps)
# Swap x and y in the result
def swap_xy(obj):
##if hasattr(obj, 'x') and hasattr(obj, 'y'):
# obj.x, obj.y = obj.y, obj.x
# return obj
# return a new Point object:
if isinstance(obj, fc.Point):
return fc.Point(x=obj.y, y=obj.x, z=obj.z, color=obj.color)
return obj
return [swap_xy(p) for p in result]
return wrapper
def create_line_grid(x0 = 50, y0 = 50, z0 = 0.2,
Ny = 15, Nx = 5,
X = 160,
Y = 44,
side_width = 0.3,
main_width = 0.1,
overlap = 0.25,
passes = 4, # one pass
pass_dz = 0.20):
Lx = X / (2*Nx - 1 - overlap * (2*Nx - 2))
DX = - Lx * overlap
S_x = 2* (Lx + DX)
S_y = Y / (Ny + 1)
lines = []
def setw(w):
lines.append(fc.ExtrusionGeometry(width=w))
p = fc.Point(x=x0, y=y0, z=z0)
def on():
lines.append(fc.Extruder(on=True))
# G11
lines.append(fc.ManualGcode(text="G1 E0.5"))
def off():
lines.append(fc.Extruder(on=False))
# G10
lines.append(fc.ManualGcode(text="G1 E-0.5"))
lines.append(fc.ManualGcode(text="M0 P300"))
def side_wall(yv=y0):
setw(side_width)
off()
lines.append(fc.Point(x=x0+X, y=yv, z=z0))
on()
for k in range(passes):
# left side wall doesn't render, why?
lines.append(fc.Point(x=x0+X, y=yv, z=z0 + k * pass_dz))
lines.append(fc.Point(x=x0, y=yv, z=z0 + k * pass_dz))
lines.append(fc.Point(x=x0, y=yv, z=z0 + k * (pass_dz + 1)))
off()
# side_wall()
setw(main_width)
# offset strip fins in a s-pattern
for j in range(1,Ny+1): # in the y direciton
xiter = range(Nx)
if j % 2 == 0:
xiter = reversed(xiter)
for i in xiter: # in the x direction
# Skip odd lines when i is the last column
if i == Nx-1 and j % 2 != 0:
continue
# Add DX to x coordinate when j is odd and i is not the end
if j % 2 != 0 and i != Nx-1:
x_offset = Lx + DX
else:
x_offset = 0
p1 = fc.Point(x=x0 + i*S_x + x_offset, y=y0+ j*S_y, z=z0)
p2 = fc.Point(x=x0 + i*S_x + x_offset + Lx, y=y0 + j*S_y, z=z0)
def qd(a, b):
return (a.x - b.x)**2 + (a.y - b.y)**2 + (a.z - b.z)**2
if qd(p1, p) > qd(p2, p):
p1, p2 = p2, p1
for k in range(passes):
p1 = p1.copy()
p2 = p2.copy()
p1.z = z0 + k * pass_dz
p2.z = z0 + k * pass_dz
lines.append(p1)
on()
lines.append(p2)
off()
# lines.append(p1) # back some percentage instead?
p = p2
# side_wall(y0 + Y*2)
off()
return lines
create_line_grid_h = transposing(create_line_grid)
# shouldn't this be the bounding box of extrusion?
# why should travel be larger than extrusion?
def get_bounding_box(objects):
if not objects:
return None
min_x = min_y = min_z = float('inf')
max_x = max_y = max_z = float('-inf')
for obj in objects:
if hasattr(obj, 'x') and hasattr(obj, 'y') and hasattr(obj, 'z'):
min_x = min(min_x, obj.x)
min_y = min(min_y, obj.y)
min_z = min(min_z, obj.z)
max_x = max(max_x, obj.x)
max_y = max(max_y, obj.y)
max_z = max(max_z, obj.z)
return {
'min': { 'x' : min_x, 'y' : min_y, 'z' : min_z},
'max': { 'x' : max_x, 'y' : max_y, 'z' : max_z},
}
def draw_l_corners(sequence, corner_length=10, corner_lengthy = 2, offset=2, z=0.2):
bbox = get_bounding_box(sequence)
if bbox is None:
return []
x_min, y_min = bbox["min"]["x"] - offset, bbox["min"]["y"] - offset
x_max, y_max = bbox["max"]["x"] + offset, bbox["max"]["y"] + offset
corners = []
# counterclockwise
corner_points = [
(x_min+corner_length, y_min),
(x_min, y_min),
(x_min, y_min + corner_lengthy),
(x_min, y_max - corner_lengthy),
(x_min, y_max),
(x_min+corner_length, y_max),
(x_max-corner_length, y_max),
(x_max, y_max),
(x_max, y_max-corner_lengthy),
(x_max, y_min+corner_lengthy),
(x_max, y_min),
(x_max-corner_length, y_min)
]
corners.append(fc.Extruder(on=False))
for i, (x, y) in enumerate(corner_points):
corners.append(fc.Point(x=x, y=y, z=z))
if i % 3 == 0:
corners.append(fc.Extruder(on=True))
if i % 3 == 2:
corners.append(fc.Extruder(on=False))
return corners
line_grid = create_line_grid()
result = [fc.ExtrusionGeometry(width=2.5, height=0.2),
fc.ManualGcode(text="M207 F100 S10"),
fc.ManualGcode(text="M203 X50 Y50"),
fc.Fan(speed_percent=0)]
def on():
result.append(fc.Extruder(on=True))
result.append(fc.ManualGcode(text="G1 E0.5"))
def off():
result.append(fc.Extruder(on=False))
result.append(fc.ManualGcode(text="G1 E-0.5"))
# result += draw_l_corners(line_grid)
result.append(fc.Extruder(on=False))
# get out of the way, and then pause
def away():
off()
result.append(fc.Point(x=180, y=180, z=10))
result.append(fc.ManualGcode(text="M0"))
away()
def stack(layers = 5):
global result
for i in range(layers):
result += create_line_grid(z0=0.1 + 0.2*8*i)
away()
result += create_line_grid_h(z0=0.1 + 0.2*8*(i+0.5), Ny = math.floor(15*160/44))
if i < layers-1:
away()
def side_by_side(xrange=(0, 220), w = 45):
global result
for x in range(xrange[0], xrange[1], w):
result += create_line_grid(x0=x)
side_by_side()
print('\n\n-----------------\n\n')
# have to set the temperature before the "move to the start position"
# myprinter = fc.GcodeControls(printer_name="Cura/Creality Ender-5 S1",
# initialization_data={"primer": "travel"})
with open("tape.gcode", "w") as file:
file.write(fc.transform(result, 'gcode')) #
file.close()
print(f'wrote gcode {time.ctime()}')
# fc.transform(result, 'plot')
# preheat without waiting, then preheat and wait
# before the cura primer gcode
# "nozzle_temp"" : "230" adds the M109 S230 too late
# https://github.com/FullControlXYZ/fullcontrol/issues/93#issuecomment-2258953005
temperature = 230
bed_temperature = 60
fan = 25 # why am I repeating myself here?
os.system(f"sed -i -e '1i\\M104 S{temperature}\\nM140 S{bed_temperature}\\nG28' -e '11i\\M190 S{bed_temperature}\\nM109 S{temperature}\\nM106 S{fan}' tape.gcode")
# copy to sd card overwriting tape.gcode if it's plugged
if os.path.exists("/dev/mmcblk0p1"):
if not os.path.exists("/media/aavogt/F089-C8E2/"):
os.system("udisksctl mount -b /dev/mmcblk0p1")
os.system("cp tape.gcode /media/aavogt/disk")
os.system("udisksctl unmount -b /dev/mmcblk0p1")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment