My headboard is a bit of a kludge and could do with some tidying up, but here it is.
Code: Select all
// Upper row text
Upper_row_text="SANTA";
// Lower row text
Lower_row_text="SPECIAL";
// The angle of the arc forming the headboard
angle=100; // [30:5:120]
// How thick the board on which the lettering is placed should be
backboard_thickness=2; // [1:0.5:5]
// How high the letters should be
font_size=6; // [4:12]
// The thickness of the letters above the board
lettering_thickness=1; // [0.5:0.5:5]
// The radius of arc forming the outer edge of the headboard
outer_radius=50; // [30:100]
// How big the border around the edge of the board should be
border_height=1; // [0.5:0.5:2]
// The number of letters in the row with the most letters
max_letters=max(len(Upper_row_text),len(Lower_row_text));
// The height of the headboard (i.e. the difference between the inner and outer radii)
board_height=font_size*3+border_height*2;
// Create the backboard
back_board(backboard_thickness,outer_radius,board_height,angle,lettering_thickness,border_height);
// Add the text
// Upper row
translate([0,0,backboard_thickness])
text_arc(Upper_row_text,max_letters,font_size,lettering_thickness,outer_radius-board_height/2+font_size/2-2,0.75*angle);
// Lower row
translate([0,0,backboard_thickness])
text_arc(Lower_row_text,max_letters,font_size,lettering_thickness,outer_radius-board_height+font_size/2,0.75*angle);
module text_arc(the_text,max_letters,font_size,lettering_thickness,radius,angle) {
number_of_letters=len(the_text);
letter_difference=max_letters-number_of_letters;
for (i = [0:number_of_letters]) {
letter_angle=angle/2-((i+1+letter_difference/2)*(angle/(max_letters+1)));
rotate(letter_angle)
translate([0,radius,0])
linear_extrude(lettering_thickness)
text(the_text[i],halign="center",font_size);
}
}
module back_board(thickness,radius,height,angle,border_thickness,border_width){
difference() {
union(){
cylinder(thickness,radius,radius);
circ(thickness+border_thickness,radius,border_width);
circ(thickness+border_thickness,radius-height+border_width,border_width);
rotate(90-angle/2)
cube([radius,border_width,thickness+border_thickness]);
rotate(-90+angle/2)
translate([-radius,0,0])
cube([radius,border_width,thickness+border_thickness]);
offset_cylinder(thickness+border_thickness,height/2+border_width,radius,angle/2);
offset_cylinder(thickness+border_thickness,height/2+border_width,radius,-angle/2);
}
translate([0,0,-1])
cylinder(thickness+border_thickness+2,radius-height,radius-height);
translate([0,0,-1])
circ(thickness+border_thickness+2,2*radius,radius);
rotate(-angle/2)
translate([0,0,-1])
cube([radius,2*radius,thickness+border_thickness+2]);
rotate(angle/2)
translate([-radius,0,-1])
cube([radius,2*radius,thickness+border_thickness+2]);
translate([0,0,-1])
offset_cylinder(thickness+border_thickness+2,height/2,radius,angle/2);
translate([0,0,-1])
offset_cylinder(thickness+border_thickness+2,height/2,radius,-angle/2);
translate([-radius,-radius,-1])
cube([radius*2,radius+2,thickness+border_thickness+2]);
}
}
module circ(thickness,radius,width) {
difference(){
cylinder(thickness,radius,radius);
translate([0,0,-1])
cylinder(thickness+2,radius-width,radius-width);
}
}
module offset_cylinder(height,radius,distance,angle){
rotate(angle)
translate([0,distance,0])
cylinder(height,radius,radius);
}
module two_offset_cylinders(height,radius,distance,angle){
offset_cylinder(height,radius,distance,angle);
offset_cylinder(height,radius,distance,-angle);
}
module sector(thickness,radius,angle) {
difference(){
cylinder(thickness,radius,radius);
translate([0,0,-1])
two_offset_cubes(thickness+2,radius,radius,angle);
}
}
module offset_cube(thickness,length,width,angle){
rotate(45+angle)
cube([length,width,thickness]);
}
module two_offset_cubes(thickness,length,width,height){
offset_cube(thickness,length,width,angle);
offset_cube(thickness,length,width,-angle);
}
module arc(thickness,radius,angle,width) {
difference(){
sector(thickness,radius+width,angle);
translate([0,0,-1])
sector(thickness+2,radius,angle+2);
}
}
$fn=100;
Much like in TinkerCAD creating complex shapes is just a case of taking some simple shapes and combining them or subtracting one from another. For example a sector (or whatever the 3D equivalent of a sector is!) I made by taking a cylinder and then chopping off the bits I didn't want with some large cubes... crude, but exactly what I'd do in TinkerCAD. And arc (or 3D arc) is then just a sector with a sector subtending the same angle but a smaller radius subtracted from it.
I've used my curved text code from above but called it twice, once for each row. Rather than set the angle for each individual letter to rotate through I've set an angle for the arc of the whole headboard, and spaced the letters out within that. I'm not really sure whether this is a better approach. I also wanted the spacing for each row to be the same so I needed to base it on the number of letters in the longest row - OpenSCAD's max() makes it really easy to find the largest of the inputs you give it.
As you can see you can change the text and various other parameters. Because it will use whatever space is available, if you try to cram too many letters in they will overlap, so you need to be careful when choosing your combination of text/angle/radius. It's currently set up more for fiddling than guaranteeing a good result every time - but it's still quicker than editing my headboard in TinkerCAD!
Here's a print from the code back in the summer for our first meet-up since 2019. It's a prototype for a headboard in memory of our friend in the South West Wales area group.
Even after fiddling the parameters you can see the letter spacing is a problem more generally - since really having each letter spaced evenly never works. An 'I' is much narrower than a 'W'. I haven't found anything in OpenSCAD to solve this, although I think from Googling around there may be libraries other people have developed which I can use - I need to look into this more... So when I have a moment to refine this code I'm going to try to improve this - or at least make the various parameters 'interlock' a bit more so it's quicker to get something that just works, whatever the length of the text.