// This renders engineering templates for my sous vide cooker. // All shapes print out at their designated sizes, so making // engineering diagrams is easy. These templates were printed and // rubber-cemented onto a steel project box and cut out with a drill // and a nibble-notch tool, which are actually the other handyman's secret // weapons. // // Now if Frink could only control a computerized milling machine. // Which, I guess, I'd have to have it build first. boxwidth = 218 mm boxdepth = 156 mm g = new graphics g.stroke[.2 mm] // PID controller cy = 88 mm cx = boxwidth / 2 g.drawRectCenter[cx, cy, 45 mm, 45 mm] drawCross[g, cx, cy] g.font["SansSerif", 3 mm] g.text["PID Controller", cx, cy + 1 cm] // Top of box outline g.drawRectSides[0 mm, 0 mm, boxwidth, boxdepth] // Switches cy = 18 mm + 19 mm / 2 drawSwitch[g, cx - 4 cm, cy, "Main", "Switch"] drawSwitch[g, cx + 0 cm, cy, "Heater", "Engage"] drawSwitch[g, cx + 4 cm, cy, "Pump", "Engage"] // Heat sink cx = 6 cm cy = -6 cm g.drawRectCenter[cx, cy, 5 cm, 8 cm] g.drawRectCenter[cx, cy, 5 cm, 56 mm] g.text["Heat Sink", cx, cy+.5 cm] drawCross[g,cx,cy] drawCross[g, cx, cy - 7/2 cm] drawCross[g, cx, cy + 7/2 cm] // Fan (approx 3 cm left of heat sink) cx = cx - 3 cm - 2.5 cm + 2.5 cm / 2 g.drawRectCenter[cx, cy, 2.5 cm, 6 cm] drawCross[g,cx,cy] g.text["Fan", cx, cy+5 mm] // Fan (drill pattern) cx = 130 mm g.drawRectCenter[cx, cy, 6 cm, 6 cm] g.drawRectCenter[cx, cy, 5.62 cm, 5.62 cm] drawCircleWithCross[g, cx, cy, 60 mm] drawCircleWithCross[g, cx-2.5 cm, cy-2.5 cm, 3 mm] drawCircleWithCross[g, cx+2.5 cm, cy-2.5 cm, 3 mm] drawCircleWithCross[g, cx-2.5 cm, cy+2.5 cm, 3 mm] drawCircleWithCross[g, cx+2.5 cm, cy+2.5 cm, 3 mm] g.text["Fan (drill pattern)", cx, cy+.5 cm] vertSpace = 1.4 cm // Space between center of bottom holes and base of box boxBaseY = cy + 2.5 cm + vertSpace g.line[cx-4 cm, boxBaseY, cx+4 cm, boxBaseY] g.text["Bottom of box", cx, boxBaseY, "center", "bottom"] // Outlet cy = -12 cm cx = 12.5 cm g.color[.7, .7, .7] g.drawRectCenter[cx, cy, 26 mm, 22 mm] // General guide rectangle g.color[0,0,0] p = new polygon top = cy - (22 mm / 2) p.addPoint[cx - (19 mm / 2), top] p.addPoint[cx + (19 mm / 2), top] step1y = top + 5.75 mm // Y-coord of 5.75 mm step p.addPoint[cx + (19 mm / 2), step1y] p.addPoint[cx + (26 mm / 2), step1y] step2y = step1y + 10.6 mm p.addPoint[cx + (26 mm / 2), step2y] p.addPoint[cx + (9.1 mm / 2), step2y] bottom = top + 22 mm p.addPoint[cx + (9.1 mm / 2), bottom] p.addPoint[cx - (9.1 mm / 2), bottom] p.addPoint[cx - (9.1 mm / 2), step2y] p.addPoint[cx - (26 mm / 2), step2y] p.addPoint[cx - (26 mm / 2), step1y] p.addPoint[cx - (19 mm / 2), step1y] p.addPoint[cx - (19 mm / 2), top] g.add[p] g.text["Outlet", cx, cy] // Inlet cy = -12 cm cx = 2.5 cm drawRoundedRectangle[g, cx, cy, 27.4 mm, 19.8 mm, 5.0 mm] d = 3.4mm drawCircleWithCross[g, cx+20 mm, cy, d] drawCircleWithCross[g, cx-20 mm, cy, d] g.text["Inlet", cx, cy] // Circuit breaker cx = cx + 5 cm g.color[.7,.7,.7] g.saveTransform[] g.rotate[90 degrees, cx,cy] drawCircleWithCross[g, cx, cy, 16 mm] g.color[0,0,0] r = 16 mm / 2 ry = 14 mm / 2 rx = sqrt[r^2 - ry^2] arclen = 2 arcsin[ry/r] gp = new GeneralPath gp.moveTo[cx-rx, cy-ry] gp.lineTo[cx+rx, cy-ry] gp.circularArc[cx, cy, -arclen] gp.lineTo[cx-rx, cy+ry] gp.circularArc[cx, cy, -arclen] g.add[gp] g.restoreTransform[] g.text["Circuit Breaker", cx, cy + 1 cm] // 12 V jack cx = cx + 8 cm drawCircleWithCross[g, cx, cy, 2.5 mm] drawCircleWithCross[g, cx + 3.6 mm + 9.6 mm + 2.7 mm, cy, 2.5 mm] g.drawRectCenter[cx + 15.9 mm / 2, cy, 11.5 mm, 9.0 mm] g.text["12 V Jack", cx + 15.9 mm / 2, cy + 1 cm] g.show[] g.write["sousvide.svg", 8.5 in, 11 in] //g.write["sousvide.html", 800, 800] //g.browse["sousvide.html"] drawSwitch[g is graphics, cx, cy, text1="", text2=""] := { g.drawRectSides[cx-11mm, cy-1.1mm, cx-10.1mm, cy+1.1 mm] r = 20.2 mm / 2 // drawCircleWithCross[g, cx, cy, 2r] ry = 19.0 mm / 2 rx = sqrt[r^2 - ry^2] bigarclen = 2 arcsin[ry/r] rx2 = 4.2 mm / 2 ry2 = sqrt[r^2 - rx2^2] smallarclen = 2 arcsin[rx2/r] gp = new GeneralPath gp.moveTo[cx + rx, cy - ry] gp.circularArc[cx, cy, -bigarclen] gp.lineTo[cx + rx2, cy + ry] gp.lineTo[cx + rx2, cy + ry2] gp.circularArc[cx, cy, -smallarclen] gp.lineTo[cx - rx2, cy + ry] gp.lineTo[cx - rx, cy + ry] gp.circularArc[cx, cy, -bigarclen] gp.lineTo[cx - rx2, cy - ry] gp.lineTo[cx - rx2, cy - ry2] gp.circularArc[cx, cy, -smallarclen] gp.lineTo[cx + rx2, cy - ry] gp.lineTo[cx + rx, cy - ry] g.add[gp] g.text[text1, cx, cy-.5 cm] g.text[text2, cx, cy+.5 cm] } drawCross[g is graphics, cx, cy] := { g.line[cx-2 mm, cy, cx+2mm, cy] g.line[cx, cy-2mm, cx, cy+2mm] } drawCircleWithCross[g is graphics, cx, cy, diameter] := { drawCross[g, cx, cy] g.drawEllipseCenter[cx, cy, diameter, diameter] } drawRoundedRectangle[g is graphics, cx, cy, width, height, r] := { hw = width/2 hh = height/2 cxr = cx+hw-r cxl = cx-hw+r cyb = cy+hh-r cyt = cy-hh+r left = cx - hw right = cx + hw top = cy - hh bottom = cy + hh // Draw curved area to cut out in gray g.color[0.7,0.7,0.7] gp = new filledGeneralPath gp.moveTo[cxl, top] gp.lineTo[cxr, top] gp.circularArc[cxr,cyt,-90 deg] gp.lineTo[right, cyb] gp.circularArc[cxr,cyb,-90 deg] gp.lineTo[cxl, bottom] gp.circularArc[cxl, cyb, -90 deg] gp.lineTo[left,cyt] gp.circularArc[cxl,cyt,-90 deg] gp.close[] g.add[gp] g.color[0.7,0.7,0.7] g.drawRectCenter[cx,cy,width,height] g.color[0,0,0] g.drawEllipseCenter[cxl,cyt,2r,2r] drawCross[g,cxl,cyt] g.drawEllipseCenter[cxr,cyt,2r,2r] drawCross[g,cxr,cyt] g.drawEllipseCenter[cxl,cyb,2r,2r] drawCross[g,cxl,cyb] g.drawEllipseCenter[cxr,cyb,2r,2r] drawCross[g,cxr,cyb] g.line[cxr + r, cyt, cxr + r, cyb] g.line[cxl - r, cyt, cxl - r, cyb] g.line[cxl, cyt - r, cxr, cyt - r] g.line[cxl, cyb + r, cxr, cyb + r] }