hexbrick/hexbrick-lib.scad

180 lines
5.3 KiB
OpenSCAD
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// hex toy bricks based on designs described at
// http://tamivox.org/redbear/hex_toy_bricks/index2.html
// I follow the prose descriptions and formulas given there, but this
// implementation in openscad is original.
// configurable values
stud_height = 2;
base_height = 3;
base_width = 3.5;
outer_width = .8;
inner_width = .64;
ceiling_thickness = .6;
stud_inset = .05;
outer_wall_inset = .25;
corner_round = .05;
// Round or hex studs are both viable choices
use_round_stud = false;
// "the base height equals the sum of the socket depth and the ceiling
// thickness"
socket_depth = base_height - ceiling_thickness;
// "the stud height cannot be more than the socket depth"
if(socket_depth < stud_height) error();
// "If the stud width is denoted by S, the base width by B, and the inner width
// by I, then S = (B - I) / sqrt(3)" says tamivox.org, but this doesn't
// make a correct model in openscad even after accounting for the fact that
// a "hexagon" constructed with cylinder() is measured with the diameter across
// points instead of across flats.
hex_stud_width = base_width - inner_width / sqrt(3);
// "Some manufacturers might prefer a round stud. For a crisp fit in the
// hexagonal sockets, the diameter should be sqrt(3) times the stud width as
// given in figure F-1a"
round_stud_width = hex_stud_width * sqrt(3)/2;
// advance from point to point of hex
short_advance = base_width * sqrt(3);
// advance from to flat of hex
long_advance = 1.5 * base_width;
X = 1*[1,0,0];
Y = 1*[0,1,0]; XY = X+Y;
Z = 1*[0,0,1]; XZ = X+Z; YZ = Y+Z; XYZ=X+Y+Z;
module cube_cc(sz, cc) {
translate([sz[0] * cc[0] * -.5, sz[1] * cc[1] * -.5, sz[2] * cc[2] *-.5])
cube(sz);
}
module cube_cx(sz) { cube_cc(sz, X); }
module cube_cy(sz) { cube_cc(sz, Y); }
module cube_cxy(sz) { cube_cc(sz, X+Y); }
module lambda_wall(width=inner_width) {
for(th=[0,120,240])
rotate([0,0,th])
cube_cy([base_width, width, base_height - ceiling_thickness/2]);
}
module hexgrid(x, y) {
yprime = y + .5 * x;
translate([x*long_advance, yprime*short_advance,0]) children();
}
// Output a hex grid of walls nx × ny
module inner_walls(nx, ny) {
translate([-base_width/2, -short_advance/2, -base_height])
for(x=[-1:1:nx]) {
for(y=[-1:1:ny]) {
hexgrid(x,y) lambda_wall();
}
}
}
module outline_single() {
rotate(Z*30)
circle(short_advance, $fn=6);
}
module round_stud() {
cylinder(r=round_stud_width-stud_inset, h=stud_height);
}
module hex_stud() {
difference() {
translate(-ceiling_thickness*Z/2)
cylinder(r=hex_stud_width-stud_inset, h=stud_height+ceiling_thickness/2, $fn=6);
if(0) translate(-ceiling_thickness*Z)
cylinder(r=(hex_stud_width-stud_inset)/2, h=stud_height+2*ceiling_thickness, $fn=24);
}
}
module stud() {
if(use_round_stud) round_stud(); else hex_stud();
}
function maxcoord_x(seq, best=0) = len(seq) == 0 ? best
: maxcoord_x(rest(seq), max(best, seq[0][0]));
function maxcoord_x(seq, best=0) = len(seq) == 0 ? best
: maxcoord_x(rest(seq), max(best, seq[0][0]));
module outline_coordlist(cc) {
offset(r=-corner_round)
offset(r=corner_round)
for(ii=[0:1:len(cc)-1]) {
ci = cc[ii];
hull() {
for(jj=[0:1:len(ci)-1]) {
cij = ci[jj];
x = cij[0];
y = cij[1];
hexgrid(x,y) outline_single();
}
}
}
}
module inner_volume_coordlist(cc) {
translate([0,0,-base_height-1])
linear_extrude(height=base_height+2)
offset(delta=-outer_wall_inset-outer_width/2)
outline_coordlist(cc);
}
module outer_walls_coordlist(cc) {
translate(-Z*base_height)
linear_extrude(height=base_height-ceiling_thickness/2)
difference() {
offset(delta=-outer_wall_inset)
outline_coordlist(cc);
offset(delta=-outer_width-outer_wall_inset)
outline_coordlist(cc);
}
}
module ceiling_coordlist(cc) {
translate((-ceiling_thickness+1e-3)*Z)
linear_extrude(height=ceiling_thickness)
offset(delta=-outer_wall_inset-1e-3)
outline_coordlist(cc);
}
// The structure of the "cc" parameter is complicated:
// It is a list of lists of nonnegative integer coords
// Each coord gets a stud
// The outer walls for each list of points get hulled together, which is useful
// for lateral bricks. The outermost lists are not hulled but common edges
// are eliminated, which is useful for punctal bricks. It seems possible that
// there are uses for bricks that combine punctal and lateral features.
module piece_coordlist(cc, sc=undef) {
maxx = max([for (i=cc) max([for(j=i) j[0]])]);
maxy = max([for (i=cc) max([for(j=i) j[1]])]);
color("red") outer_walls_coordlist(cc);
intersection() {
color("blue") inner_walls(maxx+1, maxy+1);
inner_volume_coordlist(cc);
}
st = (sc == undef) ? cc : sc;
color("orange") ceiling_coordlist(cc);
for(ii=[0:1:len(st)-1]) {
ci = st[ii];
for(jj=[0:1:len(ci)-1]) {
cij = ci[jj];
x = cij[0];
y = cij[1];
hexgrid(x,y) stud();
}
}
}
module piece_punctual(cc, sc=undef) {
cc = [for (i=cc) [i]];
sc = (sc == undef) ? cc : [for (i=sc) [i]];
piece_coordlist(cc, sc);
}