Skip to content

Instantly share code, notes, and snippets.

@widget-
Created January 30, 2023 16:45
Show Gist options
  • Save widget-/2267cd6281c7870e7a6a22f74413ad89 to your computer and use it in GitHub Desktop.
Save widget-/2267cd6281c7870e7a6a22f74413ad89 to your computer and use it in GitHub Desktop.
include <BOSL2/std.scad>
// use -D on cli to render one part
// -D=top_leg
// -D=bottom_leg
// -D=top_ring
// -D=mid_ring_segment
// -D=bottom_ring
// empty for full-size preview
part=""; // ["","top_leg","bottom_leg","top_ring","mid_ring_segment","bottom_ring"]
preview_amount_degrees = 360;
// // mini ball:
// ball_radius = 80;
// strut_count = 8;
// neck_hole_radius = 30;
// center_band_width = 20;
// strut_thickness = 5;
// strut_connector_length = 5;
// full ball
ball_radius = 215;
strut_thickness = 10;
strut_connector_length = 10;
strut_count = 8;
neck_hole_radius = 110;
center_band_width = 50;
wall_thickness = 1.5;
shell_thickness = 0.7;
strut_repeat_x = 1;
strut_repeat_y = 2;
_wall_thickness_angle = wall_thickness/ball_radius*180/PI;
_strut_connector_length_angle = strut_connector_length/ball_radius*180/PI;
strut_width = (strut_thickness - wall_thickness) * strut_repeat_x+wall_thickness;
strut_height = (strut_thickness - wall_thickness) * strut_repeat_y+wall_thickness;
_bottom_hole_angle = acos((neck_hole_radius+strut_height)/ball_radius);
_center_band_angle = atan(center_band_width/ball_radius)/2;
_top_cutout_radius = strut_count*(strut_width+wall_thickness)/PI/2;
_top_ring_height_offset = sqrt(ball_radius^2-_top_cutout_radius^2);
_top_ring_height_angle = asin(_top_ring_height_offset/ball_radius);
rear_button_radius = 30;
rear_button_band_width = 15;
eye_and_mouth_border = 6;
eye_width = 48;
eye_height = 72;
eye_separation = 130;
mouth_top_radius_x = 50;
mouth_top_radius_z = 60;
mouth_bottom_radius_x = 87.5;
mouth_bottom_radius_z = 140;
mouth_hole_spacing = 7;
mouth_hole_size = 4;
eye_to_crown = 80;
crown_radius = 580/2/PI;
crown_circumference_minor = 280;
crown_circumference_major = 310;
hollow = true; // for resin prints
screw_holes = false; // for fdm prints
slop = 0.6; // slop for combining holes
rough_render = false;
explode = false;
explode_distance = 50;
$fa = $preview ? 1 : 1;
$fs = $preview ? 5 : 1;
module render_if_rendering() {
// yeah this is stupid but OpenSCAD needs it to make repeats way faster while rendering
if (!$preview)
render()
children();
else
children();
}
module strut_outer_2d(_slop) {
render() {
// top arc
_arc_points = strut_width;
_angle = atan(strut_width/2 / ball_radius);
_step = _angle / _arc_points;
points = [for (a=[-_angle : _step : _angle]) [sin(a)*ball_radius, cos(a)*ball_radius]];
fwd(points[0][1] - strut_height/2)
polygon(points);
// outer perimiter
difference() {
rect([strut_width, strut_height]);
offset(delta=_slop/2)
rect([strut_width-wall_thickness*2, strut_height-wall_thickness*2]);
}
// diagonal struts
// offset(delta=-slop/2)
// xcopies(spacing=strut_thickness-wall_thickness, n=strut_repeat_x)
// ycopies(spacing=strut_thickness-wall_thickness, n=strut_repeat_y) {
// zrot_copies([45, -45])
// rect([wall_thickness, strut_thickness * sqrt(2)], chamfer=wall_thickness/2);
// }
}
}
/** positive slop = smaller size */
module strut_inner_2d(_slop) {
render()
difference() {
offset(delta=_slop)
rect([strut_width-wall_thickness*2, strut_height-wall_thickness*2]);
offset(delta=_slop)
offset(delta=-wall_thickness)
rect([strut_width-wall_thickness*2, strut_height-wall_thickness*2]);
}
}
module strut_solid_2d(for_differencing = false) {
render_if_rendering()
if (for_differencing) {
rect([strut_width-wall_thickness, ball_radius]);
} else {
rect([strut_width-wall_thickness, strut_height-wall_thickness]);
}
}
/** Heightwise strut */
module long_strut_arc_outer(sa, ea) {
render_if_rendering()
yrot(-sa)
xrot(90)
rotate_extrude(angle=ea-sa)
right(ball_radius - strut_height/2)
zrot(-90)
strut_outer_2d(slop);
}
/** Subtractive piece to make sure vertical struts line up */
module long_strut_arc_solid(sa, ea) {
render_if_rendering()
yrot(-sa)
xrot(90)
rotate_extrude(angle=ea-sa)
right(ball_radius - strut_height/2)
zrot(-90)
strut_solid_2d(for_differencing=true);
}
/** Heightwise connecter sticky-out bit */
module long_strut_arc_inner(sa, ea, _slop=0) {
render_if_rendering()
yrot(-sa)
xrot(90)
rotate_extrude(angle=ea-sa)
right(ball_radius - strut_height/2)
zrot(-90)
strut_inner_2d(_slop);
}
/** Lengthwise connecter sticky-out bit */
module lat_strut_arc_outer(sa, ea, long_angle) {
// // ¯\_(ツ)_/¯
// angle_adjustment = - long_angle/100 + long_angle^2/45^2;
// angle_adjustment = 1-long_angle/360;
angle_adjustment = 1;
length = ea - sa;
render_if_rendering()
zrot(-sa*angle_adjustment)
rotate_extrude(angle=length*angle_adjustment)
zrot(long_angle)
right(ball_radius - strut_height/2)
zrot(-90)
strut_outer_2d(slop);
}
module lat_strut_arc_solid(sa, ea, long_angle) {
length = ea - sa;
// angle_adjustment = 1-long_angle/360;
angle_adjustment = 1;
render_if_rendering()
zrot(-sa*angle_adjustment)
rotate_extrude(angle=length*angle_adjustment)
zrot(long_angle)
right(ball_radius - strut_height/2)
zrot(-90)
strut_solid_2d();
}
module lat_strut_arc_inner(sa, ea, long_angle, _slop) {
// angle_adjustment = - long_angle/100 + long_angle^2/45^2;
length = ea - sa;
// angle_adjustment = 1-long_angle/360;
angle_adjustment = 1;
render_if_rendering()
zrot(-sa*angle_adjustment)
rotate_extrude(angle=length*angle_adjustment)
zrot(long_angle)
right(ball_radius - strut_height/2)
zrot(-90)
strut_inner_2d(_slop);
}
module top_ring() {
// numbers we need
_ring_center_height = _top_ring_height_offset - strut_height*sin(_top_ring_height_angle)/2;
_ring_center_radius = cos(_top_ring_height_angle)*(_ring_center_height);
_circumscribed_outer_ring_center_radius = _ring_center_radius / cos(180/strut_count);
_top_ring_connector_end_angle = _top_ring_height_angle - _strut_connector_length_angle;
// the ring part
up(_ring_center_height)
zrot(180/strut_count)
rotate_extrude($fn=strut_count)
right(_circumscribed_outer_ring_center_radius - strut_width / 2)
skew(sxy=cos(_top_ring_height_angle))
strut_outer_2d(slop);
// legs that stick out
zrot_copies(n=strut_count)
long_strut_arc_inner(_top_ring_height_angle + _wall_thickness_angle, _top_ring_connector_end_angle);
}
module top_leg() {
// hull()
_connector_offset = strut_width/ball_radius*180/PI;
// These are the angles struts going horizontallyu
_top_leg_arcs = [
// _center_band_angle+_strut_connector_length_angle/2,
(_top_ring_height_angle-(_center_band_angle+_strut_connector_length_angle/2))*1/3+_center_band_angle+_strut_connector_length_angle/2,
(_top_ring_height_angle-(_center_band_angle+_strut_connector_length_angle/2))*2/3+_center_band_angle+_strut_connector_length_angle/2
];
// These are the struts going vertically. They end at the center band on the bottom and top ring on the top
long_strut_arc_outer(_center_band_angle, _top_leg_arcs[0]-_connector_offset/2);
long_strut_arc_outer(_top_leg_arcs[0]+_connector_offset/2, _top_leg_arcs[1]-_connector_offset/2);
long_strut_arc_outer(_top_leg_arcs[1]+_connector_offset/2, _top_ring_height_angle);
sw_deg = -strut_width/ball_radius*90/PI;
zrot(sw_deg) {
difference() {
union() {
for (i = _top_leg_arcs) {
// hi yes this is a hack - we move it too far then cut it on the left edge below
lat_strut_arc_outer(-sw_deg*2, 360/strut_count-sw_deg*4, i);
zrot(360/strut_count)
lat_strut_arc_solid(0, sw_deg*3, i);
}
outer_shell_arc(360/strut_count, _center_band_angle, _top_ring_height_angle);
}
left(0.01)
for (i = _top_leg_arcs) {
lat_strut_arc_inner(0, -sw_deg*4, i, slop);
}
// cut away right edge by rotating to where next beam is
zrot(360/strut_count+_connector_offset/2)
long_strut_arc_solid(_center_band_angle, _top_ring_height_angle);
// cut away left edge by moving linearly to the left
zrot(-sw_deg)
fwd(strut_width-slop-.44) // what is this from??
long_strut_arc_solid(_center_band_angle, _top_ring_height_angle);
}
}
for (i = _top_leg_arcs) {
zrot(360/strut_count+sw_deg*2) {
lat_strut_arc_inner(0, -sw_deg*3, i, -slop);
}
}
}
module outer_shell_arc(width, long_start, long_end) {
points = [
each arc(r=ball_radius+.1, angle=[long_start, long_end]),
each reverse(arc(r=ball_radius+.1-shell_thickness, angle=[long_start, long_end]))
];
rotate_extrude(angle=width)
polygon(points);
}
module mid_ring_segment() {
sw_deg = -strut_width/ball_radius*90/PI;
zflip_copy()
union() {
zrot(sw_deg)
lat_strut_arc_outer(0, 360/strut_count, _center_band_angle+sw_deg);
zrot(360/strut_count+sw_deg)
lat_strut_arc_solid(0, sw_deg, _center_band_angle+sw_deg);
zrot(360/strut_count+sw_deg)
lat_strut_arc_inner(0, -sw_deg*2, _center_band_angle+sw_deg, -slop);
zrot(sw_deg/4)
long_strut_arc_inner(_center_band_angle-_wall_thickness_angle+.15, _center_band_angle+_strut_connector_length_angle);
}
long_strut_arc_outer(-_center_band_angle+strut_width/ball_radius*180/PI, _center_band_angle-strut_width/ball_radius*180/PI);
outer_shell_arc(360/strut_count+sw_deg, -_center_band_angle, _center_band_angle);
}
module bottom_leg() {
// hull()
_connector_offset = strut_width/ball_radius*180/PI;
_bottom_leg_arcs = [
-20,
-_bottom_hole_angle+_strut_connector_length_angle/2
];
// These are the struts going vertically. They end at the center band on the bottom and top ring on the top
long_strut_arc_outer(-_center_band_angle, _bottom_leg_arcs[0]+_connector_offset/2);
long_strut_arc_outer(_bottom_leg_arcs[0]-_connector_offset/2, _bottom_leg_arcs[1]+_connector_offset/2);
long_strut_arc_outer(_bottom_leg_arcs[1]-_connector_offset/2, -_bottom_hole_angle);
sw_deg = -strut_width/ball_radius*90/PI;
zrot(sw_deg) {
difference() {
union() {
for (i = _bottom_leg_arcs) {
// hi yes this is a hack - we move it too far then cut it on the left edge below
lat_strut_arc_outer(-sw_deg*1.5, 360/strut_count-sw_deg*4, i);
zrot(360/strut_count)
lat_strut_arc_solid(0, sw_deg*3, i);
}
outer_shell_arc(360/strut_count, -_center_band_angle, -_bottom_hole_angle);
}
left(0.01)
for (i = _bottom_leg_arcs) {
lat_strut_arc_inner(0, -sw_deg*4, i, slop);
}
// cut away right edge by rotating to where next beam is
zrot(360/strut_count+_connector_offset/2)
long_strut_arc_solid(_center_band_angle, -_bottom_hole_angle-5);
// cut away left edge by moving linearly to the left
zrot(-sw_deg)
fwd(strut_width-.76)
long_strut_arc_solid(_center_band_angle, -_bottom_hole_angle-5);
}
}
for (i = _bottom_leg_arcs) {
zrot(360/strut_count+sw_deg*2) {
lat_strut_arc_inner(0, -sw_deg*3, i, -slop);
}
}
}
// color("cyan")
// strut_outer_2d();
// color("green")
// strut_inner_2d();
// hull()
union() {
if (part=="") {
difference() { union() {
// bottom legs
down(explode ? explode_distance : 0)
color("#CCAAFF55")
zrot_copies([0:360/strut_count:preview_amount_degrees])
right(explode ? explode_distance : 0)
back(explode ? explode_distance/2 : 0)
render_if_rendering()
bottom_leg();
// top ring
up(explode ? explode_distance*2 : 0)
color("#66CC0099")
top_ring();
// middle sections
color("#FFFF0055")
zrot_copies([0:360/strut_count:preview_amount_degrees])
right(explode ? explode_distance : 0)
back(explode ? explode_distance/2 : 0)
render_if_rendering()
mid_ring_segment();
// top legs
up(explode ? explode_distance : 0)
color("#AACCFF55")
zrot_copies([0:360/strut_count:preview_amount_degrees])
right(explode ? explode_distance : 0)
back(explode ? explode_distance/2 : 0)
render_if_rendering()
top_leg();
}
zrot(360/strut_count-1.5)
down(10)
yrot(90)
zrot(-90)
left(77.5)
fwd(140*2)
linear_extrude(height = ball_radius+5)
import("mouth.svg");
}
} else if (part=="top_leg") {
xrot(90)
render_if_rendering()
top_leg();
} else if (part=="top_ring") {
xrot(180)
top_ring();
} else if (part=="mid_ring_segment") {
mid_ring_segment();
} else if (part=="bottom_leg") {
bottom_leg();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment