├── box.png ├── boards.png ├── README.md ├── dovetail-box.scad └── dovetails.scad /box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfinke/OpenSCAD-Dovetails/HEAD/box.png -------------------------------------------------------------------------------- /boards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cfinke/OpenSCAD-Dovetails/HEAD/boards.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | OpenSCAD Dovetails 2 | ================== 3 | A library for generating dovetail tails and pins in OpenSCAD. 4 | 5 | `dovetail_pins()` will generate just the pins of a dovetail joint. 6 | 7 | `dovetail_tails()` will generate just the tails of a dovetail joint. 8 | 9 | `board_with_dovetail_tails()` and `board_with_dovetail_pins()` are much more useful; they will generate boards with pins or tails cut into each end. 10 | 11 | The default output of `dovetails.scad` is just a pair of boards with pins and tails. 12 | 13 | ![A pair of boards with pins and tails](/boards.png) 14 | 15 | `dovetail-box.scad` demonstrates how four boards would fit together and is also an example of pins and tails of different thicknesses. 16 | 17 | ![A dovetailed box frame](/box.png) -------------------------------------------------------------------------------- /dovetail-box.scad: -------------------------------------------------------------------------------- 1 | use ; 2 | 3 | tail_width = .75; 4 | tail_count = 3; 5 | board_width = 4; 6 | angle = 15; 7 | board_thickness = 0.25; 8 | board_thickness_2 = 0.5; 9 | pin_width = pin_width(tail_width = tail_width, tail_count=tail_count, board_width=board_width); 10 | 11 | color( "white" ) translate([board_thickness, 0, 0]) rotate([0, -90, 0]) 12 | board_with_dovetail_tails( 13 | board_length=8, 14 | board_width=board_width, 15 | board_thickness=board_thickness, 16 | tail_length=board_thickness_2, 17 | tail_width=tail_width, 18 | pin_width=pin_width, 19 | tail_count=tail_count, 20 | angle=angle 21 | ); 22 | 23 | color( "white" ) translate([6, 0, 0]) rotate([0, -90, 0]) board_with_dovetail_tails( 24 | board_length=8, 25 | board_width=board_width, 26 | board_thickness=board_thickness, 27 | tail_length=board_thickness_2, 28 | tail_width=tail_width, 29 | pin_width=pin_width, 30 | tail_count=tail_count, 31 | angle=angle 32 | ); 33 | 34 | color( "brown" ) translate([0, 8, 0]) rotate([0, 0, -90]) translate([board_thickness_2, 0, 0]) rotate([0, -90, 0])board_with_dovetail_pins( 35 | board_length=6, 36 | board_width=board_width, 37 | board_thickness=board_thickness_2, 38 | pin_length=board_thickness, 39 | tail_width=tail_width, 40 | pin_width=pin_width, 41 | pin_count = tail_count + 1, 42 | angle=angle 43 | ); 44 | 45 | color( "brown" ) translate([6, 0, 0]) rotate([0, 0, 90]) translate([board_thickness_2, 0, 0]) rotate([0, -90, 0])board_with_dovetail_pins( 46 | board_length=6, 47 | board_width=board_width, 48 | board_thickness=board_thickness_2, 49 | pin_length=board_thickness, 50 | tail_width=tail_width, 51 | pin_width=pin_width, 52 | pin_count = tail_count + 1, 53 | angle=angle 54 | ); -------------------------------------------------------------------------------- /dovetails.scad: -------------------------------------------------------------------------------- 1 | /** 2 | * pin_length is measured along the same axis as the length of the board. 3 | * pin_width is the width of the bottom of the pins, where they're widest. 4 | * pin_thickness is measured along the same axis as the board thickness. 5 | * tail_width is the width of the tails where they meet the bottom of the pins, where they're narrowest. 6 | */ 7 | module dovetail_pins(pin_length=.75, pin_width=1, pin_thickness=.75, pin_count=4, angle=15, tail_width=1) { 8 | intersection() { 9 | translate([0.005, 0.005, 0.005]) cube([(pin_count-1)*(pin_width+tail_width)-0.01, pin_length-0.01, pin_thickness-0.01]); 10 | dovetail_pins_idealized( 11 | pin_length=pin_length, 12 | pin_width=pin_width, 13 | pin_thickness=pin_thickness, 14 | pin_count=pin_count, 15 | angle=angle, 16 | tail_width=tail_width 17 | ); 18 | } 19 | } 20 | 21 | /** 22 | * tail_length is measured along the same axis as the length of the board. 23 | * tail_width is the width of the tails where they meet the board, where they're narrowest. 24 | * tail_thickness is measured along the same axis as the board thickness. 25 | * pin_width is the width of the bottom of the pins, where they're widest. 26 | */ 27 | module dovetail_tails(tail_length=.75, tail_width=1, tail_thickness=.75, tail_count=3, angle=15, pin_width=1) { 28 | pin_count = tail_count + 1; 29 | pin_thickness = tail_length; 30 | pin_length = tail_thickness; 31 | 32 | translate([0, 0, tail_thickness]) { 33 | rotate([-90, 0, 0]) { 34 | translate([0, 0, -0.005]) { 35 | difference() { 36 | translate([0.005, 0.005, 0.005]) { 37 | cube([(pin_count-1)*(pin_width+tail_width)-0.01, tail_thickness-0.01, tail_length-0.01]); 38 | } 39 | 40 | dovetail_pins_idealized( 41 | pin_length=pin_length, 42 | pin_width=pin_width, 43 | pin_thickness=pin_thickness, 44 | pin_count=pin_count, 45 | angle=angle, 46 | tail_width=tail_width 47 | ); 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | /** 55 | * Used for generating both pins and tails. Don't call this directly. 56 | */ 57 | module dovetail_pins_idealized( 58 | pin_length=.75, 59 | pin_width=1, 60 | pin_thickness=.75, 61 | pin_count=4, 62 | angle=15, 63 | tail_width=1) { 64 | 65 | pin_width_top = pin_width - ( 2 * tan(angle) * pin_thickness ); 66 | 67 | translate([0, pin_length, 0]) { 68 | rotate([90, 0, 0]) { 69 | intersection() { 70 | cube([(pin_count-1)*(pin_width+tail_width), pin_thickness, pin_length]); 71 | 72 | for (pin = [0:pin_count-1]) { 73 | translate([pin * (pin_width + tail_width), 0]) { 74 | linear_extrude(pin_length) { 75 | polygon([ 76 | [-pin_width/2, 0], 77 | [-pin_width_top/2, pin_thickness], 78 | [pin_width_top/2, pin_thickness], 79 | [pin_width/2, 0] 80 | ]); 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * Determine the width the pins need to be once the tail widths are chosen. 91 | */ 92 | function pin_width (tail_width, tail_count, board_width) = ( board_width - (tail_width * tail_count) ) / (tail_count); 93 | 94 | /** 95 | * Construct a board with tails cut into it. board_length includes the length of the tails. 96 | */ 97 | module board_with_dovetail_tails(board_length, board_width, board_thickness, tail_length, tail_width, pin_width, tail_count, angle) { 98 | 99 | tail_thickness = board_thickness; 100 | 101 | pin_width = pin_width(tail_width = tail_width, tail_count=tail_count, board_width=board_width); 102 | translate([0, board_length - ( 2 * tail_length) + tail_length, 0]) { 103 | dovetail_tails(tail_length=tail_length, tail_width=tail_width, tail_thickness=tail_thickness, tail_count=tail_count, angle=angle, pin_width=pin_width); 104 | } 105 | translate([0, tail_length, 0]) cube([board_width, board_length - ( 2 * tail_length), board_thickness]); 106 | translate([0, tail_length, 0]) mirror([0,1,0]) dovetail_tails(tail_length=tail_length, tail_width=tail_width, tail_thickness=tail_thickness, tail_count=tail_count, angle=angle, pin_width=pin_width); 107 | } 108 | 109 | /** 110 | * Construct a board with pins cut into it. board_length includes the length of the pins. 111 | */ 112 | module board_with_dovetail_pins(board_length, board_width, board_thickness, pin_length, tail_width, pin_width, pin_count, angle) { 113 | translate([0, board_length - ( 2 * pin_length) + pin_length, 0]) { 114 | dovetail_pins(pin_length=pin_length, pin_width=pin_width, pin_thickness=board_thickness, pin_count=pin_count, angle=angle, tail_width=tail_width); 115 | } 116 | translate([0, pin_length, 0]) cube([board_width, board_length - ( 2 * pin_length), board_thickness]); 117 | dovetail_pins(pin_length=pin_length, pin_width=pin_width, pin_thickness=board_thickness, pin_count=pin_count, angle=angle, tail_width=tail_width); 118 | } 119 | 120 | // An example set of boards. 121 | tail_width = .75; 122 | tail_count = 3; 123 | board_width = 4; 124 | angle = 15; 125 | board_thickness = 0.5; 126 | pin_width = pin_width(tail_width = tail_width, tail_count=tail_count, board_width=board_width); 127 | 128 | board_with_dovetail_tails( 129 | board_length=8, 130 | board_width=board_width, 131 | board_thickness=board_thickness, 132 | tail_length=.5, 133 | tail_width=tail_width, 134 | pin_width=pin_width, 135 | tail_count=tail_count, 136 | angle=angle 137 | ); 138 | 139 | translate([board_width + 1, 0, 0]) board_with_dovetail_pins( 140 | board_length=6, 141 | board_width=board_width, 142 | board_thickness=board_thickness, 143 | pin_length=.5, 144 | tail_width=tail_width, 145 | pin_width=pin_width, 146 | pin_count = tail_count + 1, 147 | angle=angle 148 | ); --------------------------------------------------------------------------------