Reportar

Lámpara de Onda - gota de agua de madera cortada con láser

Instrucción
disc.xs
disc
.xs
Escenario de aplicación
Procesamiento láser
Máquina y módulo
xTool M2
10W
Material utilizado
Contrachapado
Tira LED
gift
6
522

Información

      Un disco de contrachapado de 300 mm cortado con una ranura continua en espiral, para que pueda ser drapeado
sobre doce costillas en forma de que adoptan la forma de ondas que se extienden desde una
Caída de caída. Una tira LED dentro del anillo base la ilumina desde el borde.

El perfil no se dibuja a mano. Es una función de Bessel, que es la
solución real para una gota que cae sobre una membrana circular, es decir, el espaciamiento de
Los anillos y la forma en que se desvanecen hacia afuera provienen de la física.

El problema interesante aquí es que un disco plano matemáticamente no puede llegar a ser
una superficie ondulada sin cambiar su propia circunferencia. 
Las ranuras concéntricas no pueden hacerlo, porque un anillo cerrado no puede
Cambia su circunferencia. Una espiral puede, porque se acaba sobre sí misma como una
muelle del reloj. Por eso el patrón es como se ve.

Cortado con un láser de diodo de 10 W en contrachapado de álamo de 3,5 mm. Toda la geometría es
generados por 4 scripts cortos en Python para que puedas cambiar el diámetro,
amplitud o altura de ranura y regenerar los archivos.

Lo publiqué en Facebook: 

https://www.facebook.com/groups/lasermaterials/permalink/1338253281623420/

Lo publiqué en Reddit: 

https://www.reddit.com/r/xToolOfficial/s/fd0xtk4Syw

____
Este proyecto es mi diseño, construido a través de varias iteraciones de pruebas y ensamblaje. Cualquier parecido con otras lámparas o proyectos que hayas visto es casualidad, busqué antes de empezar y no encontré nada parecido, pero si conoces trabajos previos en esta línea, realmente me gustaría verlo.
    

Instrucción

1

Paso1: Consigue los materiales + enlace a redes sociales

- Contrachapado de 3,5 mm, aproximadamente 300 x 900 mm 
- tira LED COB de 24 V, blanco cálido, unos 900
mm - pegamento para madera
- Lija fina, grano

 240 Lo publiqué en Facebook: 
 
2

Paso2: Mide tu contrachapado

No te saltes esto. Mi sábana se vendía como 4 mm y las pinzas marcaban 3,5. Peor aún,
ni siquiera era consistente: tenía unos 0,3 mm de variación entre esquinas de
la misma hoja.
 
El primer buje que corté usaba 0,15 mm de holgura. Ocho costillas entraron bien y las
últimas cuatro se rompieron intentando forzarlas. Las ranuras del archivo ahora son
0,5 mm sobredimensionadas, lo que suena descuidado pero es lo que realmente funciona una vez que añades
variación de hoja al carbón láser.
3

Paso3: Corta primero el peine de prueba - OPCIONAL

Haz este paso si quieres regenerar el SVG con mucha precisión:
 
hub.py también saca un peine pequeño con seis ranuras, de 3,7 a 4,2 mm en
pasos de 0,1 mm. Corta solo eso, luego prueba a deslizar un trozo de contrachapado en
cada ranura.

Quieres el que el retazo se deslize con una ligera presión del pulgar y
no se cae solo. Ese número va al cubo. Dos minutos aquí
ahorran una parte arruinada.
4

Paso4: Ejecutar los scripts - OPCIONAL

Haz este paso si quieres regenerar el SVG con mucha precisión:

python3 disc.py

python3 rib.py

python3 hub.py 

python3 ring.py
 
Cada uno imprime un resumen antes de escribir su SVG, así puedes comprobar los
números sin abrir nada. El disco debería indicar aproximadamente 15 vueltas y
una cinta de 6,6 m.
5

Paso5: Ajusta el corte

Corta un pequeño cuadrado del patrón en espiral sobre un recorte antes de comprometerte.
Mis ajustes en un diodo de 10 W en álamo de 3,5 mm eran 100% potencia, 4 mm/s,
1 pasada, asistencia de aire activada.
6

Paso6: Corta todo

Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 6 - Corta todo
Vista previa
Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 6 - Corta todo
Vista previa
Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 6 - Corta todo
Vista previa
Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 6 - Corta todo
Vista previa
- Disco: 1
- Costillas: 12
- Buje: 2 (se pegan entre sí)
- Anillo: 3 tiras y 3 placas de empalme
7

Paso7: Entiende cuáles son las costillas antes de pegar nada

Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 7 - Entiende cuáles son las costillas antes de pegar nada
Vista previa
Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 7 - Entiende cuáles son las costillas antes de pegar nada
Vista previa
Las costillas no son platos planos que se apilan. Se mantienen en el borde, como los
marcos dentro del casco de un barco, y es la forma de su borde superior lo que sostiene
la ola. El disco se encuentra sobre los doce a la vez.

 

Las alturas son de 12,4 mm en el extremo interior, hasta 22,6 mm en la primera cresta,
hasta 16,3 mm en la depresión y de nuevo hasta 21,2 mm en la segunda cresta. Esa
curva es el perfil de Bessel tallado en madera.
8

Paso8: Construye el hub

Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 8 - Construye el hub
Vista previa
Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 8 - Construye el hub
Vista previa
Pega los dos discos del cubo cara a cara con las ranuras alineadas. La forma fiable:
apilalas, empuja dos costillas recortadas por ranuras opuestas para forzar la alineación,
luego pega y deja que seque así.
Al doblarlo, se obtiene 7 mm de agarre en cada costilla en lugar de 3,5 mm.
Luego desliza las costillas.
9

Paso9: Libera el disco

Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 9 - Libera el disco
Vista previa
Hay 14 pequeñas pestañas de 0,6 mm a lo largo de un radio que sostienen la espiral en la
registro. Sin ellos, todo se deshace en cuanto lo levantas de la
cama.
 
Coloca el disco plano y corta cada uno de ellos con un cuchillo afilado. Todos.

 

Ahora es una cinta de 6,6 m anclada solo en el centro y el borde. Llévalo plano
en un cartón. No lo levantes por el borde.
10

Paso10: Forma y pegamento

Lámpara de Onda - gota de agua de madera cortada con láser instruction: step 10 - Forma y pegamento
Vista previa
Coloca el disco sobre la araña, cénrala y luego pega hacia fuera mientras avanzas.

 

Pesa la gravedad, la gravedad por sí sola no es suficiente para que las cintas se retuerzan contra las costillas.
11

Paso11: Anillo base e iluminación

El disco termina teniendo 293 mm de ancho una vez curvado, no 300, porque el material viaja a lo largo de la onda en lugar de en línea recta. El anillo está en talla de eso.

Pega el anillo a la parte inferior del borde del disco y pesa el aro hacia abajo.

Luego coloca la tira COB en la cara interior, 8 a 10 mm por debajo del borde superior, apuntando hacia dentro.

12

Paso12: CÓDIGO PYTHON

"""
Ripple lamp - rib generator.


 

One rib. I cut 12 of these and stand them on edge in the hub like the
spokes of a wheel. The wavy top edge is what the disc lies on, the straight
bottom edge sits flat on the table, that's what sets the height, not the hub.
"""


 

import math


 

# ---- same wave as the disc, don't touch these separately ----
R = 150.0
A0 = 9.0
KZ = 13.3237
K = KZ / R


 

RIB_R0 = 12.0 # inner end, any closer and 12 ribs collide at the centre
CLEAR = 10.0 # air under the lowest point of the wave, room for the hub
MARGIN = 10.0 # pull the outer end back so the rib can't poke past the disc


 

OUT = "rib.svg"



 

def bessel(n, x, steps=1500):
total = 0.0
for i in range(steps + 1):
t = math.pi * i / steps
w = 1.0 if 0 < i < steps else 0.5
total += w * math.cos(n * t - x * math.sin(t))
return total / steps



 

N = 30000
STEP = R / N
HEIGHT = [-A0 * bessel(0, K * STEP * i) for i in range(N + 1)]
RIM = HEIGHT[N]
HEIGHT = [h - RIM for h in HEIGHT] # measure everything from the rim



 

