Uses Polyround from https://github.com/Irev-Dev/Round-Anything
Ran out of time before all details where done.
cover=polyRound([[0,0,0],[7,0,2],[7,5,0],[0,5,0]],8);
finext=polyRound([[0,5,0],[7,5.01,0.5],[7,11.8,0.5],
[6,11.8,0.2],[6,12,0],[0,12,0]],8);
case=polyRound([[0,0,0.01],[6,0.01,0.7],[6,12,0.1],
[5.9,12.8,0],[5.5,13.5,0.1],
[3.5,13.5,0.05],[3.5,13,0.05],[2.5,13,.05],
[2.5,14,0.05],[0,14,0] ],1);
rotate( 90,[0,1,0]){
color("darkred")translate([0,0,-0.1])
rotate_extrude($fn=45)polygon (cover);
color("lightgreen")
intersection(){
rotate_extrude($fn=45)polygon (finext);
translate([0,0,1])linear_extrude(13,convexity=27)
offset(-0.2,$fn=8)offset(0.3,$fn=8)offset(-0.1,$fn=8)
union()
{
circle(5.95,$fn=30);
rotate( 90 ){
translate ([0,0,0])square([0.3,14,],center=true);
translate ([1.5*1,0,0])square([0.3,13.6,],center=true);
translate ([1.5*2,0,0])square([0.3,12.5,],center=true);
translate ([1.5*-1,0,0])square([0.3,13.6,],center=true);
translate ([1.5*-2,0,0])square([0.3,12.5,],center=true);
}
rotate( 0 ){
translate ([0,0,0])square([0.3,14,],center=true);
translate ([1.5*1,0,0])square([0.3,13.6,],center=true);
translate ([1.5*2,0,0])square([0.3,12.5,],center=true);
translate ([1.5*-1,0,0])square([0.3,13.6,],center=true);
translate ([1.5*-2,0,0])square([0.3,12.5,],center=true);
}
}
}
color("lightgreen")rotate_extrude($fn=45)polygon (case);
color("grey")cylinder(18,0.8,0.8,$fn=20);
color("lightgreen")rotate(0)translate([0,0,13])
cube([7,0.5,1],center=true);
color("lightgreen")rotate(60)translate([0,0,13])
cube([7,0.5,1],center=true);
color("lightgreen")rotate(120)translate([0,0,13])
cube([7,0.5,1],center=true);
color("lightgreen")translate([0,0,11.3])
linear_extrude(1,convexity=27)
offset(-0.2,$fn=8)offset(0.3,$fn=8)offset(-0.1,$fn=8)
union()
{
circle(5.95,$fn=30);
color("lightgreen")rotate(45) square([14.5,1.5 ],center=true);
color("lightgreen")rotate(90+45) square([14.5,1.5 ],center=true);
}
color("lightgreen")translate([0,0,5])
linear_extrude(7.3,convexity=27)
offset(0.2,$fn=8)offset(-0.4,$fn=8)
union()
{
circle(5.95,$fn=30);
color("lightgreen")rotate(45) square([14.5,1.5 ],center=true);
color("lightgreen")rotate(90+45) square([14.5,1.5 ],center=true);
}
color("lightgreen")rotate(90+45)translate([6.5,0,11.8])
cylinder(1,0.6,0.6, $fn=6);
color("lightgreen")rotate(90*2+45)translate([6.5,0,11.8])
cylinder(1,0.6,0.6, $fn=6);
color("lightgreen")rotate(90*3+45)translate([6.5,0,11.8])
cylinder(1,0.6,0.6, $fn=6);
color("lightgreen")rotate(90*4+45)translate([6.5,0,11.8])
cylinder(1,0.6,0.6, $fn=6);
}
intersection()
{
translate([0,0,-10]) linear_extrude(15,convexity=27)
difference(){offset(-0.5,$fn=16)offset(1,$fn=8)offset(-0.5,$fn=16)
union(){
translate([8,6])
offset(-0.5,$fn=16)offset(1,$fn=8)offset(-0.5,$fn=16)
square([6,5],center=true);
translate([8,-6])
offset(-0.5,$fn=16)offset(1,$fn=8)offset(-0.5,$fn=16)
square([6,5],center=true);
translate([8,0]) square([3,8],center=true);
}
translate([9.5,5.3]) circle(0.6,$fn=16);
translate([6.5,5.3]) circle(0.6,$fn=16);
translate([9.5,-5.3]) circle(0.6,$fn=16);
translate([6.5,-5.3]) circle(0.6,$fn=16);
}
rotate( 90,[0,1,0]){
color("lightgreen")translate([0,0,5])linear_extrude(6.3,convexity=27)
difference(){
offset(-0.5,$fn=16)offset(1,$fn=8)offset(-0.5,$fn=16)union()
{
circle(5.95,$fn=30);
translate([6,0]) square([5,15],center=true);
}
offset(0.9,$fn=16)offset(-1.5,$fn=16)color("lightgreen") translate([6,0]) square([5,15],center=true);
}
}}
function polyRound(radiipoints,fn=5)=
// reworte most of it all here heavily use of wrap function
let(p=getpoints(radiipoints))
let(r=getradii(radiipoints))
let(Lp1=last(p),Lp=Lp1+1)
let(temp=[for(i=[0:last(p)])
round3points(
p[wrap(i-1,Lp,0)],
p[wrap(i ,Lp,0)],
p[wrap(i+1,Lp,0)],
r[wrap(i,Lp,0)],
fn)
]
)
//common trick to flatten a list of list
[for (a = temp)
for (b = a) b];
function a3DpolyRound(radiipoints,fn=5)=
// reworte most of it all here heavily use of wrap function
let(p=get3points(radiipoints))
let(r=get3radii(radiipoints))
let(Lp1=last(p),Lp=Lp1+1)
let(
temp=[for(i=[0:last(p)])
a3Dround3points(
p[wrap(i-1,Lp,0)],
p[wrap(i ,Lp,0)],
p[wrap(i+1,Lp,0)],
r[wrap(i,Lp,0)],
fn)])
//common trick to flatten a list of list
[for (a = temp)
for (b = a) b];
function angle (a,b)= (atan2(norm(cross(a,b)),a*b));
function a3Dround3points(p1,p2,p3,r,fn)=
let(
p12=p1-p2,
p32=p3-p2,
m12=norm(p12),
m32=norm(p32),
angle123= ( angle( (p12), (p32))),
a=[m12,0],
b=[0,0],
c=[sin(angle123)*m32,cos(angle123)*m32],
temp= round3points(a,b,c,r,fn)
,e=echo(a,c,angle123,r)
)
[
for (l = temp)
p2
+ (l.x * c.y + l.y * -c.x )*(1/(a.x*c.y-c.x*a.y)) * (p12)
+ (l.x * -a.y + l.y * a.x )*(1/(a.x*c.y-c.x*a.y)) * (p32)
]
;
function rot(p,a)=[
p.x*cos(a)-p.y*sin(a),
p.x*sin(a)+p.y*cos(a),0];
function round3points(p1,p2,p3,r,fn)=
// move check to top, single point reurn in case of collinear
dot(un(p1-p2),(p2-p3))>0.98||r==0?[ p2 ]
:
let(ang= (cosineRuleAngle(p1,p2,p3)) )//angle between the lines
// constrained tangD to the shortest leg p1-p2, or p2-p3
let(tangD=min(norm(p1-p2)/2 ,norm(p2-p3)/2, r/tan(ang/2)))
//distance to the tangent point from p2
let(circD=r/sin(ang/2))//distance to the circle centre from p2
let(a12=abs(atan(getGradient(p1,p2))))//angle of line 1
let(a23=abs(atan(getGradient(p2,p3))))//angle of line 2
let(vec21=p1-p2)//vector from p2 to p1
let(vec23=p3-p2)//vector from p2 to p3
let(dir21x=vec21[0]==0?0:vec21[0]/abs(vec21[0]))
//tangent along line p2 to p1 x polerisation. Returns 1,-1 or 0
let(dir21y=vec21[1]==0?0:vec21[1]/abs(vec21[1]))
//tangent along line p2 to p1 y polerisation. Returns 1,-1 or 0
let(dir23x=vec23[0]==0?0:vec23[0]/abs(vec23[0]))
//tangent along line p3 to p1 x polerisation. Returns 1,-1 or 0
let(dir23y=vec23[1]==0?0:vec23[1]/abs(vec23[1]))
//tangent along line p3 to p1 Y polerisation. Returns 1,-1 or 0
let(t12=[p2[0]+dir21x*cos(a12)*tangD,p2[1]+dir21y*sin(a12)*tangD])//tangent point along line p2 to p2 by offseting from p2
let(t23=[p2[0]+dir23x*cos(a23)*tangD,p2[1]+dir23y*sin(a23)*tangD])//tangent point along line p2 to p3 by offseting from p2
let(vec_=getMidpoint(t12,t23)-p2)//vector from P1 to the midpoint of the two tangents
let(dirx_=vec_[0]==0?0:vec_[0]/abs(vec_[0]))//circle center point x polerisation
let(diry_=vec_[1]==0?0:vec_[1]/abs(vec_[1]))//circle center point y polerisation
let(a_=abs(atan(getGradient(getMidpoint(t12,t23),p2))))//angle of line from tangent midpoints to p2
let(cen=[p2[0]+dirx_*cos(a_)*circD,p2[1]+diry_*sin(a_)*circD])//circle center by offseting from p2
let(e1=(p2[0]-p1[0])*(p2[1]+p1[1]))//edge 1
let(e2=(p3[0]-p2[0])*(p3[1]+p2[1]))//edge 2
let(e3=(p1[0]-p3[0])*(p1[1]+p3[1]))//edge 3
let(CWorCCW=(e1+e2+e3)/abs(e1+e2+e3))//rotation of the three points cw or ccw?
CentreN2PointsArc(t12,t23,cen,CWorCCW,fn);
function CentreN2PointsArc(p1,p2,cen,CWorCCW,fn)=
let(r=pointDist(p1,cen))
let(CircA1=invtan(p1[0]-cen[0],p1[1]-cen[1]))//angle of line 1
let(CircA2=cosineRuleAngle(p2,cen,p1))//angle between the lines
[for(i=[0:fn]) [cos(CircA1+(CircA2/fn)*-i*CWorCCW)*r+cen[0],sin(CircA1+(CircA2/fn)*-i*CWorCCW)*r+cen[1]]];
function invtan(run,rise)=
let(a=abs(atan(rise/run)))
rise==0&&run>0?0:rise>0&&run>0?a:rise>0&&run==0?90:rise>0&&run<0?180-a:rise==0&&run<0?180:rise<0&&run<0?a+180:rise<0&&run==0?270:rise<0&&run>0?360-a:"error";
function cosineRuleAngle(p1,p2,p3)=
let(p12=abs(pointDist(p1,p2)))
let(p13=abs(pointDist(p1,p3)))
let(p23=abs(pointDist(p2,p3)))
acos((sq(p23)+sq(p12)-sq(p13))/(2*p23*p12));
function getIntersect(m1,m2,k1,k2)=
let(x=(k2-k1)/(m1-m2))
let(y=m1*x+k1)
[x,y];
function sq(x)=x*x;
function getGradient(p1,p2)=(p2[1]-p1[1])/(p2[0]-p1[0]);
function getConstant(p,m)=p[1]-m*p[0];
function getMidpoint(p1,p2)=[(p1[0]+p2[0])/2,(p1[1]+p2[1])/2];
function pointDist(p1,p2)=
sqrt(abs(sq(p1[0]-p2[0])+sq(p1[1]-p2[1])));
function zipxyr(a,b)=[for(i=[0:last(a)])[a[i].x,a[i].y,b[i]]];
function getpoints(p)=
[for(i=[0:len(p)-1])[p[i].x,p[i].y ]];
// gets [x,y]list of[x,y,r]list
function getradii(p)=
[for(i=[0:len(p)-1])p[i][2]]; // gets [r]list of[x,y,r]list
function get3points(p)=
[for(i=[0:len(p)-1])[p[i].x,p[i].y,p[i].z]];
// gets [x,y,z]list of[x,y,z,r]list
function get3radii(p)=
[for(i=[0:len(p)-1])p[i][3]]; // gets [r]list of[x,y,r]list
function wrap(x,x_max=1,x_min=0) = (((x - x_min) % (x_max - x_min)) + (x_max - x_min)) % (x_max - x_min) + x_min; // wraps numbers inside boundaries
function dot (a,b)=a*b; // dotproduct is implied in * of vextoes
function last(i)=len(i)-1;// shorthand sugar for len(i)-1
function un(v)=v/max(norm(v),1e-16);// div by zero safe unit normal