// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /* ITLISASAMPM */ /* ACQUARTERDC */ /* TWENTYFIVEX */ /* FALFSTENFTO */ /* PASTERUNINE */ /* ONESIXTHREE */ /* FOURFIVETWO */ /* EIGHTELEVEN */ /* SEVENTWELVE */ /* TENSEOCLOCK */ a3 = [297, 420]; e = 0.2; // Overall is [335, 330] on [450, 450] with 58 mm margins. s = [410, 410, 4]; module rcube(s, r=5) { hull() { for (x = [r, s[0]-r]) { for (y = [r, s[1] - r]) { translate([x, y, 0]) cylinder(r=r, s[2]); } } } } // Size of one LED on a strip. sled = [100/3, 10+1, 3]; module led_strip(n) { dc = 28+2.5; w = 10; h = 3; lh = 2; d = 5; cube([n*dc, w, h-lh]); for (x = [0..dc*n]) { translate([x, 0, 0]) difference() { cube([d, d, h-lh]); translate([d/2, d/2, h-1]) cylinder(d=(d-1), 1); } } } // Width and height in characters cx = 11; cy = 10; // Separation between LEDs dx = sled[0]; dy = 35; t = 4; sleds = [dx*cx, dy*cy, t]; module layer_plate() { square([s[0], s[1]], center=false); } module mholes() { inset = 7; m = 4; d = s[0] - inset*2; for (x = [inset, s[0]-inset]) { for (y = [inset:d/3:inset+d]) { translate([x, y, 0]) circle(d=m, $fn=10); } } } module back_layer() { difference() { layer_plate(); mholes(); } } module led_layer() { module cutout() { // Done as a snake // LED strips for (y = [0:dy:dy*cy-1]) { translate([sled[1]/2, y, 0]) # square([sled[0]*cx+sled[1], sled[1]]); } // Verticals for (y = [0:dy*2:dy*cy-1]) { translate([3, y, 0]) square([sled[1]-1, dy+sled[1]]); } for (y = [dy:dy*2:dy*(cy-1)-1]) { translate([sled[0]*cx+sled[1]-3, y+cy-sled[1]+1, 0]) square([sled[1], dy+sled[1]]); } } sc = [dx*cx+sled[1]*2, dy*(cy-1)+sled[1], 4]; difference() { layer_plate(); translate((s-sc)/2) cutout(); nodemcu(); mholes(); } } module holes_layer() { // LED hole radius lhr = 6; module holes() { for (y = [0:dy:dy*cy-1]) { for (x = [0:dx:dx*cx-1]) { translate([x+lhr, y+lhr, 0]) circle(r=lhr); } } } sh = [dx*(cx-1)+lhr*2, dy*(cy-1)+lhr*2, t]; difference() { layer_plate(); translate((s-sh)/2) holes(); nodemcu(); mholes(); } } module diffuse_layer() { // LED hole radius lhr = dx-6; module holes() { for (y = [0:dy:dy*cy-1]) { for (x = [0:dx:dx*cx-1]) { translate([x+lhr/2, y+lhr/2, 0]) square([lhr, lhr]); } } } sh = [dx*(cx-1)+lhr*2, dy*(cy-1)+lhr*2, t]; difference() { layer_plate(); translate((s-sh)/2) holes(); mholes(); } } // Diffuser sheet. sd = [340, 340, 5]; module diffuser_layer() { difference() { layer_plate(); translate((s - sd)/2+[0, 0, -e]) cube(sd); mholes(); } } // Front words panel module words_layer() { module character(ch) { if (len(search(str(ch), "APQRDO")) > 0) { difference() { text(text=ch, size=dy*.7, font="Bitstream Vera Sans Mono:style=Bold", halign="center"); translate([-.8-.3, -6, 0]) square([3, 30]); } } else { text(text=ch, size=dy*.7, font="Bitstream Vera Sans Mono:style=Bold", halign="center"); } } module row(v) { for (i = [0:len(v)-1]) { translate([sled[0]*i, 0, 0]) character(v[i]); } } module rows() { texts = [ "ITSISASAMPM", "ACQUARTERDC", "TWENTYFIVEX", "HALFSTENFTO", "PASTERUNINE", "ONESIXTHREE", "FOURFIVETWO", "EIGHTELEVEN", "SEVENTWELVE", "TENSOKYDUDE", ]; for (i = [0:len(texts)-1]) { translate([0, dy*i, 0]) row(texts[len(texts)-i-1]); } } difference() { layer_plate(); translate((s-sleds+[dx, dy, 0])/2 + [0, -11, 0]) rows(); mholes(); } } module nodemcu(h=t*2) { sn = [26, 48+8, h]; susb = [10, 20, h]; translate([s[0]-susb[0]*2, 10, 0]) rotate(90, [0, 0, 1]) { translate([(sn[0]-susb[0])/2, -susb[1], 0]) square([susb[0], susb[1]], center=false); square([sn[0], sn[1]], center=false); } } module clock() { back_layer(); translate([0, 0, t*1]) led_layer(); translate([0, 0, t*2]) holes_layer(); translate([0, 0, t*3]) diffuser_layer(); translate([0, 0, t*4]) words_layer(); } module sliced(c, o) { h = 600; difference() { translate([0, -c, 0]) children(); translate([-10, o*h, 0]) square(h); } } module slice_bottom() { sliced(cut, 0) children(); } module slice_top() { sliced(cut, -1) children(); } // cut is how far up to cut the layer into two parts. cut = 410-(410-297+58); // The following is a bit messy. For each layer you should do a // slice_top() layer(); export to svg; then do a slice_bottom() // layer(); then export to svg. //slice_top() slice_bottom() words_layer(); //diffuse_layer(); //holes_layer(); //led_layer()