def height(r):
return HEIGHT[max(0, min(N, int(round(r / STEP))))]



 

# ---- how far the disc actually reaches once it's curved ----
# This caught me out. The flat disc is 300 mm but the material has to travel
# along the wave, not straight, so the finished thing comes out smaller.
# The ribs live in the finished shape, so they use this radius, not 150.
walk = 0.0
R_PROJ = R
for i in range(1, N + 1):
walk += math.hypot(STEP, HEIGHT[i] - HEIGHT[i - 1])
if walk >= R:
R_PROJ = STEP * i
break


 

RIB_R1 = R_PROJ - MARGIN
BASE = min(HEIGHT) - CLEAR
RIB_L = RIB_R1 - RIB_R0


 

# --- draw it: wavy top left to right, then straight back along the bottom ---
X0, Y0 = 5.0, 5.0 + (max(HEIGHT) - BASE)
pts = []
steps = 400
for i in range(steps + 1):
r = RIB_R0 + RIB_L * i / steps
pts.append((X0 + (r - RIB_R0), Y0 - (height(r) - BASE)))
d = "M " + " L ".join(f"{p[0]:.3f} {p[1]:.3f}" for p in pts)
d += f" L {X0 + RIB_L:.3f} {Y0:.3f} L {X0:.3f} {Y0:.3f} Z"


 

W, H = RIB_L + 10, Y0 + 5
svg = [f'<svg xmlns="http://www.w3.org/2000/svg" width="{W:.0f}mm" height="{H:.0f}mm" '
f'viewBox="0 0 {W:.0f} {H:.0f}">',
'<g fill="none" stroke="#000000" stroke-width="0.1">',
f'<path d="{d}"/>', '</g></svg>']
open(OUT, "w").write("\n".join(svg))


 

edge = 0.0
for i in range(1, len(pts)):
edge += math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1])


 

print(f"{OUT} written - cut 12 of these")
print(f"flat disc is {2 * R:.0f} mm, curved it ends up {2 * R_PROJ:.0f} mm")
print(f"rib runs r={RIB_R0} to r={RIB_R1:.1f}, so {RIB_L:.1f} mm long")
print(f"baseline sits {-BASE:.2f} mm below the disc rim")
print()
print(" r height above baseline")
for rr in (12, 25, 43, 60, 79, 100, 114, 130, RIB_R1):
print(f"{rr:6.1f} {height(rr) - BASE:9.2f} mm")
print()
print(f"tallest {max(height(RIB_R0 + RIB_L * i / 400) - BASE for i in range(401)):.1f} mm, "
f"shortest {min(height(RIB_R0 + RIB_L * i / 400) - BASE for i in range(401)):.1f} mm")
print(f"one rib is {(edge + RIB_L + 2 * (height(RIB_R0) - BASE)) / 1000:.2f} m of cutting, "
f"x12 = {12 * (edge + RIB_L + 2 * (height(RIB_R0) - BASE)) / 1000:.2f} m")
print(f"spacing at the rim {2 * math.pi * RIB_R1 / 12:.0f} mm")
 
"""
Ripple lamp - hub generator.


 

The hub is the little disc that holds the 12 ribs at 30 degrees apart.
Slots are open at the rim so a rib slides in sideways along the table.
They can't drop in from above, a rib is 131 mm long and the slot is 26.


 

I cut this twice and glue the two together, 7 mm of grip instead of 3.5
keeps the ribs from wobbling.
"""


 

import math


 

# ---- the important bit ----
# My sheet was sold as 4 mm and calipers say 3.5. It also isn't even across
# the sheet, I get about +/- 0.3 mm from corner to corner. First time round I
# used 3.65 mm slots and 4 of the 12 ribs wouldn't go in, so now I measure the
# THICKEST spot I can find and add clearance on top of that.
T_MEASURED = 3.5 # thickest reading I got with the calipers
CLEARANCE = 0.5 # covers sheet variation plus the charring from the laser
SLOT_W = T_MEASURED + CLEARANCE


 

HUB_R = 38.0 # hub radius
SLOT_R0 = 12.0 # slot bottom, this is what sets where the rib stops
N_RIB = 12


 

