2025-01-02 15:11:48 +10:30
|
|
|
CF_Tube_Len = 420; // Convenient Amazon size, longer would be better of course but prices are important
|
|
|
|
CF_Tube_OD = 5.0; // Outer Diameter
|
|
|
|
CF_Tube_ID = 3.0;
|
|
|
|
CF_Square_Width = 6.0;
|
|
|
|
CF_Square_ID = 5.0; // Inner diameter, sadly doesn't fit the tubes
|
|
|
|
|
|
|
|
cyl_hd_fn = $preview ? 32 : 512;
|
|
|
|
cyl_ld_fn = $preview ? 24 : 72;
|
2025-02-10 16:15:55 +10:30
|
|
|
|
|
|
|
module Dowel() {
|
|
|
|
h = 27;
|
|
|
|
rotate([-90, 0, 0]) {
|
|
|
|
$fn=72;
|
|
|
|
translate([0, 0, -h/2]) cylinder_beak(d=5.25, h=h);
|
|
|
|
hull() {
|
|
|
|
cylinder(d=6, h=0.00001, center=true);
|
|
|
|
cylinder_outer(d=5.25, h=3, center=true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-02 15:11:48 +10:30
|
|
|
module CFTube(hole=true) { // Align +y
|
|
|
|
rotate([0, 0, 90]) render() difference() {
|
|
|
|
rotate([0, 90, 0]) cylinder(h=CF_Tube_Len, d=CF_Tube_OD, $fn=cyl_hd_fn);
|
|
|
|
if (hole) rotate([0, 90, 0]) cylinder(h=CF_Tube_Len, d=CF_Tube_ID, $fn=cyl_ld_fn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
module CFSquare(hole=true) {
|
|
|
|
rotate([0, 0, 90]) render() difference() {
|
|
|
|
translate([0, -CF_Square_Width/2, -CF_Square_Width/2]) cube([CF_Tube_Len, CF_Square_Width, CF_Square_Width]);
|
|
|
|
if (hole) rotate([0, 90, 0]) cylinder(h=CF_Tube_Len, d=CF_Square_ID, $fn=cyl_ld_fn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hull_epsilon = 0.2;
|
|
|
|
module CFTubeCutout(x1, x2, tolerance = CF_Tube_OD_tolerance, VLH = false, taper_length = 5) {
|
|
|
|
tolerance = tolerance + (VLH ? 0.3 : 0);
|
|
|
|
taper_mul = 1.2;
|
|
|
|
taper_direction = (x1 > x2) ? (-1) : 1;
|
|
|
|
x_min = min(x1, x2);
|
|
|
|
x_max = max(x1, x2);
|
2025-02-10 14:47:30 +10:30
|
|
|
$fn = 360;
|
2025-01-02 15:11:48 +10:30
|
|
|
translate([0, x_min, 0])
|
|
|
|
rotate([-90,0,0])
|
2025-02-10 14:47:30 +10:30
|
|
|
cylinder(h=x_max-x_min, d=CF_Tube_OD+tolerance);
|
2025-01-02 15:11:48 +10:30
|
|
|
hull() {
|
|
|
|
translate([0, x1])
|
|
|
|
rotate([-90,0,0])
|
2025-02-10 14:47:30 +10:30
|
|
|
cylinder(h=hull_epsilon, d=(CF_Tube_OD*taper_mul)+tolerance);
|
2025-01-02 15:11:48 +10:30
|
|
|
translate([0, x1+(taper_length*taper_direction)])
|
|
|
|
rotate([-90,0,0])
|
2025-02-10 14:47:30 +10:30
|
|
|
cylinder(h=hull_epsilon, d=CF_Tube_OD+tolerance);
|
2025-01-02 15:11:48 +10:30
|
|
|
}
|
|
|
|
hull() {
|
|
|
|
translate([0, x2])
|
|
|
|
rotate([-90,0,0])
|
2025-02-10 14:47:30 +10:30
|
|
|
cylinder(h=hull_epsilon, d=(CF_Tube_OD*taper_mul)+tolerance);
|
2025-01-02 15:11:48 +10:30
|
|
|
translate([0, x2-(taper_length*taper_direction)])
|
|
|
|
rotate([-90,0,0])
|
2025-02-10 14:47:30 +10:30
|
|
|
cylinder(h=hull_epsilon, d=CF_Tube_OD+tolerance);
|
2025-01-02 15:11:48 +10:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module CFSquareCutout(x1, x2, tolerance = CF_Square_Width_tolerance, taper_x1 = true, taper_x2 = true, taper_length = 5) {
|
|
|
|
x = CF_Square_Width+tolerance;
|
|
|
|
taper_mul = 1.2;
|
|
|
|
taper_direction = (x1 > x2) ? (-1) : 1;
|
|
|
|
x_min = min(x1, x2);
|
|
|
|
x_max = max(x1, x2);
|
|
|
|
translate([-x/2, x_min, -x/2]) cube([x, x_max-x_min, x]);
|
|
|
|
if (taper_x1) {
|
|
|
|
hull() {
|
|
|
|
translate([0, x1, 0])
|
|
|
|
cube([x*taper_mul, hull_epsilon, x*taper_mul], center=true);
|
|
|
|
translate([0, x1+(taper_length*taper_direction), 0])
|
|
|
|
cube([x, hull_epsilon, x], center=true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (taper_x2){
|
|
|
|
hull() {
|
|
|
|
translate([0, x2, 0])
|
|
|
|
cube([x*taper_mul, hull_epsilon, x*taper_mul], center=true);
|
|
|
|
translate([0, x2-(taper_length*taper_direction), 0])
|
|
|
|
cube([x, hull_epsilon, x], center=true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-01-03 18:20:30 +10:30
|
|
|
|
2025-01-12 21:56:24 +10:30
|
|
|
module CFTubeCutout2(v, block_y0, block_y1, tolerance = CF_Tube_OD_tolerance, VLH = false, taper_length = 2, taper_mul = 1.1, notch = true, tolerance_length = CF_Square_Width_tolerance) {
|
2025-01-03 18:20:30 +10:30
|
|
|
// Alternate approach: supply start vector v, and the bounding y values of the piece, taper on entry points only.
|
|
|
|
tolerance = tolerance + (VLH ? 0.3 : 0);
|
|
|
|
tube_y0 = v[1];
|
|
|
|
tube_y1 = tube_y0 + CF_Tube_Len;
|
|
|
|
OD = CF_Tube_OD + tolerance;
|
|
|
|
taper_OD = (CF_Tube_OD*taper_mul) + tolerance;
|
|
|
|
|
2025-02-10 14:47:30 +10:30
|
|
|
$fn = 360;
|
2025-01-03 18:20:30 +10:30
|
|
|
// Full cylinder, unconditional
|
2025-01-12 21:56:24 +10:30
|
|
|
translate(v) translate([0, -tolerance_length, 0]) hull() {
|
2025-02-10 14:47:30 +10:30
|
|
|
rotate([-90,0,0]) cylinder(h=CF_Tube_Len+tolerance_length*2, d=OD);
|
2025-01-11 14:35:19 +10:30
|
|
|
if (notch) translate([-OD*0.02, 0, -OD*0.6]) cube([OD*0.04, CF_Tube_Len, OD*0.6]);
|
|
|
|
}
|
|
|
|
|
2025-01-03 18:20:30 +10:30
|
|
|
// Check for tapered holes
|
|
|
|
if ((block_y0 >= tube_y0) && (block_y0 < tube_y1)) // Tube protrudes through start of block
|
|
|
|
hull() {
|
|
|
|
translate([v[0], block_y0, v[2]])
|
2025-02-10 14:47:30 +10:30
|
|
|
rotate([-90,0,0]) cylinder(h=hull_epsilon, d=taper_OD);
|
2025-01-03 18:20:30 +10:30
|
|
|
translate([v[0], block_y0+taper_length, v[2]])
|
2025-02-10 14:47:30 +10:30
|
|
|
rotate([-90,0,0]) cylinder(h=hull_epsilon, d=OD);
|
2025-01-03 18:20:30 +10:30
|
|
|
}
|
|
|
|
if ((block_y1 <= tube_y1) && (block_y1 > tube_y0)) // Tube protrudes through end of block
|
|
|
|
hull() {
|
|
|
|
translate([v[0], block_y1-hull_epsilon, v[2]])
|
2025-02-10 14:47:30 +10:30
|
|
|
rotate([-90,0,0]) cylinder(h=hull_epsilon, d=taper_OD);
|
2025-01-03 18:20:30 +10:30
|
|
|
translate([v[0], block_y1-hull_epsilon-taper_length, v[2]])
|
2025-02-10 14:47:30 +10:30
|
|
|
rotate([-90,0,0]) cylinder(h=hull_epsilon, d=OD);
|
2025-01-03 18:20:30 +10:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-12 21:56:24 +10:30
|
|
|
module CFSquareCutout2(v, block_y0, block_y1, tolerance = CF_Square_Width_tolerance, taper_length = 2, taper_mul = 1.1, tolerance_length = CF_Square_Width_tolerance) {
|
2025-01-03 18:20:30 +10:30
|
|
|
w = CF_Square_Width + tolerance;
|
|
|
|
taper_w = (CF_Square_Width * taper_mul) + tolerance;
|
|
|
|
tube_y0 = v[1];
|
|
|
|
tube_y1 = tube_y0 + CF_Tube_Len;
|
|
|
|
|
|
|
|
// Full square rod, unconditional
|
2025-01-12 21:56:24 +10:30
|
|
|
translate([v[0]-w/2, v[1] - tolerance_length, v[2]-w/2]) cube([w, CF_Tube_Len + tolerance_length*2, w]);
|
2025-01-03 18:20:30 +10:30
|
|
|
// Check for tapered holes
|
|
|
|
if ((block_y0 >= tube_y0) && (block_y0 < tube_y1)) // Tube protrudes through start of block
|
|
|
|
hull() {
|
|
|
|
translate([v[0], block_y0, v[2]])
|
|
|
|
cube([taper_w, hull_epsilon*2, taper_w], center=true);
|
|
|
|
translate([v[0], block_y0+taper_length, v[2]])
|
|
|
|
cube([w, hull_epsilon*2, w], center=true);
|
|
|
|
}
|
|
|
|
if ((block_y1 <= tube_y1) && (block_y1 > tube_y0)) // Tube protrudes through end of block
|
|
|
|
hull() {
|
|
|
|
translate([v[0], block_y1-hull_epsilon, v[2]])
|
|
|
|
cube([taper_w, hull_epsilon*2, taper_w], center=true);
|
|
|
|
translate([v[0], block_y1-hull_epsilon-taper_length, v[2]])
|
|
|
|
cube([w, hull_epsilon*2, w], center=true);
|
|
|
|
}
|
|
|
|
}
|
2025-02-01 18:22:58 +10:30
|
|
|
|
2025-02-05 18:07:14 +10:30
|
|
|
module TrussRodGeneric(length, tolerance, stages, taper_l = 1.5, taper_extra = 1.0, taper_points=[], extra=false) {
|
2025-02-01 18:22:58 +10:30
|
|
|
$fn = 360;
|
|
|
|
epsilon = 0.00000001;
|
|
|
|
rot = [-90, 180, 0];
|
|
|
|
|
|
|
|
module squircle(d, h, w) {
|
2025-02-05 23:52:04 +10:30
|
|
|
sq_h = max(h-d, epsilon);
|
2025-02-01 18:22:58 +10:30
|
|
|
render() hull() {
|
2025-02-12 12:25:24 +10:30
|
|
|
circle_outer(d = d);
|
2025-02-05 23:52:04 +10:30
|
|
|
translate([-w/2, h - d/2 - sq_h]) square([w, sq_h]);
|
2025-02-01 18:22:58 +10:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (s = stages) rotate(rot) linear_extrude(s[0]) squircle(s[1], s[2], s[3]);
|
2025-02-02 15:03:56 +10:30
|
|
|
for (i = [0:len(stages)-2]) {
|
|
|
|
s0 = stages[i];
|
|
|
|
s1 = stages[i+1];
|
|
|
|
translate([0, s0[0], 0]) hull() {
|
|
|
|
rotate(rot) linear_extrude(epsilon) squircle(s0[1], s0[2], s0[3]);
|
|
|
|
rotate(rot) linear_extrude(taper_l) squircle(s1[1], s1[2], s1[3]);
|
|
|
|
}
|
|
|
|
}
|
2025-02-01 18:22:58 +10:30
|
|
|
if (extra) {
|
|
|
|
l = 33;
|
|
|
|
s = stages[0];
|
|
|
|
translate([0, -l, 0]) rotate(rot) linear_extrude(l+s[0]) squircle(s[1], s[2], s[3]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tapers
|
|
|
|
for (x = taper_points) {
|
|
|
|
larger_stages = [ for (s = stages) if (s[0] >= x) s];
|
|
|
|
if (len(larger_stages)) {
|
|
|
|
s = larger_stages[0];
|
|
|
|
t2 = taper_extra * 2;
|
|
|
|
render() hull() {
|
|
|
|
translate([0, x-epsilon/2, 0]) rotate(rot) linear_extrude(epsilon) squircle(s[1]+t2, s[2]+t2, s[3]+t2);
|
|
|
|
translate([0, x+taper_l-epsilon, 0]) rotate(rot) linear_extrude(epsilon) squircle(s[1], s[2], s[3]);
|
|
|
|
translate([0, x-taper_l, 0]) rotate(rot) linear_extrude(epsilon) squircle(s[1], s[2], s[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-02-05 18:07:14 +10:30
|
|
|
|
2025-02-12 12:25:24 +10:30
|
|
|
module TrussRod(length = 630, tolerance = 0, taper_l = 3.0, taper_extra = 1.0, taper_points=[], extra=false) {
|
2025-02-05 18:07:14 +10:30
|
|
|
// base profile
|
|
|
|
base_d = 6.0 + tolerance;
|
|
|
|
base_w = base_d;
|
|
|
|
base_h = 9.0 + tolerance;
|
|
|
|
|
|
|
|
// nut?
|
2025-02-12 12:25:24 +10:30
|
|
|
stage2_d = 7.05 + 0.05 + tolerance;
|
2025-02-05 18:07:14 +10:30
|
|
|
stage2_w = base_w;
|
|
|
|
stage2_h = base_h + (stage2_d - base_d);
|
|
|
|
stage2_l = 55 + tolerance;
|
|
|
|
|
|
|
|
// Turning end
|
|
|
|
stage3_d = 9.2 + tolerance;
|
|
|
|
stage3_w = stage3_d;
|
|
|
|
stage3_h = base_h + (stage3_d - base_d);
|
|
|
|
stage3_l = 35 + tolerance;
|
|
|
|
|
|
|
|
// Rod outline
|
|
|
|
stages = [ // Must be ascending order for later
|
|
|
|
[stage3_l, stage3_d, stage3_h, stage3_w],
|
|
|
|
[stage2_l, stage2_d, stage2_h, stage2_w],
|
|
|
|
[length, base_d, base_h, base_w],
|
|
|
|
];
|
|
|
|
TrussRodGeneric(length=length, tolerance=tolerance, stages=stages, taper_l=taper_l, taper_extra=taper_extra, taper_points=taper_points, extra=extra);
|
|
|
|
}
|
2025-02-14 14:23:52 +10:30
|
|
|
module TrussRodSingleAction(length = 460, tolerance = 0, taper_l = 3.0, taper_extra = 1.0, taper_points=[], extra=false) {
|
2025-02-05 18:07:14 +10:30
|
|
|
// base profile
|
|
|
|
base_d = 4.6 + tolerance;
|
|
|
|
base_w = 6.1 + tolerance;
|
|
|
|
base_h = 8.1 + tolerance;
|
|
|
|
|
|
|
|
// nut?
|
2025-02-05 23:52:04 +10:30
|
|
|
stage2_d = 7.0 + 0.8 + tolerance;
|
2025-02-05 18:07:14 +10:30
|
|
|
stage2_w = base_w;
|
|
|
|
stage2_h = base_h + (stage2_d - base_d);
|
|
|
|
stage2_l = 44 + tolerance;
|
|
|
|
|
|
|
|
// Rod outline
|
|
|
|
stages = [ // Must be ascending order for later
|
|
|
|
[stage2_l, stage2_d, stage2_h, stage2_w],
|
|
|
|
[length, base_d, base_h, base_w],
|
|
|
|
];
|
|
|
|
TrussRodGeneric(length=length, tolerance=tolerance, stages=stages, taper_l=taper_l, taper_extra=taper_extra, taper_points=taper_points, extra=extra);
|
|
|
|
}
|
2025-02-15 01:19:07 +10:30
|
|
|
|
|
|
|
|
|
|
|
module TrussRods(extra=0, tolerance=0.6) {
|
|
|
|
for (rod = $trussrod_positions) {
|
|
|
|
pos = rod[0];
|
|
|
|
rot = rod[1];
|
|
|
|
m = rod[2];
|
|
|
|
// Transform absolute taper points to relate to the position and rotation of the rod
|
|
|
|
// Currently this will only work well for truss rods aligned along the Y axis
|
|
|
|
y_mul = cos(rot[2]); // This should be +1 for 0 rotation, -1 for 180 rotation. Incomplete for now, only covers 180° Z rotation.
|
|
|
|
taper_points = [ for (y = $segment_cuts) y_mul*(y - pos[1]) ];
|
|
|
|
// echo(rod, y_mul, taper_points)
|
|
|
|
translate(pos) rotate(rot) {
|
|
|
|
if (m == "TrussRodSingleAction") TrussRodSingleAction(extra=$trussrods_extra, tolerance=tolerance, taper_points=taper_points);
|
|
|
|
if (m == "TrussRod") TrussRod(extra=$trussrods_extra, tolerance=tolerance, taper_points=taper_points);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
module CFs(taper_length = 2, taper_mul = 1.1, tolerance = CF_Tube_OD_tolerance) {
|
|
|
|
d = CF_Tube_OD + tolerance;
|
|
|
|
taper_OD = (CF_Tube_OD*taper_mul) + tolerance;
|
|
|
|
l = CF_Tube_Len;
|
|
|
|
$fn = 90;
|
|
|
|
for (v = $reinforcing_tube_positions) {
|
|
|
|
y0 = v[1];
|
|
|
|
y1 = y0+l;
|
|
|
|
translate(v = v) rotate([-90, 0, 0]) cylinder_beak(d=d, h=l);
|
|
|
|
for (cut_y = $segment_cuts) {
|
|
|
|
if (cut_y == y0) {
|
|
|
|
// Taper in only (beginning of segment)
|
|
|
|
translate([v[0], cut_y, v[2]]) rotate([-90,0,0]) cylinder_outer(d=taper_OD, d2=d, h=taper_length);
|
|
|
|
} else if (cut_y == y1) {
|
|
|
|
// Taper out only (end of segment)
|
|
|
|
translate([v[0], cut_y, v[2]]) rotate([90,0,0]) cylinder_outer(d=taper_OD, d2=d, h=taper_length);
|
|
|
|
} else if ((y1 > cut_y) && (cut_y > y0)) {
|
|
|
|
// Taper in and out (tube spans multiple segments)
|
|
|
|
translate([v[0], cut_y, v[2]]) for (i=[-1,1]) rotate([i*90,0,0]) cylinder_outer(d=taper_OD, d2=d, h=taper_length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
module Dowels() {
|
|
|
|
for (v = $dowel_positions) translate(v) Dowel();
|
|
|
|
}
|
|
|
|
module Reinforcements() {
|
|
|
|
TrussRods();
|
|
|
|
CFs();
|
|
|
|
Dowels();
|
|
|
|
}
|