From 231d1e2e54b04f38d12fd26bef65ab934511c920 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sat, 17 Oct 2026 18:45:17 +0200 Subject: [PATCH] Trennwaende (lange Wuende 1-9 mit eindeutigen Fuessen, Trennstuecke) ergaenzt; gemeinsame Einstellungen in gemeinsam.scad; Rueckwand mit Steckschlitzen und Wandnummern Co-Authored-By: Claude Sonnet 5.5 --- cad/openscad/gemeinsam.scad | 58 ++++++++++++++++ cad/openscad/rueckwand.scad | 67 ++++++------------- cad/openscad/trennwaende.scad | 122 ++++++++++++++++++++++++++++++++++ cad/openscad/wortfolie.scad | 20 +----- 4 files changed, 205 insertions(+), 62 deletions(-) create mode 100644 cad/openscad/gemeinsam.scad create mode 100644 cad/openscad/trennwaende.scad diff --git a/cad/openscad/gemeinsam.scad b/cad/openscad/gemeinsam.scad new file mode 100644 index 0000000..e954e9e --- /dev/null +++ b/cad/openscad/gemeinsam.scad @@ -0,0 +1,58 @@ +// Gemeinsame Einstellungen und Maße für wortfolie.scad, rueckwand.scad und +// trennwaende.scad. Wird per include eingebunden, hier die Rahmengröße wählen. + +// ---------- Rahmen ---------- +// Rahmengröße (Bildfläche des IKEA SANNAHED): 25, 35 oder 50 (cm) +rahmen_cm = 25; // [25, 35, 50] + +spiel_mm = 1; // Luft pro Seite zwischen Platte/Folie und Rahmen-Innenmaß +rand_mm = 15; // freier Rand von der Kante bis zum Buchstabenfeld + // (Rahmenfalz verdeckt ca. 1 cm der Bildfläche) +minutenpunkte = false; // 4 Punkte/LEDs in den Ecken für die Minuten + +// ---------- Material und Aufbau ---------- +mdf_mm = 2.5; // Materialstärke der Rückwand und der Trennwände +tiefe_mm = 20; // Höhe der Trennwände (Abstand Rückwand bis Folie) +toleranz = 0.2; // Luft in Stecklöchern +schlitz_b = 10; // Breite der Füße/Schlitze der Trennwände + +// ---------- Raster ---------- +spalten = 11; +zeilen = 10; + +// Wörter mit LED-Streifen: [Zeile, erste Spalte, Anzahl Buchstaben, Name] +// Zeile 0 = oben, Spalte 0 = links. Das "S" von EINS ist ein eigener Streifen, +// damit es bei "ein Uhr" (EIN) aus und bei "viertel vor eins" (EINS) an sein kann. +woerter = [ + [0, 0, 2, "ES"], [0, 3, 3, "IST"], [0, 7, 4, "FÜNF"], + [1, 0, 7, "ZWANZIG"], [1, 7, 4, "ZEHN"], + [2, 0, 7, "VIERTEL"], [2, 8, 3, "VOR"], + [3, 0, 4, "HALB"], [3, 4, 3, "NTP"], [3, 7, 4, "NACH"], + [4, 0, 4, "NEUN"], [4, 4, 3, "API"], [4, 7, 4, "FÜNF"], + [5, 0, 4, "ZWEI"], [5, 4, 3, "RTC"], [5, 7, 3, "EIN"], [5, 10, 1, "S"], + [6, 0, 4, "DREI"], [6, 4, 3, "ESP"], [6, 7, 4, "VIER"], + [7, 0, 4, "ACHT"], [7, 6, 5, "SECHS"], + [8, 0, 6, "SIEBEN"], [8, 6, 5, "ZWÖLF"], + [9, 0, 3, "UHR"], [9, 4, 3, "ELF"], [9, 7, 4, "ZEHN"] +]; + +// Trennwand n (1 = oben) steht zwischen Zeile n-1 und n. Ihre drei Füße stecken in +// diesen Spalten der Rückwand. Jede Kombination gibt es nur einmal, auch gespiegelt: +// so passt jede Wand nur an genau eine Stelle. +fuss_spalten = [ + [2, 3, 5], [4, 6, 8], [3, 4, 5], [4, 5, 8], [2, 4, 7], + [3, 6, 7], [6, 7, 8], [2, 4, 5], [2, 3, 7] +]; + +// ---------- Berechnung ---------- +platte = rahmen_cm * 10 - 2 * spiel_mm; // Kantenlänge von Platte/Folie +feld = platte - 2 * rand_mm; // Kantenlänge des Buchstabenfelds +raster_a = feld / spalten; // Zellenabstand (quadratische Zellen) +mass = raster_a / 19.8; // Skalierung der Beschriftung + +// Zellenmitte (Spalte s, Zeile z), Ursprung = Plattenmitte, y nach oben +function zx(s) = (s - (spalten - 1) / 2) * raster_a; +function zy(z) = ((zeilen - 1) / 2 - z) * raster_a; + +// y-Mitte der Trennwand n (n = 1 .. zeilen-1), zwischen Zeile n-1 und n +function wand_y(n) = (zy(n - 1) + zy(n)) / 2; diff --git a/cad/openscad/rueckwand.scad b/cad/openscad/rueckwand.scad index a07ee90..b9f4a19 100644 --- a/cad/openscad/rueckwand.scad +++ b/cad/openscad/rueckwand.scad @@ -4,6 +4,7 @@ // Das LED-Raster ist identisch mit wortfolie.scad, damit LEDs und Buchstaben passen. // // Export als 2D: F6 rendern, dann Datei -> Export -> als DXF / SVG. +// Die Steckschlitze nehmen die Füße der Trennwände aus trennwaende.scad auf. // Für den Laser: erst teil = "schneiden", dann teil = "gravur" exportieren. // Rückwand der Wortuhr (Trägerplatte für die LEDs) für IKEA SANNAHED @@ -19,53 +20,19 @@ // Export als 2D: F6 rendern, dann Datei -> Export -> als DXF / SVG. // Für den Laser: erst teil = "schneiden", dann teil = "gravur" exportieren. -// ---------- Einstellungen ---------- -// Rahmengröße (Bildfläche des SANNAHED): 25, 35 oder 50 (cm) -rahmen_cm = 25; // [25, 35, 50] +include // Rahmengröße (rahmen_cm), Wortliste, Fußpositionen +// ---------- Einstellungen ---------- // Welcher Teil soll ausgegeben werden? teil = "beide"; // ["beide" (Vorschau), "schneiden", "gravur"] -spiel_mm = 1; // Luft pro Seite zwischen Platte und Rahmen-Innenmaß -rand_mm = 15; // wie in wortfolie.scad (muss gleich bleiben!) fase_mm = 10; // abgeschrägte Ecken oben links und unten rechts (klein genug für den Minutenpunkt) led_pitch = 1000 / 60; // LED-Abstand des Streifens (60 LED/m) streifen_b = 10; // Breite des LED-Streifens (WS2812) led_marke_d = 5; // Ø der LED-Markierungen (Gravur) -schlitz_b = 10; // Kabeldurchführung zwischen den Zeilen (Breite) -schlitz_h = 3.5; // und Höhe -minutenpunkte = false; // 4 einzelne LEDs in den Ecken (wie in wortfolie.scad) dicke_mm = 0; // 0 = flache 2D-Ausgabe (für Laser/DXF), >0 = 3D-Vorschau -// ---------- Raster ---------- -spalten = 11; -zeilen = 10; - -// Wörter mit LED-Streifen: [Zeile, erste Spalte, Anzahl Buchstaben, Name] -// Zeile 0 = oben, Spalte 0 = links. Das "S" von EINS ist ein eigener Streifen, -// damit es bei "ein Uhr" (EIN) aus und bei "viertel vor eins" (EINS) an sein kann. -woerter = [ - [0, 0, 2, "ES"], [0, 3, 3, "IST"], [0, 7, 4, "FÜNF"], - [1, 0, 7, "ZWANZIG"], [1, 7, 4, "ZEHN"], - [2, 0, 7, "VIERTEL"], [2, 8, 3, "VOR"], - [3, 0, 4, "HALB"], [3, 4, 3, "NTP"], [3, 7, 4, "NACH"], - [4, 0, 4, "NEUN"], [4, 4, 3, "API"], [4, 7, 4, "FÜNF"], - [5, 0, 4, "ZWEI"], [5, 4, 3, "RTC"], [5, 7, 3, "EIN"], [5, 10, 1, "S"], - [6, 0, 4, "DREI"], [6, 4, 3, "ESP"], [6, 7, 4, "VIER"], - [7, 0, 4, "ACHT"], [7, 6, 5, "SECHS"], - [8, 0, 6, "SIEBEN"], [8, 6, 5, "ZWÖLF"], - [9, 0, 3, "UHR"], [9, 4, 3, "ELF"], [9, 7, 4, "ZEHN"] -]; - -platte = rahmen_cm * 10 - 2 * spiel_mm; -feld = platte - 2 * rand_mm; -raster_a = feld / spalten; -fase = fase_mm; -mass = raster_a / 19.8; // Skalierung der Beschriftung - -// Zellenmitte (Spalte s, Zeile z), Ursprung = Plattenmitte, y nach oben -function zx(s) = (s - (spalten - 1) / 2) * raster_a; -function zy(z) = ((zeilen - 1) / 2 - z) * raster_a; +fase = fase_mm; // Anzahl LEDs, die am Stück in die Wortbreite passen (höchstens eine je Buchstabe) function led_anzahl(w) = min(w[2], floor(w[2] * raster_a / led_pitch)); @@ -77,12 +44,20 @@ module umriss() { polygon([[-h + fase, h], [h, h], [h, -h + fase], [h - fase, -h], [-h, -h], [-h, h - fase]]); } -// Kabeldurchführungen: die LED-Reihen laufen im Zickzack, -// Zeile 0 von links nach rechts, Zeile 1 zurück usw. +// Steckschlitze für die Füße der Trennwände (siehe trennwaende.scad): +// drei je Wand, Position nur für genau diese Wand passend. module schlitze() { - for (z = [0 : zeilen - 2]) - translate([zx(z % 2 == 0 ? spalten - 1 : 0), (zy(z) + zy(z + 1)) / 2]) - square([schlitz_b, schlitz_h], center = true); + for (n = [1 : zeilen - 1], c = fuss_spalten[n - 1]) + translate([zx(c), wand_y(n)]) + square([schlitz_b, mdf_mm + toleranz], center = true); +} + +// Nummer der Trennwand (von oben nach unten) im linken Rand neben ihrem Schlitz +module wandnummern() { + for (n = [1 : zeilen - 1]) + translate([-platte / 2 + rand_mm / 2, wand_y(n)]) + text(str(n), size = 4 * mass, font = "Liberation Sans:style=Bold", + halign = "center", valign = "center"); } // Ein Streifenstück je Wort: Umriss + LED-Markierungen, mittig unter dem Wort @@ -108,15 +83,16 @@ module minuten_marken() { // Pfeil mit Beschriftung DATA unter jeder Zeile, am Zeilenanfang. // Die Reihen laufen im Zickzack: gerade Zeilen nach rechts, ungerade nach links. module pfeil(z) { - l = 12 * mass; + l = 7 * mass; r = z % 2 == 0 ? 1 : -1; x0 = r > 0 ? zx(0) - raster_a / 2 + 2 : zx(spalten - 1) + raster_a / 2 - 2; - translate([x0, zy(z) - raster_a / 2]) { + // unter der Trennwand (Mitte der Lücke), damit sie nicht verdeckt wird + translate([x0, zy(z) - raster_a / 2 - (mdf_mm / 2 + 0.3 + l * 0.18)]) { translate([r > 0 ? 0 : -l * 0.6, -l * 0.07]) square([l * 0.6, l * 0.14]); translate([r * l * 0.6, 0]) polygon([[0, -l * 0.18], [r * l * 0.4, 0], [0, l * 0.18]]); translate([r * (l + 2 * mass), 0]) - text("DATA", size = 3 * mass, font = "Liberation Sans", + text("DATA", size = 2.2 * mass, font = "Liberation Sans", halign = r > 0 ? "left" : "right", valign = "center"); } } @@ -126,6 +102,7 @@ module gravur() { for (w = woerter) streifen(w); minuten_marken(); for (z = [0 : zeilen - 1]) pfeil(z); + wandnummern(); } // "beide" ist nur eine Vorschau: die Gravur erscheint als Aussparung in der Platte. diff --git a/cad/openscad/trennwaende.scad b/cad/openscad/trennwaende.scad new file mode 100644 index 0000000..e96cd67 --- /dev/null +++ b/cad/openscad/trennwaende.scad @@ -0,0 +1,122 @@ +// Trennwände der Wortuhr für IKEA SANNAHED (Lasercut, MDF) +// Vorlage: cad/ALT/Trennwaende_fuer_Laser.dxf +// +// - 9 lange Wände (zwischen den 10 Zeilen), von oben nach unten mit 1 bis 9 graviert. +// Jede hat drei Füße an einer eigenen Stelle und passt nur in ihre Schlitze in +// rueckwand.scad. Auch gespiegelt gibt es keine zweite passende Stelle. +// - kurze Trennstücke zwischen den Wörtern einer Zeile, u. a. zwischen EIN und S. +// Sie stecken mit Zapfen in Schlitzen der langen Wände. +// - Kabeldurchlässe: unten in den Trennstücken (Kabel zwischen den Streifen eines +// Wortes der Zeile) und in den langen Wänden am Zeilenwechsel (Zickzack der LEDs). +// +// Export als 2D: F6 rendern, dann Datei -> Export -> als DXF / SVG. +// Für den Laser: erst teil = "schneiden", dann teil = "gravur" exportieren. + +include // Rahmengröße (rahmen_cm), Wortliste, Fußpositionen + +// ---------- Einstellungen ---------- +teil = "beide"; // ["beide" (Vorschau), "schneiden", "gravur"] + +zapfen_h = tiefe_mm * 0.25; // Höhe der Zapfen/Schlitze der Trennstücke +kabel_b = 8; // Breite der Kabeldurchlässe +kabel_h = 3.5; // Höhe der Kabeldurchlässe +abstand_mm = 3; // Abstand der Teile auf dem Laserbogen +nummer_gr = 8; // Größe der eingravierten Nummer + +// ---------- Berechnung ---------- +wand_l = platte - 1; // Länge der langen Wände +fuss_b = schlitz_b - toleranz; // Breite der Füße +// Zapfen/Schlitze: unterer und oberer Höhenbereich in der Wand, damit sich Zapfen +// von oben und unten an derselben Stelle nicht treffen +unten_y0 = tiefe_mm * 0.20; +oben_y0 = tiefe_mm * 0.60; + +// Trennstellen einer Zeile: x-Mitte zwischen zwei benachbarten Wörtern +function trenn_x(z) = + let (ws = [for (w = woerter) if (w[0] == z) w]) + [for (i = [0 : len(ws) - 2]) + (zx(ws[i][1] + ws[i][2] - 1) + zx(ws[i + 1][1])) / 2]; + +// Wand n liegt zwischen Zeile n-1 (darüber) und Zeile n (darunter) +// Trennstücke der Zeile darüber stecken im oberen, die darunter im unteren Schlitz. + +module wand(n) { + difference() { + union() { + translate([-wand_l / 2, 0]) square([wand_l, tiefe_mm]); + for (c = fuss_spalten[n - 1]) + translate([zx(c) - fuss_b / 2, -mdf_mm]) square([fuss_b, mdf_mm + 0.01]); + } + // Schlitze für die Zapfen der Trennstücke + for (x = trenn_x(n - 1)) + translate([x - (mdf_mm + toleranz) / 2, oben_y0]) square([mdf_mm + toleranz, zapfen_h + toleranz]); + for (x = trenn_x(n)) + translate([x - (mdf_mm + toleranz) / 2, unten_y0]) square([mdf_mm + toleranz, zapfen_h + toleranz]); + // Kabeldurchlass am Zeilenwechsel (ungerade Wand: rechts, gerade: links) + translate([zx(n % 2 == 1 ? spalten - 1 : 0) - kabel_b / 2, -0.01]) + square([kabel_b, kabel_h]); + } +} + +module wand_nummer(n) { + translate([-wand_l / 2 + nummer_gr * 1.2, tiefe_mm / 2]) + text(str(n), size = nummer_gr, font = "Liberation Sans:style=Bold", + halign = "center", valign = "center"); +} + +// Trennstück zwischen zwei Wörtern der Zeile z. Lokal: x läuft von oben nach unten +// (plattenhöhe), y ist die Tiefe. Das linke Ende stößt an die Wand über der Zeile +// (unterer Schlitz), das rechte an die Wand darunter (oberer Schlitz). +// Die erste und die letzte Zeile reichen bis zum Plattenrand. +function stueck_laenge(z) = + let (oben = z == 0 ? platte / 2 - 0.5 : zy(z) + raster_a / 2 - mdf_mm / 2, + unten = z == zeilen - 1 ? -platte / 2 + 0.5 : zy(z) - raster_a / 2 + mdf_mm / 2) + oben - unten; +function stueck_mitte(z) = // x-Position der Zeilenmitte im Stück + (z == 0 ? platte / 2 - 0.5 : zy(z) + raster_a / 2 - mdf_mm / 2) - zy(z); + +module stueck(z) { + l = stueck_laenge(z); + difference() { + union() { + square([l, tiefe_mm]); + if (z > 0) + translate([-mdf_mm, unten_y0]) square([mdf_mm + 0.01, zapfen_h]); + if (z < zeilen - 1) + translate([l - 0.01, oben_y0]) square([mdf_mm + 0.01, zapfen_h]); + } + translate([stueck_mitte(z) - kabel_b / 2, -0.01]) square([kabel_b, kabel_h]); + } +} + +// Alle Stücke: [Zeile] je Trennstelle +stuecke = [for (z = [0 : zeilen - 1]) for (x = trenn_x(z)) z]; + +// ---------- Anordnung auf dem Laserbogen ---------- +wand_hoehe = tiefe_mm + mdf_mm; // mit Füßen +function stueck_breite(z) = stueck_laenge(z) + 2 * mdf_mm; +stueck_pro_reihe = floor(wand_l / (stueck_breite(1) + abstand_mm)); +st_y0 = (zeilen - 1) * (wand_hoehe + abstand_mm) + abstand_mm; + +module bogen(zeigen) { + for (n = [1 : zeilen - 1]) + translate([0, (zeilen - 1 - n) * (wand_hoehe + abstand_mm) + mdf_mm]) { + if (zeigen == "schnitt") wand(n); + else wand_nummer(n); + } + if (zeigen == "schnitt") + for (i = [0 : len(stuecke) - 1]) + translate([-wand_l / 2 + mdf_mm + (i % stueck_pro_reihe) * (stueck_breite(1) + abstand_mm), + st_y0 + floor(i / stueck_pro_reihe) * (tiefe_mm + abstand_mm)]) + stueck(stuecke[i]); +} + +module ausgabe() { + if (teil == "schneiden") bogen("schnitt"); + else if (teil == "gravur") bogen("gravur"); + else difference() { bogen("schnitt"); bogen("gravur"); } +} +ausgabe(); + +echo(str("Lange Wände: ", zeilen - 1, " à ", wand_l, " x ", tiefe_mm, " mm, Trennstücke: ", len(stuecke), + ", Materialstärke ", mdf_mm, " mm")); diff --git a/cad/openscad/wortfolie.scad b/cad/openscad/wortfolie.scad index 5238b24..c8f6459 100644 --- a/cad/openscad/wortfolie.scad +++ b/cad/openscad/wortfolie.scad @@ -2,16 +2,11 @@ // Die Buchstaben sind Aussparungen in der (schwarzen) Folie. // Export als 2D: F6 rendern, dann Datei -> Export -> als DXF / SVG. -// ---------- Einstellungen ---------- -// Rahmengröße (Bildfläche des SANNAHED): 25, 35 oder 50 (cm) -rahmen_cm = 25; // [25, 35, 50] +include // Rahmengröße (rahmen_cm), Rand, Minutenpunkte -spiel_mm = 1; // Luft pro Seite zwischen Folie und Rahmen-Innenmaß -rand_mm = 15; // freier Rand von der Folienkante bis zum Buchstabenfeld - // (Rahmenfalz verdeckt ca. 1 cm der Bildfläche) +// ---------- Einstellungen ---------- buchstaben_anteil = 0.62; // Buchstabenhöhe relativ zum Zellenabstand schrift = "Liberation Sans:style=Bold"; -minutenpunkte = false; // 4 Punkte in den Ecken für die Minuten punkt_d_anteil = 0.18; // Punktdurchmesser relativ zum Zellenabstand dicke_mm = 0; // 0 = flache 2D-Ausgabe (für Laser/DXF), >0 = 3D-Vorschau @@ -31,18 +26,9 @@ raster = [ ]; // ---------- Berechnung ---------- -spalten = 11; -zeilen = len(raster); - -folie = rahmen_cm * 10 - 2 * spiel_mm; // Kantenlänge der Folie in mm -feld = folie - 2 * rand_mm; // Kantenlänge des Buchstabenfelds -raster_a = feld / spalten; // Zellenabstand (quadratische Zellen) +folie = platte; // Kantenlänge der Folie in mm buch_h = raster_a * buchstaben_anteil; // Buchstabengröße -// Mittelpunkt der Zelle (Spalte s, Zeile z), Ursprung = Folienmitte, y nach oben -function zx(s) = (s - (spalten - 1) / 2) * raster_a; -function zy(z) = ((zeilen - 1) / 2 - z) * raster_a; - module buchstaben() { for (z = [0 : zeilen - 1], s = [0 : spalten - 1]) translate([zx(s), zy(z)])