# Small comb I cut first to check the fit before committing to the hub.
# Each tooth gap is 0.1 mm wider than the last.
MAKE_TEST_COMB = True
COMB_START = 3.7
COMB_STEP = 0.1
COMB_N = 6


 

OUT = "hub.svg"


 

paths = []
HX = HY = HUB_R + 5.0


 

# ---- hub outline, one closed path ----
# Going round: arc along the rim, dive in to the slot bottom, round the end,
# back out, arc to the next slot.
hw = SLOT_W / 2
t_out = math.sqrt(HUB_R ** 2 - hw ** 2) # where the slot side meets the rim
d = []
first = None
for k in range(N_RIB):
a = k * 2 * math.pi / N_RIB
ca, sa = math.cos(a), math.sin(a)


 

def pt(t, off):
return (HX + t * ca - off * sa, HY + t * sa + off * ca)


 

out_m, in_m = pt(t_out, -hw), pt(SLOT_R0, -hw)
in_p, out_p = pt(SLOT_R0, hw), pt(t_out, hw)
if k == 0:
first = out_m
d.append(f"M {out_m[0]:.3f} {out_m[1]:.3f}")
else:
d.append(f"A {HUB_R:.3f} {HUB_R:.3f} 0 0 1 {out_m[0]:.3f} {out_m[1]:.3f}")
d.append(f"L {in_m[0]:.3f} {in_m[1]:.3f}")
d.append(f"A {hw:.3f} {hw:.3f} 0 0 1 {in_p[0]:.3f} {in_p[1]:.3f}")
d.append(f"L {out_p[0]:.3f} {out_p[1]:.3f}")
d.append(f"A {HUB_R:.3f} {HUB_R:.3f} 0 0 1 {first[0]:.3f} {first[1]:.3f} Z")
paths.append(" ".join(d))


 

cut = 2 * math.pi * HUB_R + N_RIB * (2 * (t_out - SLOT_R0) + math.pi * hw)


 

# ---- fit test comb ----
W = 2 * HUB_R + 10
H = 2 * HUB_R + 10
if MAKE_TEST_COMB:
cw, ch, tooth = 10.0, 22.0, 6.0
x0, y0 = 5.0, H + 8.0
total_w = COMB_N * (cw + COMB_START) + 10
paths.append(f"M {x0:.3f} {y0:.3f} L {x0 + total_w:.3f} {y0:.3f} "
f"L {x0 + total_w:.3f} {y0 + ch:.3f} L {x0:.3f} {y0 + ch:.3f} Z")
x = x0 + 5.0
for i in range(COMB_N):
w = COMB_START + i * COMB_STEP
paths.append(f"M {x:.3f} {y0:.3f} L {x + w:.3f} {y0:.3f} "
f"L {x + w:.3f} {y0 + tooth + 6:.3f} L {x:.3f} {y0 + tooth + 6:.3f} Z")
cut += 2 * (w + tooth + 6)
x += w + cw
H = y0 + ch + 5
W = max(W, x0 + total_w + 5)


 

svg = [f'<svg xmlns="http://www.w3.org/2000/svg" width="{W:.0f}mm" height="{H:.0f}mm" '
f'viewBox="0 0 {W:.0f} {H:.0f}">', '<g fill="none" stroke="#000000" stroke-width="0.1">']
svg += [f'<path d="{p}"/>' for p in paths]
svg.append('</g></svg>')
open(OUT, "w").write("\n".join(svg))


 

print(f"{OUT} written")
print(f"hub {2 * HUB_R:.0f} mm across, {N_RIB} open slots")
print(f"slot width {SLOT_W:.2f} mm for {T_MEASURED} mm plywood "
f"({CLEARANCE} mm clearance)")
print(f"slot depth {HUB_R - SLOT_R0:.0f} mm, tooth {2 * math.pi * HUB_R / N_RIB - SLOT_W:.1f} mm wide")
print(f"solid middle {2 * SLOT_R0:.0f} mm across")
if MAKE_TEST_COMB:
widths = ", ".join(f"{COMB_START + i * COMB_STEP:.1f}" for i in range(COMB_N))
print(f"test comb slots: {widths} mm")
print(f"cut length {cut / 1000:.2f} m - cut TWO of the hub")
print(f"sheet {W:.0f} x {H:.0f} mm")


 


 

