Created
January 30, 2023 16:45
-
-
Save widget-/2267cd6281c7870e7a6a22f74413ad89 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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