3dprint/anybeam.scad

327 lines
10 KiB
OpenSCAD

//
// Anybeam OpenSCAD Library
//
// This library provides an anybeam() module that can be used to create beams
// with a variaty of hole, axle and slot patterns using a simple declaritive syntax.
//
//
// Beam String
//
// A beam is speficied with a sequence of characters, each representing a hole
// type in the beam.
//
// O Pin hole
// X Axle hole
// ( Half hole with a slot on the right.
// ) Half hole with the slot on the left.
// - (dash) A full width slot, use with ( and ) to create long slots with half hole ends like "(--)" (4 span slot) or "()" (2 span slot)
// | (line) Pin hole at the edge (rotated 90 degree in respect to normal pin hole). Beam will be rotated 90 degree if at least one its end is "|", and none of its ends are "O".
// # (hash) Axle hole at the edge.
// . (period) Skip this hole.
//
// Use the above characters to represent the hole layout on the beam:
//
// XOOOOX - Size 6 beam with axle holes at the ends.
// OOXOO - Size 5 beam with an axle hole in the middle.
// (---)OOO - Size 8 beam with a size 5 slot and three holes at the end.
//
// Between each beam is a connection vector that defines how the beams connect.
//
// [ PREVIOUS_BEAM_HOLE, CURRENT_BEAM_HOLE, ANGLE ]
//
// * Holes are numbered from 1 to N (the length of the beam) from left to right.
// * Angles are in degrees.
//
// Here is a standard 4x2 90 degree lift arm:
//
// [ "XOOO", [ 4, 1, 90 ], "OO" ]
//
// The connection hole specifier may includ a fractional part.
//
//
// Fractional Hole Spacing
//
// Here is a 4x2 beam with the size 2 beam in the midde of the size 4 beam.
// The space prevents a hole from appearing at the start of the beam where
// the two overlap.
//
// Connecting hole 2.5 of the size 4 beam to hole 1 of the size 2 beam at 90 degrees.
//
// [ "OOOO", [ 2.5, 1, 90 ], ".O" ]
//
//
// Examples:
// Constants.
AB_HOLE_SPACING = 8.0;
AB_HOLE_INSIDE_DIAMETER = 5.4;
AB_STUD_DIAMETER = 4.8;
AB_HOLE_RING_DIAMETER = 6.28;
AB_HOLE_RING_DEPTH = 0.9;
AB_BEAM_WIDTH = 7.8; // originally 7.6, restore if you want slightly thinner beams like standard ones
AB_AXLE_GAP = 1.95;
AB_AXLE_LENGTH = 5.1;
AB_BEAM_HEIGHT = 7.8;
AB_THIN_BEAM_HEIGHT = AB_BEAM_HEIGHT/3;
// From roipoussiere's string functions - https://www.thingiverse.com/thing:202724
function ab_fill(car, nb_occ, out="") = (nb_occ == 0) ? out : str(ab_fill(car, nb_occ-1, out), car);
//anybeam( [ "XOOO", [ 4, 1, 53.13 ], "OOO()", [ 5, 1, -53.13 ], "(-)X" ], 1 );
//anybeam( [ "X##X", [ 4, 1, 90 ], "X|OO|X", [ 6, 1, 90 ], "X##X", [ 4, 1, 90 ], "X|OO|X" ], 1);
// Standard small frame
//anybeam( [ "O|||O", [ 5, 1, 90 ], "O|O|O|O", [ 7, 1, 90 ], "O|||O", [ 5, 1, 90 ], "O|O|O|O" ], 1);
// Standard big frame
//anybeam( [ "O|||O", [ 5, 3, 90 ], "||O|O|O|O||", [ 9, 1, 90 ], "O|||O", [ 5, 3, 90 ], "||O|O|O|O||" ], 1);
//anybeam( [ "|O|O|", [ 5, 1, 90 ], "_|O|O|O|_", [ 9, 1, 90 ], "|O|O|", [ 5, 1, 90 ], "_|O|O|O|_" ], 1);
//anybeam_tee(stem="|O|", top="_O|");
module anybeam( beams = [], height = 1 ) {
translate([0, 0, height/2]) {
difference() {
ab_beams( beams, height * AB_BEAM_HEIGHT );
ab_holes( beams, height * AB_BEAM_HEIGHT );
}
}
}
module anybeam_straight( holes = 10, height = 1 ) {
if( len(holes )) {
anybeam( [ holes ], height);
}
else {
anybeam( [ ab_fill("O", holes ) ], height);
}
}
module anybeam_tee( stem = "OOO", top = "OOO", height = 1 ) {
anybeam( [ stem, [ 2, 1, 90 ], top ], height );
}
module anybeam_143( left = "XOOO", right = "OOOOOX", height = 1 ) {
anybeam( [ left, [ len(left), 1, 53.13 ], right ], height );
}
module anybeam_90(left = "XOOO", right = "OO", height = 1) {
anybeam( [ left, [ len(left), 1, 90 ], right ], height );
}
module anybeam_135x2(left = "XOOOOOO", middle = " () ", right = "OOX", height = 1) {
anybeam( [ left, [ len(left), 1, 45 ], middle, [ len(middle), 1, 45], right ], height );
}
//
// Test beam that uses all features.
//
module anybeam_test(left = "XOOOOOO", middle = "O(-) ", right = 3, height = 1) {
anybeam( [ left, [ len(left), 3, 45 ], middle, [ len(middle), 1, 45], right ], height );
}
//
// Support Modules
//
//
// Layout beam holes.
//
module ab_holes( beams = [], height = AB_BEAM_HEIGHT, b = 0 ) {
beam = beams[b];
connection = beams[b-1];
next_beam = beams[b+2];
if( connection ) {
if( next_beam ) {
translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] )
rotate([0, 0, connection[2]])
translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] )
ab_beam_holes( beam, height )
ab_holes( beams, height, b+2 );
}
else {
translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] )
rotate([0, 0, connection[2]])
translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] )
ab_beam_holes( beam, height );
}
}
else {
if( next_beam ) {
ab_beam_holes( beam, height )
ab_holes( beams, height, b+2 );
}
else {
ab_beam_holes( beam, height );
}
}
}
//
// Layout solid beams.
//
module ab_beams( beams = [], height = AB_BEAM_HEIGHT, b = 0 ) {
beam = beams[b];
connection = beams[b-1];
next_beam = beams[b+2];
if( connection ) {
if( next_beam ) {
translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] )
rotate([0, 0, connection[2]])
translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] )
ab_solid_beam( beam, height )
ab_beams( beams, height, b+2 );
}
else {
translate( [ (connection[0]-1)*AB_HOLE_SPACING, 0, 0 ] )
rotate([0, 0, connection[2]])
translate( [ -(connection[1]-1)*AB_HOLE_SPACING, 0, 0 ] )
ab_solid_beam( beam, height );
}
}
else {
if( next_beam ) {
ab_solid_beam( beam, height )
ab_beams( beams, height, b+2 );
}
else {
ab_solid_beam( beam, height );
}
}
}
//
// A single solid beam.
//
module ab_solid_beam( beam = "OOOO", beam_height = AB_BEAM_HEIGHT ) {
holes = len(beam) ? len(beam)-1 : beam-1;
beam_length = holes*AB_HOLE_SPACING;
rot = (beam[0] == "|" && beam[len(beam)-1] != "O" || beam[0] != "O" && beam[len(beam)-1] == "|" ? 90 : 0);
union() {
rotate([ rot, 0, 0 ])
translate( [beam_length/2,0,0] ) {
cube( [ beam_length, AB_BEAM_WIDTH, beam_height ], center=true );
translate( [-beam_length/2, 0, 0] )
cylinder( r = AB_BEAM_WIDTH/2, beam_height, center=true, $fn=100 );
translate( [beam_length/2, 0, 0] )
cylinder( r = AB_BEAM_WIDTH/2, beam_height, center=true, $fn=100 );
}
if( $children ) child(0);
}
}
module ab_beam_holes( beam = "OOOO", beam_height = AB_BEAM_HEIGHT ) {
holes = len(beam)-1;
beam_length = holes*AB_HOLE_SPACING;
layout = beam;
for (hole = [0:1:holes]) {
translate( [hole*AB_HOLE_SPACING,0,0] ) {
if( layout == "" ) {
ab_hole_pin( beam_height );
}
else {
if( layout[hole] == "O" ) {
ab_hole_pin( beam_height );
}
if( layout[hole] == "|" ) {
rotate([-90, 0, 0]) ab_hole_pin( beam_height );
}
if( layout[hole] == "(" ) {
ab_hole_left_slot( beam_height );
}
if( layout[hole] == ")" ) {
ab_hole_right_slot( beam_height );
}
if( layout[hole] == "-" ) {
ab_hole_slot( beam_height );
}
if( layout[hole] == "X" ) {
ab_hole_axle( beam_height, first = (hole==0), last = (hole==holes) );
}
if( layout[hole] == "#" ) {
rotate([-90, 0, 0]) ab_hole_axle( beam_height, first = (hole==0), last = (hole==holes) );
}
// Any other letter is a space.
}
}
}
if( $children ) child(0);
}
module ab_hole_pin( beam_height = AB_BEAM_HEIGHT ) {
cylinder(beam_height+2, AB_HOLE_INSIDE_DIAMETER/2, AB_HOLE_INSIDE_DIAMETER/2, center = true, $fn=100);
translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5])
cylinder(AB_HOLE_RING_DEPTH+1, AB_HOLE_RING_DIAMETER/2, AB_HOLE_RING_DIAMETER/2, center = true, $fn=100);
translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)])
cylinder(AB_HOLE_RING_DEPTH+1, AB_HOLE_RING_DIAMETER/2, AB_HOLE_RING_DIAMETER/2, center = true, $fn=100);
}
module ab_hole_left_slot( beam_height = AB_BEAM_HEIGHT ) {
ab_hole_pin(beam_height);
translate([AB_HOLE_SPACING/4, 0, 0]) {
cube([AB_HOLE_SPACING/2+.05,AB_HOLE_INSIDE_DIAMETER,beam_height+2], center = true);
translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5])
cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1,], center = true);
translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)])
cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1], center = true);
}
}
module ab_hole_right_slot( beam_height = AB_BEAM_HEIGHT ) {
ab_hole_pin(beam_height);
translate([-AB_HOLE_SPACING/4, 0, 0]) {
cube([AB_HOLE_SPACING/2+.05,AB_HOLE_INSIDE_DIAMETER,beam_height+2], center = true);
translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5])
cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1,], center = true);
translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)])
cube([AB_HOLE_SPACING/2+0.05, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1], center = true);
}
}
module ab_hole_slot( beam_height = AB_BEAM_HEIGHT ) {
cube([AB_HOLE_SPACING,AB_HOLE_INSIDE_DIAMETER,beam_height+2], center = true);
translate([0,0,beam_height/2-AB_HOLE_RING_DEPTH/2+.5])
cube([AB_HOLE_SPACING, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1,], center = true);
translate([0,0,-(beam_height/2-AB_HOLE_RING_DEPTH/2+.5)])
cube([AB_HOLE_SPACING, AB_HOLE_RING_DIAMETER, AB_HOLE_RING_DEPTH+1], center = true);
}
module ab_hole_axle( beam_height = AB_BEAM_HEIGHT , first = false, last = false) {
if( first == true ) {
cube([AB_AXLE_GAP,AB_AXLE_LENGTH,beam_height+2], center = true);
translate([+.5,0,0])
cube([AB_AXLE_LENGTH+1,AB_AXLE_GAP,beam_height+2], center = true);
}
if( last == true ) {
cube([AB_AXLE_GAP,AB_AXLE_LENGTH,beam_height+2], center = true);
translate([-.5,0,0])
cube([AB_AXLE_LENGTH+1,AB_AXLE_GAP,beam_height+2], center = true);
}
if( first == false && last == false ) {
cube([AB_AXLE_GAP,AB_AXLE_LENGTH,beam_height+2], center = true);
cube([AB_AXLE_LENGTH,AB_AXLE_GAP,beam_height+2], center = true);
}
}