"""
Ripple lamp - top disc generator.


 

Cuts a 300 mm disc with one long variable-pitch spiral slot in it.
Once it comes off the laser the whole thing is basically one 6.6 m
ribbon held at the hub and at the rim, so it can drape over the ribs.
"""


 

import math


 

# ---- disc ----
R = 150.0 # disc radius, so 300 mm across
R_START = 15.0 # spiral starts here, everything inside stays solid
R_END = 138.5 # spiral stops here, the rest is my glue land for the cylinder
P0 = 6.0 # radial pitch near the centre
P1 = 11.0 # radial pitch out at the rim
SLOT_W = 2.0 # slot width, this is also my closing budget when it bends
T = 3.5 # actual measured thickness of my plywood


 

# ---- wave shape ---
# I'm using the J0 Bessel function instead of a cosine because that's the real
# shape a drop makes on a round membrane, and the peak comes out gentler.
A0 = 9.0 # amplitude
KZ = 13.3237 # 3rd max of J0 -> dip in the middle, dip at the rim
K = KZ / R


 

# --- transport tabs ----
# Without these the spiral unwinds the second I lift it off the bed.
# They all sit on one radius so I can snap them with a single pass of a blade.
TAB_ANGLE = 0.0
TAB_W = 0.6


 

OUT = "disc.svg"



 

def bessel(n, x, steps=1500):
"""J_n via the integral form. No scipy needed."""
total = 0.0
for i in range(steps + 1):
t = math.pi * i / steps
w = 1.0 if 0 < i < steps else 0.5
total += w * math.cos(n * t - x * math.sin(t))
return total / steps



 

# Precompute the profile once, it's slow otherwise.
N = 20000
STEP = R / N
HEIGHT = [-A0 * bessel(0, K * STEP * i) for i in range(N + 1)]



 

def height(r):
return HEIGHT[max(0, min(N, int(r / STEP)))]



 

def curvature(r, h=1.0):
return (height(r + h) - 2 * height(r) + height(r - h)) / h ** 2



 

def pitch(r):
"""Tighter pitch in the middle where the wood has to work hardest."""
u = (r - R_START) / (R_END - R_START)
return P0 + (P1 - P0) * max(0.0, min(1.0, u))



 

# ---- walk the spiral ----
CX = CY = 155.0
polar = []
theta, r = 0.0, R_START
d_theta = 0.0008
while r < R_END:
polar.append((theta, r))
r += pitch(r) / (2 * math.pi) * d_theta
theta += d_theta
polar.append((theta, R_END))
TURNS = theta / (2 * math.pi)


 

points = [(CX + rr * math.cos(th), CY + rr * math.sin(th)) for th, rr in polar]


 

# running length along the centreline, I need it to place the tabs
length = [0.0]
for i in range(1, len(points)):
length.append(length[-1] + math.hypot(points[i][0] - points[i - 1][0],
points[i][1] - points[i - 1][1]))
RIBBON = length[-1]


 

# every time the spiral crosses the tab radius, leave a bridge
gaps = []
for i in range(1, len(polar)):
a_prev = (polar[i - 1][0] - TAB_ANGLE) % (2 * math.pi)
a_now = (polar[i][0] - TAB_ANGLE) % (2 * math.pi)
if a_now < a_prev and 15 < length[i] < RIBBON - 15:
gaps.append((length[i] - TAB_W / 2, length[i] + TAB_W / 2))



 

def slot_outline(seg):
"""Offset a run of centreline points both ways and cap the ends round."""
hw = SLOT_W / 2
left, right = [], []
n = len(seg)
for i in range(n):
a, b = max(0, i - 1), min(n - 1, i + 1)
dx, dy = seg[b][0] - seg[a][0], seg[b][1] - seg[a][1]
m = math.hypot(dx, dy)
if m == 0:
continue
nx, ny = -dy / m, dx / m
left.append((seg[i][0] + hw * nx, seg[i][1] + hw * ny))
right.append((seg[i][0] - hw * nx, seg[i][1] - hw * ny))
d = "M " + " L ".join(f"{p[0]:.3f} {p[1]:.3f}" for p in left)
d += f" A {hw:.3f} {hw:.3f} 0 0 1 {right[-1][0]:.3f} {right[-1][1]:.3f}"
d += " L " + " L ".join(f"{p[0]:.3f} {p[1]:.3f}" for p in reversed(right[:-1]))
d += f" A {hw:.3f} {hw:.3f} 0 0 1 {left[0][0]:.3f} {left[0][1]:.3f} Z"
return d



 

