From da59840606b795c12344667bce0de8228a3c9f86 Mon Sep 17 00:00:00 2001 From: wardwouts Date: Sun, 7 Apr 2024 20:16:17 +0200 Subject: [PATCH] never committed? --- Vogelnestkastje/TextGenerator.scad | 139 ++++ Vogelnestkastje/assembly.scad | 51 ++ Vogelnestkastje/boardcuts.scad | 36 + Vogelnestkastje/bottom.scad | 59 ++ Vogelnestkastje/dimensions.scad | 36 + Vogelnestkastje/dimlines.scad | 784 +++++++++++++++++++++ Vogelnestkastje/explode.scad | 12 + Vogelnestkastje/frontback.scad | 122 ++++ Vogelnestkastje/partlist.sh | 3 + Vogelnestkastje/parts.scad | 25 + Vogelnestkastje/roof.scad | 54 ++ Vogelnestkastje/sawcut.scad | 11 + Vogelnestkastje/side.scad | 54 ++ Vogelnestkastje/vogelnestkast-assembly.png | Bin 0 -> 18554 bytes Vogelnestkastje/vogelnestkast.png | Bin 0 -> 18779 bytes 15 files changed, 1386 insertions(+) create mode 100644 Vogelnestkastje/TextGenerator.scad create mode 100644 Vogelnestkastje/assembly.scad create mode 100644 Vogelnestkastje/boardcuts.scad create mode 100644 Vogelnestkastje/bottom.scad create mode 100644 Vogelnestkastje/dimensions.scad create mode 100644 Vogelnestkastje/dimlines.scad create mode 100644 Vogelnestkastje/explode.scad create mode 100644 Vogelnestkastje/frontback.scad create mode 100755 Vogelnestkastje/partlist.sh create mode 100644 Vogelnestkastje/parts.scad create mode 100644 Vogelnestkastje/roof.scad create mode 100644 Vogelnestkastje/sawcut.scad create mode 100644 Vogelnestkastje/side.scad create mode 100644 Vogelnestkastje/vogelnestkast-assembly.png create mode 100644 Vogelnestkastje/vogelnestkast.png diff --git a/Vogelnestkastje/TextGenerator.scad b/Vogelnestkastje/TextGenerator.scad new file mode 100644 index 0000000..51d19dd --- /dev/null +++ b/Vogelnestkastje/TextGenerator.scad @@ -0,0 +1,139 @@ +//Draw text +scale([4,4,4]) drawtext("Hello World!"); + +//Draw character set +//scale([2,2,2]) drawtext(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}"); + +module drawtext(text) { + //Characters + chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}"; + + //Chracter table defining 5x7 characters + //Adapted from: http://www.geocities.com/dinceraydin/djlcdsim/chartable.js + char_table = [ [ 0, 0, 0, 0, 0, 0, 0], + [ 4, 0, 4, 4, 4, 4, 4], + [ 0, 0, 0, 0,10,10,10], + [10,10,31,10,31,10,10], + [ 4,30, 5,14,20,15, 4], + [ 3,19, 8, 4, 2,25,24], + [13,18,21, 8,20,18,12], + [ 0, 0, 0, 0, 8, 4,12], + [ 2, 4, 8, 8, 8, 4, 2], + [ 8, 4, 2, 2, 2, 4, 8], + [ 0, 4,21,14,21, 4, 0], + [ 0, 4, 4,31, 4, 4, 0], + [ 8, 4,12, 0, 0, 0, 0], + [ 0, 0, 0,31, 0, 0, 0], + [12,12, 0, 0, 0, 0, 0], + [ 0,16, 8, 4, 2, 1, 0], + [14,17,25,21,19,17,14], + [14, 4, 4, 4, 4,12, 4], + [31, 8, 4, 2, 1,17,14], + [14,17, 1, 2, 4, 2,31], + [ 2, 2,31,18,10, 6, 2], + [14,17, 1, 1,30,16,31], + [14,17,17,30,16, 8, 6], + [ 8, 8, 8, 4, 2, 1,31], + [14,17,17,14,17,17,14], + [12, 2, 1,15,17,17,14], + [ 0,12,12, 0,12,12, 0], + [ 8, 4,12, 0,12,12, 0], + [ 2, 4, 8,16, 8, 4, 2], + [ 0, 0,31, 0,31, 0, 0], + [16, 8, 4, 2, 4, 8,16], + [ 4, 0, 4, 2, 1,17,14], + [14,21,21,13, 1,17,14], + [17,17,31,17,17,17,14], + [30,17,17,30,17,17,30], + [14,17,16,16,16,17,14], + [30,17,17,17,17,17,30], + [31,16,16,30,16,16,31], + [16,16,16,30,16,16,31], + [15,17,17,23,16,17,14], + [17,17,17,31,17,17,17], + [14, 4, 4, 4, 4, 4,14], + [12,18, 2, 2, 2, 2, 7], + [17,18,20,24,20,18,17], + [31,16,16,16,16,16,16], + [17,17,17,21,21,27,17], + [17,17,19,21,25,17,17], + [14,17,17,17,17,17,14], + [16,16,16,30,17,17,30], + [13,18,21,17,17,17,14], + [17,18,20,30,17,17,30], + [30, 1, 1,14,16,16,15], + [ 4, 4, 4, 4, 4, 4,31], + [14,17,17,17,17,17,17], + [ 4,10,17,17,17,17,17], + [10,21,21,21,17,17,17], + [17,17,10, 4,10,17,17], + [ 4, 4, 4,10,17,17,17], + [31,16, 8, 4, 2, 1,31], + [14, 8, 8, 8, 8, 8,14], + [ 0, 1, 2, 4, 8,16, 0], + [14, 2, 2, 2, 2, 2,14], + [ 0, 0, 0, 0,17,10, 4], + [31, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 0, 2, 4, 8], + [15,17,15, 1,14, 0, 0], + [30,17,17,25,22,16,16], + [14,17,16,16,14, 0, 0], + [15,17,17,19,13, 1, 1], + [14,16,31,17,14, 0, 0], + [ 8, 8, 8,28, 8, 9, 6], + [14, 1,15,17,15, 0, 0], + [17,17,17,25,22,16,16], + [14, 4, 4, 4,12, 0, 4], + [12,18, 2, 2, 2, 6, 2], + [18,20,24,20,18,16,16], + [14, 4, 4, 4, 4, 4,12], + [17,17,21,21,26, 0, 0], + [17,17,17,25,22, 0, 0], + [14,17,17,17,14, 0, 0], + [16,16,30,17,30, 0, 0], + [ 1, 1,15,19,13, 0, 0], + [16,16,16,25,22, 0, 0], + [30, 1,14,16,15, 0, 0], + [ 6, 9, 8, 8,28, 8, 8], + [13,19,17,17,17, 0, 0], + [ 4,10,17,17,17, 0, 0], + [10,21,21,17,17, 0, 0], + [17,10, 4,10,17, 0, 0], + [14, 1,15,17,17, 0, 0], + [31, 8, 4, 2,31, 0, 0], + [ 2, 4, 4, 8, 4, 4, 2], + [ 4, 4, 4, 4, 4, 4, 4], + [ 8, 4, 4, 2, 4, 4, 8] ]; + + //Binary decode table + dec_table = [ "00000", "00001", "00010", "00011", "00100", "00101", + "00110", "00111", "01000", "01001", "01010", "01011", + "01100", "01101", "01110", "01111", "10000", "10001", + "10010", "10011", "10100", "10101", "10110", "10111", + "11000", "11001", "11010", "11011", "11100", "11101", + "11110", "11111" ]; + + //Process string one character at a time + for(itext = [0:len(text)-1]) { + //Convert character to index + ichar = search(text[itext],chars,1)[0]; + + //Decode character - rows + for(irow = [0:6]) { + //Select value to draw from table + val = dec_table[char_table[ichar][irow]]; + + //Decode character - cols + for(icol = [0:4]) { + // Retrieve bit to draw + bit = search(val[icol],"01",1)[0]; + + if(bit) { + //Output cube + translate([icol + (6*itext), irow, 0]) + cube([1.0001,1.0001,1]); + } + } + } + } +} diff --git a/Vogelnestkastje/assembly.scad b/Vogelnestkastje/assembly.scad new file mode 100644 index 0000000..803ceb4 --- /dev/null +++ b/Vogelnestkastje/assembly.scad @@ -0,0 +1,51 @@ +include +use +use +use +use + +bottom(); + +translate([0, 0, 0]){ + rotate([0,-90,0]){ + side(); + } +} +translate([nestwidth + plankthick, 0, 0]){ + rotate([0,-90,0]){ + hingedside(); + } +} + +translate([-plankthick, -plankthick, 0]){ + rotate([0,270,270]){ + front(); + } +} + +translate([-plankthick, nestwidth, 0]){ + rotate([0,270,270]){ + back(); + } +} + +translate([nestwidth/2, -overhang-plankthick, bottomtohole + plankthick + holediameter + ( ( nestwidth + ( 2 * plankthick ) ) / 2)]){ + rotate([0,90+45,0]){ + translate([nestwidth + (0* plankthick),0,-plankthick]){ + rotate([0,0,90]){ + roofleft(); + } + } + } +} + +translate([nestwidth/2, -overhang-plankthick, bottomtohole + plankthick + holediameter + ( ( nestwidth + ( 2 * plankthick ) ) / 2)]){ + rotate([0,180+45,0]){ + translate([0,0,-plankthick]){ + rotate([0,0,90]){ + roofright(); + } + } + } +} + diff --git a/Vogelnestkastje/boardcuts.scad b/Vogelnestkastje/boardcuts.scad new file mode 100644 index 0000000..9918a9e --- /dev/null +++ b/Vogelnestkastje/boardcuts.scad @@ -0,0 +1,36 @@ +include + +include +include +use +include +use + +front(); +translate([frontbackheight, 0, 0]) + sawcut(); +translate([frontbackheight + bladewidth, 0, 0]) + back(); +translate([frontbackheight + bladewidth + frontbackheight, 0, 0]) + sawcut(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth, 0, 0]) + roofleft(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength, 0, 0]) + sawcut(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth, 0, 0]) + roofright(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth + rooflength, 0, 0]) + sawcut(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth + rooflength + bladewidth, 0, 0]) + side(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth + rooflength + bladewidth + sidelength, 0, 0]) + sawcut(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth + rooflength + bladewidth + sidelength + bladewidth, 0, 0]) + hingedside(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth + rooflength + bladewidth + sidelength + bladewidth + sidelength, 0, 0]) + sawcut(); +translate([frontbackheight + bladewidth + frontbackheight + bladewidth + rooflength + bladewidth + rooflength + bladewidth + sidelength + bladewidth + sidelength + bladewidth, 0, 0]) + bottom(); + +echo ("FRONTBACKHEIGHT ", nestwidth); +echo("#### Total board length = ", 2*frontbackheight + 6*bladewidth + 2*sidelength + 2*rooflength + nestwidth, " Max width = ", frontbackwidth); diff --git a/Vogelnestkastje/bottom.scad b/Vogelnestkastje/bottom.scad new file mode 100644 index 0000000..d799b51 --- /dev/null +++ b/Vogelnestkastje/bottom.scad @@ -0,0 +1,59 @@ +include +include + +module bottom(){ + color("green") + difference(){ + difference(){ + difference(){ + difference(){ + cube(size=[nestwidth, nestwidth, plankthick], center=false); + translate([0, drainage, -2]){ + rotate([0, 0, 225]){ + cube([drainage*2, drainage*2, plankthick +4]); + } + } + } + translate([0, nestwidth-drainage, -2]){ + rotate([0, 0, 45]){ + cube([drainage*2, drainage*2, plankthick +4]); + } + } + } + translate([nestwidth-drainage, 0, -2]){ + rotate([0, 0, 315]){ + cube([drainage*2, drainage*2, plankthick +4]); + } + } + } + translate([nestwidth, nestwidth-drainage, -2]){ + rotate([0, 0, 45]){ + cube([drainage*2, drainage*2, plankthick +4]); + } + } + } + echo("#### Bottom: width = ", nestwidth, " depth = ", nestwidth); +} + +module bottomdim(){ + bottom(); + color("black"){ + translate([nestwidth - drainage, nestwidth + 10, 0]) + dimensions(length=drainage, loc=DIM_OUTSIDE); + + translate([nestwidth +10, nestwidth - drainage, 0]) + rotate([0, 0, 90]) + dimensions(length=drainage, loc=DIM_OUTSIDE); + + translate([-10, 0, 0]) + rotate([0, 0, 90]) + dimensions(length=nestwidth); + translate([0, -10 , 0]) + dimensions(length=nestwidth); + + translate([0, nestwidth + 15, 0]) + drawtext("Bottom"); + } +} + +bottomdim(); diff --git a/Vogelnestkastje/dimensions.scad b/Vogelnestkastje/dimensions.scad new file mode 100644 index 0000000..d7f94d9 --- /dev/null +++ b/Vogelnestkastje/dimensions.scad @@ -0,0 +1,36 @@ +// details in arcs +FN=40; + +// a bit thicker lines for dimensions +DIM_LINE_WIDTH = 1; + +// plank dimensions +// best to err on the too thick side, thats easier to correct with a plane +plankthick = 19; + +// depends on the bird you're making the nestbox for +// 28 = blue tit (pimpelmees) +// 32 = great tit (koolmees) +holediameter = 32; + +// used to lock the hinging side +picturehookdiameter = 3; +lockplay = 1; + +// keyhole to hang the nest box +keyholediameter = 6; +keyholeslotwidth = 3; +keyholeslotlength = 15; + +// roof overhang +overhang = 40; + +// cutout size for drainage +drainage = 10; + +// for a cuttingplan we need to know the kerf the blade will make +bladewidth = 2.8; + +// should not need to touch these values +bottomtohole = 195; +nestwidth = 120; diff --git a/Vogelnestkastje/dimlines.scad b/Vogelnestkastje/dimlines.scad new file mode 100644 index 0000000..ee3031c --- /dev/null +++ b/Vogelnestkastje/dimlines.scad @@ -0,0 +1,784 @@ +/* This is a first pass at dimension lines for OpenSCAD. The text generated for + * this comes from http://www.thingiverse.com/thing:59817, and I gratefully + * acknowledge user PGreenland for creating this dotmatrix style font. + * + * Download his file first, TextGenerator.scad, before attempting to run this + * program. + * + * What this program does: + * + * This program can draw lines with arrows and has a primitive dimensioning + * element for putting text within arrows. In addition, should the area being + * dimensioned be too narrow, there is a provision for putting the text on + * either side of the arrows. + * + * The dimension lines are drawn on the xy plane and are meant to be seen in a + * top view. + * + * ======================================================= + * Be sure to view this from above -- ctrl-4 + * ======================================================= + * + * Available: + * + * Assorted constants to ease the use of dimensioning line. Because there is + * no introspection regarding the dimensions of your creations, you will want + * to adjust the parameters to fit the context of your creation. You can adjust + * the size of the text, lines, etc to match the rest of your objects. + * + * the following functions or modules are available. + * + * line(length, width, height=DIM_HEIGHT, left_arrow=false, right_arrow=false) + * Can draw a line with the options of including an arrow at either end + * + * circle_center(radius, size, line_width) + * Draws the cross in the center of a circle. There are defaults for the + * cross size and line width + * + * dimensions(length, line_width, loc=DIM_CENTER) + * draws text within lines, such as <--- 3.5 ---> + * with the use of the variable loc you can alter the placement of the text + * loc=DIM_CENTER <--- 3.5 ---> this is the default + * loc=DIM_LEFT 3.5 <----> + * loc=DIM_RIGHT <----> 3.5 + * loc=DIM_OUTSIDE ---> 3.5 <--- + * + * leader_line(angle, radius, angle_length, horz_line_length, + * direction=DIM_RIGHT, line_width, text) + * + * for use in pointing to the edge of a circle and showing text + * + * usage of the leader line: + * translate to the center of the circle + * Typically leader lines have a bend in them. The angle variable is used + * to specify the angle from which the line will point to the center of the + * circle. The radius specifies the location of the arrow. The + * angle_length is distance that the leader line takes until meeting the + * horizontal line. Once the angled line meets the horizontal line, that + * line will either extend to the right or left. direction and therefore + * be either DIM_RIGHT or DIM_LEFT. line_width typically would be whatever + * constant you have selected for all your dimensioned lines. Finally, the + * text will be the value that you wish to show, such as R 0.500. + * + * + * Created by Don Smiley + */ + +use + +// these variables are used within the modules +DIM_CENTER = 0; +DIM_LEFT = 1; +DIM_RIGHT = 2; +DIM_OUTSIDE = 3; +DIM_HORZ = 0; +DIM_VERT = 1; +DIM_UPPER_LEFT = 0; +DIM_UPPER_RIGHT = 1; +DIM_LOWER_LEFT = 2; +DIM_LOWER_RIGHT = 3; + +/* Constants related to the annotation lines + * + * Because the dimension of the part to be documented can vary widely, you + * probably are going to need to adjust the parameters to fit the context of + * your part. + * + * For example, the following parameters were used for a part 3.5 units long. + * In addition, DIM_HEIGHT is a height meant to be slightly above your tallest + * part. + */ + +DIM_LINE_WIDTH = .025; // width of dimension lines +DIM_SPACE = .1; // a spacing value to make it easier to adjust line spacing etc +DIM_HEIGHT = .01; // height of lines + +// refers to the size of the cross within a circle +DIM_HOLE_CENTER = DIM_LINE_WIDTH * 6; + +// an approximation that sets the font size relative to the line widths +DIM_FONTSCALE = DIM_LINE_WIDTH * .7; + + + +OFFSET = .05; // added to the hole length to extend past the surface of the cube + +module arrow(arr_points, arr_length, height) { + // arrow points to the left + linear_extrude(height=height, convexity=2) + + polygon( + points = [[0, 0], + [arr_points, arr_points / 2], + [arr_length, 0], + [arr_points, -arr_points / 2]], + paths = [[0, 1, 2, 3]], convexity = 2); +} + +module line(length, width=DIM_LINE_WIDTH, + height=DIM_HEIGHT, + left_arrow=false, + right_arrow=false + ) { + /* This module draws a line that can have an arrow on either end. Because + * the intended use is to be viewed strictly from above, the height of the + * line is set arbitrarily thin. + * + * The factors arr_length and arr_points are used to create a proportionate + * arrow. Your sense of asthetics may lead you to choose different + * numbers. + */ + + arr_points = width * 4; + arr_length = arr_points * .6; + + union() { + if (left_arrow && right_arrow) { + translate([arr_length, -width / 2, 0]) + cube([length - arr_length * 2, width, height], center=false); + } else { + + if (left_arrow) { + translate([arr_length, -width / 2, 0]) + cube([length - arr_length, width, height], center=false); + } else { + if (right_arrow) { + translate([0, -width / 2, 0]) + cube([length - arr_length, width, height], center=false); + } else { + translate([0, -width / 2, 0]) + cube([length, width, height], center=false); + } + + } + } + + if (left_arrow) { + arrow(arr_points, arr_length, height); + } + + if (right_arrow) { + translate([length, 0, 0]) + rotate([0, 0, 180]) + arrow(arr_points, arr_length, height); + + } + } +} + + +module circle_center(radius, size=DIM_HOLE_CENTER, line_width=DIM_LINE_WIDTH) { + + translate([-size / 2, 0, 0]) + line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false, + right_arrow=false); + + translate([radius - size / 2, 0, 0]) + line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false, + right_arrow=false); + + translate([-radius - size / 2, 0, 0]) + line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false, + right_arrow=false); + + translate([0, -size / 2, 0]) + rotate([0, 0, 90]) + line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false, + right_arrow=false); + + translate([0, radius - size / 2, 0]) + rotate([0, 0, 90]) + line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false, + right_arrow=false); + + translate([0, -radius - size / 2, 0]) + rotate([0, 0, 90]) + line(length=size, width=line_width, height=DIM_HEIGHT, left_arrow=false, + right_arrow=false); + +} + +module dimensions(length, line_width=DIM_LINE_WIDTH, loc=DIM_CENTER) { + + + text = str(length); + space = len(text) * DIM_FONTSCALE * 7; + + if (loc == DIM_CENTER) { + line(length=length / 2 - space / 2, width=line_width, height=DIM_HEIGHT, + left_arrow=true, right_arrow=false); + translate([(length) / 2 - space / 2 * .9, -DIM_FONTSCALE * 3, 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(text); + + translate([length / 2 + space / 2, 0, 0]) + line(length=length / 2 - space / 2, width=line_width, height=DIM_HEIGHT, + left_arrow=false, right_arrow=true); + } else { + + if (loc == DIM_LEFT) { + line(length=length, width=line_width, height=DIM_HEIGHT, + left_arrow=true, right_arrow=true); + + translate([-space, -DIM_FONTSCALE * 3, 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(text); + } else { + if (loc == DIM_RIGHT) { + line(length=length, width=line_width, height=DIM_HEIGHT, + left_arrow=true, right_arrow=true); + + translate([length + space, -DIM_FONTSCALE * 3, 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(text); + } else { + if (loc == DIM_OUTSIDE) { + + rotate([0, 180, 0]) + line(length=length / 2, width=line_width, height=DIM_HEIGHT, + left_arrow=true, right_arrow=false); + + translate([(length) / 2 - space / 2 * .9, + -DIM_FONTSCALE * 3, 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(text); + + translate([length, 0, 0]) + line(length=length / 2, width=line_width, height=DIM_HEIGHT, + left_arrow=true, right_arrow=false); + } + } + } + } +} + +module leader_line(angle, radius, angle_length, horz_line_length, + direction=DIM_RIGHT, line_width=DIM_LINE_WIDTH, text, do_circle=false) { + /* leader_line + * + * Creates a line that points directly at a center point from the given + * radius. + * Then, a short horzizontal line is generated, followed by text. The + * direction of the horizontal short line defaults to the right, the + * choice made by either DIM_RIGHT or DIM_LEFT + */ + + text_length = len(text) * DIM_FONTSCALE * 6; + space = DIM_FONTSCALE * 6; + + rotate([0, 0, angle]) + translate([radius, 0, 0]) + line(length=angle_length, width=line_width, height=DIM_HEIGHT, + left_arrow=true, right_arrow=false); + + rotate([0, 0, angle]) + translate([radius + angle_length, 0, 0]) + rotate([0, 0, -angle]) + union() { + if (direction == DIM_RIGHT) { + line(length=horz_line_length, width=line_width, height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + + translate([(horz_line_length + space), -DIM_FONTSCALE * 3, 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(text); + + if (do_circle) { + translate([(horz_line_length + space + text_length/2), + 0, 0]) + difference() { + cylinder(h=DIM_HEIGHT, r=text_length + space - line_width, + center=true, $fn=100); + cylinder(h=.05, r=text_length + space - line_width * 2, + center=true, $fn=100); + } + } + + } else { + translate([-horz_line_length, 0, 0]) + line(length=horz_line_length, width=line_width, height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + + translate([-(horz_line_length + space + text_length), + -DIM_FONTSCALE * 3, + 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(text); + + } + } +} + +module titleblock(lines, descs, details) { + /* titleblock + * + * This module accepts the following arrays with formats: + * + * holds the description of the lines. width is a factor that + * expands the line width beyond DIM_LINE_WIDTH + * + * lines = [[startx, starty, horz/vert, length, width], + * [startx, starty, horz/vert, length, width]] + * + * holds the descriptions of the title blocks. these are meant to sit in + * the upper left corner. size, like width above, is a factor that + * increases/decreases the size of the font + * + * descs = [[startx, starty, horz/vert, text, size], + * [startx, starty, horz/vert, text, size]] + * + * holds the detail associated with the part being documented + * + * details = [[startx, starty, horz/vert, text, size], + * [startx, starty, horz/vert, text, size]] + */ + + DIM_FONTSCALE = DIM_LINE_WIDTH * .7; + + for (line = lines) { + translate([line[0] * DIM_LINE_WIDTH, + line[1] * DIM_LINE_WIDTH, + 0]) + if (line[2] == DIM_VERT) { + rotate([0, 0, -90]) + line(length=line[3] * DIM_LINE_WIDTH, + width=DIM_LINE_WIDTH * line[4], height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + } else { + line(length=(line[3] + 1) * DIM_LINE_WIDTH, + width=DIM_LINE_WIDTH * line[4], height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + } + + } + + for (line = descs) { + translate([line[0] * DIM_LINE_WIDTH, line[1] * DIM_LINE_WIDTH, 0]) + if (line[2] == DIM_VERT) { + rotate([0, 0, 90]) + scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4], + DIM_FONTSCALE * line[4]]) + drawtext(line[3]); + } else { + scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4], + DIM_FONTSCALE * line[4]]) + drawtext(line[3]); + } + } + + for (line = details) { + translate([line[0] * DIM_LINE_WIDTH, line[1] * DIM_LINE_WIDTH, 0]) + if (line[2] == DIM_VERT) { + rotate([0, 0, 90]) + scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4], + DIM_FONTSCALE * line[4]]) + drawtext(line[3]); + } else { + scale([DIM_FONTSCALE * line[4], DIM_FONTSCALE * line[4], + DIM_FONTSCALE * line[4]]) + drawtext(line[3]); + } + } + +} + + +module sample_titleblock1() { + /* sample titleblock + * + * Note the use of double thickness lines around the perimeter. Any line + * can be adjusted to be thinner or thicker. + * + * Note also that since lines are centered on their widths, some adjustments + * for half-width spacing is needed to avoid a jagged look on corners. + * You can see that in the horizontal lines in the first section that are + * offset by 1, which is the half-width of the outside line. + */ + title_width = 290; + row_height = 15; + + cols = [-1, 50, 114, 200, 215, 260]; + rows = [0, -row_height, -row_height * 2, -row_height * 3, -row_height * 4]; + + // spacing tweaks to fit into the blocks + desc_x = 2; // column offset for start of small text + desc_y = -5; // row offset for start of small text + det_y = -12; // row offset for start of detail text + desc_size = .75; // relative size of description text + + lines = [ + // horizontal lines + [cols[0], rows[0], DIM_HORZ, title_width, 2], + [cols[0], rows[1], DIM_HORZ, title_width, 1], + [cols[2], rows[2], DIM_HORZ, title_width - cols[2] - 1, 1], + [cols[3], rows[3], DIM_HORZ, title_width - cols[3] - 1, 1], + [cols[0], rows[4] - 1, DIM_HORZ, title_width, 2], + + // vertical lines + [0, 0, DIM_VERT, row_height * 4, 2], + [cols[1], rows[0], DIM_VERT, row_height, 1], + [cols[2], rows[0], DIM_VERT, row_height * 4, 1], + [cols[3], rows[0], DIM_VERT, row_height * 4, 1], + [cols[4], rows[3], DIM_VERT, row_height, 1], + [cols[5], rows[3], DIM_VERT, row_height, 1], + [title_width - 1, 0, DIM_VERT, row_height * 4, 2], + ]; + + descs = [ + [cols[0] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Responsible dep", desc_size], + [cols[1] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Technical reference", desc_size], + [cols[2] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Creator", desc_size], + [cols[3] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Approval person", desc_size], + [cols[2] + desc_x, rows[1] + desc_y, DIM_HORZ, + "Document type", desc_size], + [cols[3] + desc_x, rows[1] + desc_y, DIM_HORZ, + "Document status", desc_size], + [cols[2] + desc_x, rows[2] + desc_y, DIM_HORZ, + "Title", desc_size], + [cols[3] + desc_x, rows[2] + desc_y, DIM_HORZ, + "Identification number", desc_size], + [cols[3] + desc_x, rows[3] + desc_y, DIM_HORZ, + "Rev", desc_size], + [cols[4] + desc_x, rows[3] + desc_y, DIM_HORZ, + "Date of issue", desc_size], + [cols[5] + desc_x, rows[3] + desc_y, DIM_HORZ, + "Sheet", desc_size] + ]; + + details = [ + [cols[0] + desc_x, rows[0] + det_y, DIM_HORZ, + " ", 1], //Responsible dep. + [cols[1] + desc_x, rows[0] + det_y, DIM_HORZ, + " ", 1], //Technical reference + [cols[2] + desc_x, rows[0] + det_y, DIM_HORZ, + "D. Smiley ", 1], //Creator + [cols[3] + desc_x, rows[0] + det_y, DIM_HORZ, + " ", 1], //Approval person + [cols[0] + desc_x + 10, rows[2] + det_y, DIM_HORZ, + "My OpenSCAD Project", 1], + [cols[2] + desc_x, rows[1] + det_y, DIM_HORZ, + " ", 1], //Document type + [cols[3] + desc_x, rows[1] + det_y, DIM_HORZ, + "First issue", 1], //Document status + [cols[2] + desc_x, rows[2] + det_y, DIM_HORZ, + "Sample Part", 1], //Title + [cols[3] + desc_x, rows[2] + det_y, DIM_HORZ, + "123", 1], //Identification number + [cols[3] + desc_x, rows[3] + det_y, DIM_HORZ, + " ", 1], //Rev + [cols[4] + desc_x, rows[3] + det_y, DIM_HORZ, + "2013-3-31", 1], //Date of issue + [cols[5] + desc_x, rows[3] + det_y, DIM_HORZ, + "1/100", 1] //Sheet + ]; + + + titleblock(lines, descs, details); +} + +module sample_revisionblock(revisions) { + + DIM_FONTSCALE = DIM_LINE_WIDTH * .7; + + // revision block headings + row_height = 15; + revision_width = 100; + desc_x = 2; + desc_y = -10; + desc_size = 1; + + cols = [0, 20, 60, revision_width]; + rows = [0, -row_height, -row_height * 2]; + + // draw + lines = [ + // horizontal lines + [cols[0], rows[0], DIM_HORZ, revision_width, 1], + [cols[0], rows[1], DIM_HORZ, revision_width, 1], + [cols[0], rows[2], DIM_HORZ, revision_width, 1], + + // vertical lines + [cols[0], rows[0], DIM_VERT, row_height * 2, 1], + [cols[1], rows[0], DIM_VERT, row_height, 1], + [cols[2], rows[0], DIM_VERT, row_height, 1], + [cols[3], rows[0], DIM_VERT, row_height * 2, 1], + ]; + + descs = [ + [cols[0] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Rev.", desc_size], + [cols[1] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Date", desc_size], + [cols[2] + desc_x, rows[0] + desc_y, DIM_HORZ, + "Initials", desc_size], + [cols[1] + desc_x, rows[1] + desc_y, DIM_HORZ, + "Revisions", desc_size], + ]; + + details = []; + num_revisions = len(revisions); + + translate([-(revision_width + 40) * DIM_LINE_WIDTH, + row_height * 2 * DIM_LINE_WIDTH, 0]) + union() { + titleblock(lines, descs, details); + + // now for the start of actual revisions + // do this piecemeal -- draw the vertical first + + for (col = [0: len(cols)]) { + translate([cols[col] * DIM_LINE_WIDTH, 0, 0]) + rotate([0, 0, 90]) + line(num_revisions * row_height * DIM_LINE_WIDTH); + } + + for (row = [0: len(revisions)]) { + translate([0, row * row_height * DIM_LINE_WIDTH, 0]) + line(revision_width * DIM_LINE_WIDTH); + + for (col = [0:2]) { + translate([(cols[col] + desc_x) * DIM_LINE_WIDTH, + ((row + 1) * row_height + desc_y) * DIM_LINE_WIDTH, 0]) + scale([DIM_FONTSCALE, DIM_FONTSCALE, DIM_FONTSCALE]) + drawtext(revisions[row][col]); + } + } + + } +} + +module sample_titleblock2() { + + row_height = 20; + + cols = [-.5, 100, 154, 270]; + title_width = cols[3]; + + rows = [0, -row_height, -row_height * 2, -row_height * 3, -row_height * 4, + -row_height * 5, -row_height * 6, -row_height * 7 + ]; + + // spacing tweaks to fit into the blocks + desc_x = 2; // column offset for start of small text + desc_y = -5; // row offset for start of small text + det_x = 15; // col offset for start of detail text + det_y = -15; // row offset for start of detail text + desc_size = .75; // relative size of description text + + + lines = [ + // horizontal lines + [-.5, 0, DIM_HORZ, title_width, 1], + + [cols[2], rows[1], DIM_HORZ, cols[3] - cols[2] - .5, 1], + [cols[0], rows[2], DIM_HORZ, cols[1] - cols[0] - .5, 1], + [cols[0], rows[3], DIM_HORZ, cols[3] - .5, 1], + [cols[0], rows[4], DIM_HORZ, cols[2] - .5, 1], + [cols[0], rows[5], DIM_HORZ, cols[3] - .5, 1], + [cols[0], rows[6], DIM_HORZ, cols[2] - .5, 1], + [cols[0], rows[7], DIM_HORZ, cols[2] - .5, 1], + + [cols[0], rows[7], DIM_HORZ, title_width, 1], + + // vertical lines + [cols[0], rows[0], DIM_VERT, -rows[7], 1], + [cols[1], rows[0], DIM_VERT, -rows[7], 1], + [cols[2], rows[0], DIM_VERT, -rows[7], 1], + [cols[3], rows[0], DIM_VERT, -rows[7], 1], + ]; + + part_desc = ["Material", "Finish", "Weight", "Part No."]; + doc_desc = ["Drawing Number", + "Created by", + "Reviewed by", + "Date of issue" + ]; + + // aspects of the part + part_details = [ + "My Sample Part", // title + "Stainless Steel", // material + " ", // finish + "2.5", // weight + "123", // part no + ]; + + // aspects documenting the creation of the part + doc_details = [ + "33-2", // Drawing No. + "D. Smiley", // Created by + " ", // Reviewd by + "2013-3-31", // Date + ]; + + // the organization making the part + org_details = [ + "My logo", + "Canny Machines", + "Org Address, phone" + ]; + + descs = [ + + // part description + [cols[0] + desc_x, rows[2] + desc_y, DIM_HORZ, part_desc[0], desc_size], + [cols[0] + desc_x, rows[3] + desc_y, DIM_HORZ, part_desc[1], desc_size], + [cols[0] + desc_x, rows[4] + desc_y, DIM_HORZ, part_desc[2], desc_size], + [cols[0] + desc_x, rows[5] + desc_y, DIM_HORZ, part_desc[3], desc_size], + + // documentation description + [cols[1] + desc_x, rows[3] + desc_y, DIM_HORZ, doc_desc[0], desc_size], + [cols[1] + desc_x, rows[4] + desc_y, DIM_HORZ, doc_desc[1], desc_size], + [cols[1] + desc_x, rows[5] + desc_y, DIM_HORZ, doc_desc[2], desc_size], + [cols[1] + desc_x, rows[6] + desc_y, DIM_HORZ, doc_desc[3], desc_size], + ]; + + details = [ + [cols[0] + desc_x, rows[0] + det_y, DIM_HORZ, part_details[0], 1.5], + [cols[0] + desc_x, rows[2] + det_y, DIM_HORZ, part_details[1], 1], + [cols[0] + desc_x, rows[3] + det_y, DIM_HORZ, part_details[2], 1], + [cols[0] + desc_x, rows[4] + det_y, DIM_HORZ, part_details[3], 1], + [cols[0] + desc_x, rows[5] + det_y, DIM_HORZ, part_details[4], 1], + + [cols[1] + desc_x * 2, rows[3] + det_y, DIM_HORZ, doc_details[0], 1], + [cols[1] + desc_x * 2, rows[4] + det_y, DIM_HORZ, doc_details[1], 1], + [cols[1] + desc_x * 2, rows[5] + det_y, DIM_HORZ, doc_details[2], 1], + [cols[1] + desc_x * 2, rows[6] + det_y, DIM_HORZ, doc_details[3], 1], + + // Organization Details + [cols[1] + desc_x, rows[1] + det_y, DIM_HORZ, org_details[0], 1.5], + [cols[2] + desc_x, rows[0] + det_y, DIM_HORZ, org_details[1], 1.5], + [cols[2] + desc_x, rows[1] + det_y, DIM_HORZ, org_details[2], 1], + + ]; + + titleblock(lines, descs, details); + + revisions = [ + ["1a", "2013-4-1", "ds"], + ["1b", "2013-4-2", "ds"], + ["2a", "2013-4-3", "ds"], + ["3a", "2013-4-5", "ds"], + ["4a", "2013-4-15", "ds"], + ]; + + rotate([0, 0, 90]) + sample_revisionblock(revisions); + + +} + +module sample_lines(){ + // sample lines + union() { + line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + translate([0, -0.25, 0]) + line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, left_arrow=true, + right_arrow=false); + translate([0, -0.5, 0]) + line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, + left_arrow=false, right_arrow=true); + translate([0, -0.75, 0]) + line(length=2, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, left_arrow=true, + right_arrow=true); + } +} + +module sample_dimensions() { + + /* shows all possibilities + DIM_CENTER = 0; + DIM_LEFT = 1; + DIM_RIGHT = 2; + DIM_OUTSIDE = 3; + */ + + length = 2.5; + + // The following two lines are vertical lines that bracket the dimensions + // left arrow + translate([0, -1.75, 0]) + rotate([0, 0, 90]) + line(length=length, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + + // right arrow + translate([length, -1.75, 0]) + rotate([0, 0, 90]) + line(length=length, width=DIM_LINE_WIDTH, height=DIM_HEIGHT, + left_arrow=false, right_arrow=false); + + // The following runs through all the dimension types + for (i = [0:4]) { + translate([0, -.5 * i, 0]) + dimensions(length=length, line_width=DIM_LINE_WIDTH, loc=i); + } +} + +module sample_leaderlines() { + + radius = .25; + for (i = [0:6]) { + leader_line(angle=i * 15, radius=.25, angle_length=(i * .25), + horz_line_length=.5, direction=DIM_RIGHT, + line_width=DIM_LINE_WIDTH, + text=str("leader line angle: ", i * 15 + 90), + do_circle=false + ); + } + + for (i = [1:7]) { + leader_line(angle=i * 20 + 90, radius=.25, + angle_length=.75, + horz_line_length=.5, direction=DIM_LEFT, + line_width=DIM_LINE_WIDTH, + text=str("leader line angle: ", i * 20 + 90)); + } + for (i = [1:4]) { + leader_line(angle=-i * 20, radius=.25, angle_length=1.5, + horz_line_length=.25, direction=DIM_RIGHT, + line_width=DIM_LINE_WIDTH, + text=str(i), + do_circle=true + ); + } + } + +module sample_circlecenter() { + + radius = .25; + difference() { + cube([1, 1, 1], center=true); + cylinder(h=1.1, r=radius, center=true, $fn=100); + } + color("Black") + translate([0, 0, .51]) + circle_center(radius=radius, size=DIM_HOLE_CENTER, + line_width=DIM_LINE_WIDTH); + +} + +// uncomment these to sample +// sample_lines(); +// +// translate([-5.5, 0, 0]) +// sample_dimensions(); +// +// translate([4, 0, 0]) +// sample_circlecenter(); +// +// translate([-2, 3, 0]) +// sample_leaderlines(); +// +// translate([3, 4, 0]) +// sample_titleblock1(); +// +// translate([0, -2, 0]) +// sample_titleblock2(); + + diff --git a/Vogelnestkastje/explode.scad b/Vogelnestkastje/explode.scad new file mode 100644 index 0000000..ad6f4b7 --- /dev/null +++ b/Vogelnestkastje/explode.scad @@ -0,0 +1,12 @@ +module explode(distance = [10, 0, 0], center = false, enable = true) { + if(enable){ + offset = center ? (($children * distance) / 2 - distance / 2) * -1 : [0, 0 , 0]; + for(i = [0 : 1 : $children - 1]) { + translate(i * distance + offset) { + children(i); + } + } + } else { + children(); + } +} diff --git a/Vogelnestkastje/frontback.scad b/Vogelnestkastje/frontback.scad new file mode 100644 index 0000000..3bb31d7 --- /dev/null +++ b/Vogelnestkastje/frontback.scad @@ -0,0 +1,122 @@ +include +include + +frontbackheight = bottomtohole + plankthick + holediameter + ( ( nestwidth + ( 2 * plankthick ) ) / 2); +frontbackwidth = nestwidth + ( 2 * plankthick ); + +module frontback(){ + color("red") + difference(){ + difference(){ + cube([frontbackheight, frontbackwidth, plankthick]); + translate([bottomtohole + plankthick + holediameter, 0, -2]){ + rotate([0, 0, -45]) { + cube([nestwidth + ( 2 * plankthick ), nestwidth + ( 2 * plankthick ), plankthick + 4]); + } + } + } + translate([bottomtohole + plankthick + holediameter, frontbackwidth, -2]){ + rotate([0, 0, -45]) { + cube([nestwidth + ( 2 * plankthick ), nestwidth + ( 2 * plankthick ), plankthick + 4]); + } + } + } + +} + +module front(){ + difference(){ + frontback(); + translate([bottomtohole + (holediameter / 2), ( frontbackwidth / 2), -2]){ + cylinder(h = plankthick + 4, d = holediameter, center = false); + } + } + echo("#### Front: height = ", frontbackheight, " width = ", frontbackwidth); +} + + +module keyhole(){ + translate([0, 0, -2]){ + cylinder(h = plankthick + 4, d = keyholediameter, center = false); + translate([0, - keyholeslotwidth/2, 0]){ + cube([keyholeslotlength, keyholeslotwidth, plankthick + 4]); + } + translate([keyholeslotlength, 0, 0]){ + cylinder(h = plankthick + 4, d = keyholeslotwidth, center = false); + } + } +} + +module back(){ + difference(){ + frontback(); + translate([bottomtohole + plankthick + holediameter, ( ( nestwidth + ( 2 * plankthick ) ) / 2), 0]){ + keyhole(); + } + } + echo("#### Back: height = ", frontbackheight, " width = ", frontbackwidth); +} + +module frontdim(){ + front(); + color("black"){ + translate([bottomtohole + (holediameter / 2), frontbackwidth/2, 0]) + circle_center(radius=holediameter/2, size=DIM_HOLE_CENTER, + line_width=DIM_LINE_WIDTH); + + translate([bottomtohole, frontbackwidth + 10, 0]) + dimensions(length=holediameter); + + translate([0, -10 , 0]) + dimensions(length=bottomtohole + (holediameter / 2)); + translate([0, -20 , 0]) + dimensions(length=frontbackheight - (frontbackwidth/2)); + translate([0, -30 , 0]) + dimensions(length=frontbackheight); + + translate([-10, 0, 0]) + rotate([0,0,90]) + dimensions(length=frontbackwidth); + + translate([0, frontbackwidth + 15, 0]) + drawtext("Front"); + } +} + +module backdim(){ + back(); + color("black"){ + translate([bottomtohole + plankthick + holediameter - (keyholediameter/2), frontbackwidth/2, 0]) + circle_center(radius=keyholediameter/2, size=DIM_HOLE_CENTER, + line_width=DIM_LINE_WIDTH); + + translate([bottomtohole + plankthick + holediameter - (keyholediameter/2) + keyholeslotlength, frontbackwidth/2, 0]) + circle_center(radius=keyholediameter/2, size=DIM_HOLE_CENTER, + line_width=DIM_LINE_WIDTH); + + + translate([0, frontbackwidth + 10, 0]) + dimensions(length=bottomtohole + plankthick + holediameter - (keyholediameter/2)); + translate([bottomtohole + plankthick + holediameter - (keyholediameter/2), frontbackwidth + 10, 0]) + dimensions(length=keyholeslotlength, loc=DIM_RIGHT); + + translate([frontbackheight + 10, (frontbackwidth/2) - (keyholeslotwidth/2), 0]) + rotate([0,0,90]) + dimensions(length=keyholeslotwidth, loc=DIM_OUTSIDE); + translate([frontbackheight + 20, (frontbackwidth/2) - (keyholediameter/2), 0]) + rotate([0,0,90]) + dimensions(length=keyholediameter, loc=DIM_OUTSIDE); + + translate([0, -10 , 0]) + dimensions(length=frontbackheight - (frontbackwidth/2)); + translate([0, -20 , 0]) + dimensions(length=frontbackheight); + + translate([-10, 0, 0]) + rotate([0,0,90]) + dimensions(length=frontbackwidth); + + translate([0, frontbackwidth + 15, 0]) + drawtext("Back"); + } +} diff --git a/Vogelnestkastje/partlist.sh b/Vogelnestkastje/partlist.sh new file mode 100755 index 0000000..a8fc2cd --- /dev/null +++ b/Vogelnestkastje/partlist.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +/home/ward/.local/share/flatpak/exports/bin/org.openscad.OpenSCAD -o blup.dxf assembly.scad 2>&1|grep '####'|sort|awk 'BEGIN{count=0;prevline=""}{if(prevline == $0){count += 1} else {print(count, "x ", prevline);count=1;prevline=$0; }}END{print(count, "x ", prevline)}' diff --git a/Vogelnestkastje/parts.scad b/Vogelnestkastje/parts.scad new file mode 100644 index 0000000..323ce5d --- /dev/null +++ b/Vogelnestkastje/parts.scad @@ -0,0 +1,25 @@ +include +include +include +include +include + + +frontdim(); +translate([frontbackheight+50, 0, 0]){ + backdim(); +} +translate([0, frontbackwidth+50, 0]){ + roofleftdim(); + translate([rooflength + 50, 0, 0]){ + roofrightdim(); + translate([rooflength + 50, 0, 0]) + bottomdim(); + } + + translate([0, roofleftwidth+50, 0]){ + sidedim(); + translate([sidelength+50, 0, 0]) + hingedsidedim(); + } +} diff --git a/Vogelnestkastje/roof.scad b/Vogelnestkastje/roof.scad new file mode 100644 index 0000000..425cf10 --- /dev/null +++ b/Vogelnestkastje/roof.scad @@ -0,0 +1,54 @@ +include +include + +rooflength = nestwidth + ( 2 * plankthick ) + overhang; +roofleftwidth = nestwidth + plankthick; +roofrightwidth = nestwidth; + + +module roofleft(){ + color("green") + cube([rooflength, roofleftwidth, plankthick]); + echo("#### Roof left: length = ", nestwidth + ( 2 * plankthick ) + overhang, " width = ", nestwidth + plankthick); + +} + +module roofright(){ + color("blue") + cube([rooflength, nestwidth, plankthick]); + echo("#### Roof right: length = ", nestwidth + ( 2 * plankthick ) + overhang, " width = ", nestwidth); + +} + +module roofleftdim(){ + roofleft(); + color("black") { + translate([0, -10 , 0]) + dimensions(length=rooflength); + translate([-10, 0, 0]) + rotate([0,0,90]) + dimensions(length=roofleftwidth); + translate([0, roofleftwidth + 15, 0]) + drawtext("Roof left"); + } +} + +module roofrightdim(){ + roofright(); + color("black") { + translate([0, -10 , 0]) + dimensions(length=rooflength); + translate([-10, 0, 0]) + rotate([0,0,90]) + dimensions(length=roofrightwidth); + translate([0, roofrightwidth + 15, 0]) + drawtext("Roof right"); + } +} + +module roof(){ + rotate([-45, 0, 0]){ + roofleft(); + } + roofright(); +} diff --git a/Vogelnestkastje/sawcut.scad b/Vogelnestkastje/sawcut.scad new file mode 100644 index 0000000..ad87424 --- /dev/null +++ b/Vogelnestkastje/sawcut.scad @@ -0,0 +1,11 @@ +include + + + +module sawcut(){ + color("lightblue") + translate([0,-50,-50]) + cube([bladewidth, 250, 100]); +} + +sawcut(); diff --git a/Vogelnestkastje/side.scad b/Vogelnestkastje/side.scad new file mode 100644 index 0000000..92e39b2 --- /dev/null +++ b/Vogelnestkastje/side.scad @@ -0,0 +1,54 @@ +include +include + +sidelength = bottomtohole + plankthick + holediameter; + +module side(){ + color("orange") + cube(size=[sidelength, nestwidth, plankthick], center=false); + echo("#### Side: length = ", bottomtohole + plankthick + holediameter, " width = ", nestwidth); +} + +module hingedside(){ + difference(){ + side(); + translate([0, (nestwidth / 2) - ( (picturehookdiameter + lockplay ) /2 ), -2]){ + cube(size=[plankthick, picturehookdiameter + lockplay, plankthick+5], center=false); + } + } +} + +module sidedim(){ + side(); + color("black"){ + translate([-10, 0, 0]) + rotate([0,0,90]) + dimensions(length=nestwidth); + + translate([0, -10 , 0]) + dimensions(length=sidelength); + + translate([0, nestwidth + 15, 0]) + drawtext("Side"); + } +} + +module hingedsidedim(){ + hingedside(); + color("black"){ + translate([-10, 0, 0]) + rotate([0,0,90]) + dimensions(length=nestwidth); + translate([-20, (nestwidth/2) - ((picturehookdiameter+lockplay)/2), 0]) + rotate([0,0,90]) + dimensions(length=picturehookdiameter + lockplay, loc=DIM_OUTSIDE); + + translate([0, -10 , 0]) + dimensions(length=plankthick); + translate([0, -20 , 0]) + dimensions(length=sidelength); + + translate([0, nestwidth + 15, 0]) + drawtext("Hinged side"); + } +} diff --git a/Vogelnestkastje/vogelnestkast-assembly.png b/Vogelnestkastje/vogelnestkast-assembly.png new file mode 100644 index 0000000000000000000000000000000000000000..ae9a5b87136eb2b1fb8e77414ed5eceea82428d4 GIT binary patch literal 18554 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

&|~7X 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 ArvLx| literal 0 HcmV?d00001