paths = [f"M {CX - R:.3f} {CY:.3f} A {R:.3f} {R:.3f} 0 1 1 {CX + R:.3f} {CY:.3f} "
f"A {R:.3f} {R:.3f} 0 1 1 {CX - R:.3f} {CY:.3f} Z"]
cut = 2 * math.pi * R


 

# break the spiral into runs, skipping the tab positions
run = []
for i, p in enumerate(points):
in_gap = any(g0 <= length[i] <= g1 for g0, g1 in gaps)
if in_gap:
if len(run) > 3:
paths.append(slot_outline(run))
cut += 2 * (length[i] - length[i - len(run)]) + math.pi * SLOT_W
run = []
else:
run.append(p)
if len(run) > 3:
paths.append(slot_outline(run))
cut += 2 * (length[-1] - length[-len(run)]) + math.pi * SLOT_W


 

SIZE = 310
svg = [f'<svg xmlns="http://www.w3.org/2000/svg" width="{SIZE}mm" height="{SIZE}mm" '
f'viewBox="0 0 {SIZE} {SIZE}">', '<g fill="none" stroke="#000000" stroke-width="0.1">']
svg += [f'<path d="{d}"/>' for d in paths]
svg.append('</g></svg>')
open(OUT, "w").write("\n".join(svg))


 

# ---- sanity check before I waste a sheet ----
print(f"{OUT} written")
print(f"single spiral, {TURNS:.1f} turns, pitch {P0} -> {P1} mm")
print(f"ribbon length {RIBBON / 1000:.2f} m")
print(f"{len(gaps)} transport tabs, {TAB_W} mm each")
print(f"solid centre {2 * (R_START - SLOT_W / 2):.0f} mm across, "
f"solid rim {R - R_END - SLOT_W / 2:.1f} mm wide")
print()
print(" r pitch height slot closes ribbon w/t")
for rr in (15, 25, 43, 60, 79, 100, 114, 130, 150):
c = abs(curvature(rr))
p = pitch(rr)
print(f"{rr:5.0f} {p:6.1f} {height(rr) - height(R):+8.2f} "
f"{T * c * p:9.2f} mm {(p - SLOT_W) / T:9.2f}")
print()
print(f"wave height {max(HEIGHT) - min(HEIGHT):.1f} mm")
print(f"total cut {cut / 1000:.1f} m")


 


 

"""
Ripple lamp - base ring generator.


 

A flat strip with a living hinge cut into it, so it rolls up into the ring the
disc sits on. The LED strip goes on the inside face near the top and fires
inward across the underside of the waves.


 

The strip is 875 mm around, which doesn't fit my sheet, so it comes out in
three pieces joined with splice plates on the inside.
"""


 

import math


 

# ---- geometry that has to agree with the disc ----
R = 150.0 # flat disc radius
A0 = 9.0
KZ = 13.3237
K = KZ / R
T = 3.5 # measured plywood thickness


 

RING_OUT_R = 141.0 # outside radius of the ring
HEIGHT_MM = 45.0 # how tall the ring is
N_SEG = 3 # pieces, each has to fit my sheet


 

# ---- living hinge ----
HINGE_PITCH = 8.0 # spacing within one row
MARGIN = 3.0 # keep slits off the top and bottom edges
OVERLAP = 3.0 # how much the two rows overlap in the middle
END_SOLID = 15.0 # uncut zone at each end, that's the glue land


 

SPLICE_W, SPLICE_H = 30.0, 39.0


 

OUT = "ring.svg"



 

def bessel(n, x, steps=1500):
total = 0.0
for i in range(steps + 1):
t = math.pi * i / steps
w = 1.0 if 0 < i < steps else 0.5
total += w * math.cos(n * t - x * math.sin(t))
return total / steps



 

# Work out how big the disc really ends up and where its solid rim lands,
# because the ring has to glue onto that band and nowhere else.
N = 30000
STEP = R / N
H = [-A0 * bessel(0, K * STEP * i) for i in range(N + 1)]
RIM = H[N]
H = [h - RIM for h in H]


 

walk = [0.0]
for i in range(1, N + 1):
walk.append(walk[-1] + math.hypot(STEP, H[i] - H[i - 1]))



 

def projected(flat_r):
"""Where a point that sits at flat_r on the flat disc ends up once curved."""
for i in range(N + 1):
if walk[i] >= flat_r:
return STEP * i
return R



 

R_PROJ = projected(R) # finished disc radius
RIM_INNER = projected(139.5) # inner edge of the solid rim, curved
RING_IN_R = RING_OUT_R - T
MID_R = RING_OUT_R - T / 2
LENGTH = 2 * math.pi * MID_R # measured on the middle of the wall
SEG_L = LENGTH / N_SEG


 

paths = []
cut = 0.0



 

def rect(x, y, w, h):
return (f"M {x:.3f} {y:.3f} L {x + w:.3f} {y:.3f} "
f"L {x + w:.3f} {y + h:.3f} L {x:.3f} {y + h:.3f} Z")



 

# ---- the three strips ----
# Two rows of slits, offset by half a pitch, overlapping in the middle. The
# overlap is what actually does the bending - the wood twists there.
row_a = (MARGIN, (HEIGHT_MM + OVERLAP) / 2)
row_b = ((HEIGHT_MM - OVERLAP) / 2, HEIGHT_MM - MARGIN)


 

for seg in range(N_SEG):
x0, y0 = 3.0, 3.0 + seg * (HEIGHT_MM + 8)
paths.append(rect(x0, y0, SEG_L, HEIGHT_MM))
cut += 2 * (SEG_L + HEIGHT_MM)
x = x0 + END_SOLID
row = 0
while x < x0 + SEG_L - END_SOLID:
a, b = row_a if row % 2 == 0 else row_b
paths.append(f"M {x:.3f} {y0 + a:.3f} L {x:.3f} {y0 + b:.3f}")
cut += b - a
x += HINGE_PITCH / 2
row += 1


 

# ---- splice plates, glued on the inside over each butt joint ----
sy = 3.0 + N_SEG * (HEIGHT_MM + 8) + 5
for k in range(N_SEG):
paths.append(rect(3.0 + k * (SPLICE_W + 6), sy, SPLICE_W, SPLICE_H))
cut += 2 * (SPLICE_W + SPLICE_H)


 

W = max(3.0 + SEG_L + 3, 3.0 + N_SEG * (SPLICE_W + 6) + 3)
HT = sy + SPLICE_H + 3
svg = [f'<svg xmlns="http://www.w3.org/2000/svg" width="{W:.0f}mm" height="{HT:.0f}mm" '
f'viewBox="0 0 {W:.0f} {HT:.0f}">',
'<g fill="none" stroke="#000000" stroke-width="0.1">']
svg += [f'<path d="{p}"/>' for p in paths]
svg.append('</g></svg>')
open(OUT, "w").write("\n".join(svg))


 

print(f"{OUT} written")
print(f"finished disc {2 * R_PROJ:.0f} mm across")
print(f"ring {2 * RING_OUT_R:.0f} mm outside, {2 * RING_IN_R:.0f} mm inside")
print(f"overhang {R_PROJ - RING_OUT_R:.1f} mm all round")
print(f"strip {LENGTH:.0f} mm long -> {N_SEG} pieces of {SEG_L:.1f} mm")
print()
print("checks:")
print(f" disc solid rim sits between r={RIM_INNER:.1f} and r={R_PROJ:.1f} once curved")
print(f" ring wall sits between r={RING_IN_R:.1f} and r={RING_OUT_R:.1f}")
ok = RIM_INNER <= RING_IN_R and RING_OUT_R <= R_PROJ
print(f" wall lands on the glue band: {'yes' if ok else 'NO'}")
print(f" ribs must stop before r={RING_IN_R - 1:.1f} - set MARGIN in rib.py to 10")
print(f" bend radius {MID_R:.1f} mm, strain without the hinge would be "
f"{T / 2 / MID_R * 100:.2f}%")
print(f" LED strip runs about {2 * math.pi * RING_IN_R:.0f} mm around the inside")
print()
print(f"cut length {cut / 1000:.2f} m")
print(f"sheet {W:.0f} x {HT:.0f} mm")


 


 

Comentarios

Remixes

También te puede gustar

Zen LED Relaxation Lamp
GIF

Lámpara de relajación LED Zen

Little Mole
Little Mole
10
56
Helix Spiral Table Lamp - Mid-Century Modern Desk Light

Lámpara de mesa de espiral Helix - Luz de escritorio moderna de mediados de siglo

Bearded Printer
Bearded Printer
2
6
Hexagon Directional Tower Lamp with Roof

Lámpara de torre direccional hexagonal con tejado

demarcusalexan
demarcusalexan
14
22
Umbrella shaped wooden table lamp with warm ambient lighting

Lámpara de mesa de madera con forma de paraguas y iluminación ambiental cálida

douglaslibby
douglaslibby
0
2
Wooden moon and mountain lamp

Luna de madera y lámpara de montaña

hobbycollector
hobbycollector
8
30
Lampe modulable à abat-jour interchangeable et projections  lumineuses

Lámpara regulable con pantalla intercambiable y proyecciones de luz

manu.jung
manu.jung
14
42
Hamsa Hand lamp.

Lámpara de mano Hamsa.

mhwoodworking
mhwoodworking
19
56
Rectangular wooden desk lamp with blue LED light and organic cutout pattern
$1.99
$1.99
Créditos199

Lámpara de escritorio rectangular de madera con luz LED azul y patrón de recortes orgánicos

Pogaceanu Cornel
Pogaceanu Cornel
0
Wooden Lantern Laser Cut.  Decorative Lamp. Abstract Wave Pattern. Home Decor. Modern Interior

Farol de madera cortado con láser. Lámpara decorativa. Patrón abstracto de ondas. Decoración del hogar. Interior moderno

Lumen Cuts
Lumen Cuts
13
132
Personalized Heart Horse LED Lamp – Laser Cut Night Light

Lámpara LED Heart Horse personalizada – Luz nocturna cortada con láser

axiolaser
axiolaser
2
2
Western themed table lamp with horse and native american motif fabric shade

Lámpara de mesa con temática del Oeste y pantalla de tela con motivos de caballos y nativos americanos

jimabraham1
jimabraham1
4
2
Modern Geometric Spiral Table Lamp with Warm Ambient Lighting

Lámpara de mesa geométrica moderna en espiral con iluminación ambiental cálida

najm creative design
najm creative design
36
168
Geometric Candle Decoration / Table Lamp

Decoración geométrica de velas / Lámpara de mesa

RayRayRatCrafts
RayRayRatCrafts
1
2
Articulated wooden desk lamp with slatted shade
Ganador del Concurso

Lámpara de escritorio de madera articulada con pantalla de listones

douglaslibby
douglaslibby
22
74
LED Acrylic / Glass Night Lamp with Wooden Base Home Decor

Lámpara de noche LED acrílica / de vidrio con base de madera

Engraviz
Engraviz
0
2
Laser Engraved Acrylic LED Light with Abstract Human Figure Design

Luz LED acrílica grabada con láser con diseño abstracto de figura humana

shaunsokalski
shaunsokalski
6
41
Table Lamp

Lámpara de mesa

ron
ron
295
1300
3D Led lamps bundle. Acrylic lantern laser cut files. Wooden nightlight lamp. Boho illuminated led sign. Cacti svg. Swan. Mushroom. Wine
$2.20
$2.20
Créditos220

Paquetes de lámparas LED 3D. Archivos de láser con farolillos acrílicos. Lámpara de luz nocturna de madera. Cartel LED Boho iluminado. Cactus SVG. Swan. Setas. Vino

Digital Idea
Digital Idea
17