Created
July 23, 2023 15:18
-
-
Save pyrho/6617719f4a8401f3086e003576d7fe34 to your computer and use it in GitHub Desktop.
Tiny modification to https://www.printables.com/model/453323-customizable-bike-bottle-holder
This file contains hidden or 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
| $fn= $preview ? 16:32; | |
| // bottle | |
| bottleD=73-10; | |
| bottleHullTol=0.2; // render tolerance | |
| // bike frame | |
| frameD=35+.5; | |
| framePadD=11+.5; // diameter of pads around frame holes | |
| framePadH=0; // 0 for flat back | |
| boltZOffset=-15; | |
| // bolts | |
| bolt=5+.5; | |
| boltPad=2; | |
| boltHead=8.5+.5; | |
| boltHeadL=5+.5; | |
| boltSpan=64; | |
| // main bar | |
| mainBarShiftZ=0; | |
| mainBarAroundFrame=0; // extra thickness around frame | |
| mainBar=[framePadH+boltPad+boltHeadL,20,142]; // basic dimensions | |
| mainBarExtraX=1; // extra thickness for curved shape | |
| stopper=25; // size of foot | |
| stopperF=10; | |
| lockH=5; // size of top lock | |
| lockR=3; | |
| lockPos=140; // distance from the foot to the center of the lock | |
| // flexible hand holding the bottle | |
| handH=140+5; // total height of the hand | |
| handH2=25; // extra height at tips | |
| handAngle=150; | |
| handZShift=mainBarShiftZ; | |
| fingerW=3; // thickness of fingers | |
| fingerH=15; // width of fingers | |
| renderSteps=20; // render precision of the hand | |
| wall=2; | |
| // fillets | |
| f=2; | |
| f3=5; | |
| inf=500; | |
| not=0.001; | |
| ///////////////////////////////////////////// | |
| d(){ | |
| u(){ | |
| // main bar | |
| d(){ | |
| t([-mainBarAroundFrame,0,mainBarShiftZ]) cubeRounded(mainBar+[mainBarExtraX+mainBarAroundFrame,0,0],center=[0,1,1],r=[f3,f,f],r02=[wall/2,wall/2,f3],r13=[wall/2,wall/2,f],r46=[f3,f,f3]); | |
| t([bottleD/2+mainBar.x,0,0]) bottle(); | |
| } | |
| t([0,0,mainBarShiftZ]) t([0,0,-mainBar.z/2]){ | |
| //stopper | |
| cubeRounded([stopper,mainBar.y,wall],center=[0,1,0],r=[wall/2,wall/2,f3],r13=[wall/2,wall/2,stopperF],r57=[wall/2,wall/2,stopperF]); | |
| // lock | |
| t([0,0,lockPos]) lock(); | |
| } | |
| //hand | |
| tr([bottleD/2+mainBar.x,0,handZShift],[0,-90,0]) { | |
| for(b=[0,1]) mirror([0,b,0]) hand(); | |
| } | |
| } | |
| frame(); | |
| } | |
| ///////////////////////////////////////////// | |
| module lock(){ | |
| if (lockH>0) hull(){ | |
| t([mainBar.x/2,0,-lockH]) cubeRounded([not,mainBar.y-1,not],center=[0,1,1]); | |
| for(s=[-1,1]) t([mainBar.x-lockR+lockH,s*mainBar.y/4,0]) sphere(r=lockR); | |
| } | |
| } | |
| module hand(){ | |
| step=1/renderSteps; | |
| extraD=bottleD/2+bottleHullTol; | |
| fingerCylinderCut=.1; | |
| i(){ | |
| d(){ | |
| u(){ | |
| // fingers | |
| for(p=[0:step:1-step]) for(s=[1,-1]) { | |
| hull() | |
| for(p2=[0,step]){ | |
| p3=p+p2; | |
| tr([(1-p3)*s*(handH/2-fingerH/2)+s*p3*handH2/2,0,0],[p3*handAngle,0,0]) t([0,0,extraD]) i() { | |
| cylinderRounded(d=[0,fingerH],h=fingerW,r=[0,fingerW/2,0,fingerW/2],chamfer=30); | |
| cubeRounded([inf,fingerCylinderCut,inf],center=[1,1,1]); | |
| } | |
| } | |
| } | |
| // endpoints | |
| for(s=[1,-1]){ | |
| p3=1; | |
| tr([(1-p3)*s*(handH/2-fingerH/2)+s*p3*handH2/2,0,0],[p3*handAngle,0,0]) t([0,0,extraD]) i(){ | |
| cylinderRounded(d=[0,fingerH],h=fingerW,r=[0,fingerW/2,0,fingerW/2],chamfer=30); | |
| cubeRounded([inf,inf,fingerW],center=[1,2,0]); | |
| } | |
| } | |
| // mid connection | |
| hull() for(s=[1,-1]){ | |
| p3=1; | |
| tr([(1-p3)*s*(handH/2-fingerH/2)+s*p3*handH2/2,0,0],[p3*handAngle,0,0]) t([0,0,extraD]) i(){ | |
| cylinderRounded(d=[0,fingerH],h=fingerW,r=[0,fingerW/2,0,fingerW/2],chamfer=30); | |
| cubeRounded([inf,inf,fingerW],center=[1,2,0],r=[fingerW/2,fingerW/2,fingerW/2]); | |
| } | |
| } | |
| } | |
| r([0,90,0]) bottle(); | |
| cubeRounded([inf,mainBar.y-f3,inf]+[mainBarExtraX,0,0],center=[1,1,0]); | |
| } | |
| // outer cylinder | |
| //r([0,90,0]) cylinder(d=bottleD+2*fingerW,h=inf, center=true,$fn=2*$fn); | |
| } | |
| } | |
| module frame(){ | |
| t([-frameD/2,0,0]) cylinder(d=frameD,h=inf,center=true,$fn=2*$fn); | |
| t([0, 0, boltZOffset]) | |
| for(z=[0.5,-0.5]) t([0,0,(z*boltSpan)]){ | |
| t([framePadH,0,0]) r([0,-90,0]) cylinder(d=framePadD,h=inf); | |
| t([framePadH,0,0]) r([0,90,0]) bolt(bolt=bolt,boltHead=boltHead,boltHeadL=inf,boltPad=boltPad,nut=0); | |
| } | |
| } | |
| module bottle(){ | |
| cylinder(d=bottleD,h=inf, center=true,$fn=2*$fn); | |
| } | |
| ///////////////////////////////////////////// | |
| ///////////////////////////////////////////// | |
| ///////////////////////////////////////////// | |
| module cubeRounded( | |
| size=[3,3,3], | |
| r=[0,0,0], | |
| r0=[-1,-1,-1], | |
| r1=[-1,-1,-1], | |
| r2=[-1,-1,-1], | |
| r3=[-1,-1,-1], | |
| r4=[-1,-1,-1], | |
| r5=[-1,-1,-1], | |
| r6=[-1,-1,-1], | |
| r7=[-1,-1,-1], | |
| r0123=[-1,-1,-1], | |
| r4567=[-1,-1,-1], | |
| r01=[-1,-1,-1], | |
| r02=[-1,-1,-1], | |
| r13=[-1,-1,-1], | |
| r23=[-1,-1,-1], | |
| r45=[-1,-1,-1], | |
| r46=[-1,-1,-1], | |
| r57=[-1,-1,-1], | |
| r67=[-1,-1,-1], | |
| chamfer=[0,0,0,0], | |
| chamferAngle=60, | |
| center=[0,0,0], | |
| not=0.0001 | |
| ){ | |
| function max3(v)=max(v.x,max(v.y,v.z)); | |
| function sat3(a) = [max(not,a.x),max(not,a.y),max(not,a.z)]; | |
| function chg(a, b) = (a.x==-1 && a.y==-1 && a.z==-1) ? b : a; | |
| module corner(r=[0.5,1,3],$fn=$fn){ | |
| not=0.0001; | |
| step= $fn<1 ? 4/8 : 4/$fn; | |
| tr([r.z,r.z,0],180) | |
| for(i=[0:step:1-step]){ | |
| r(i*90) //hull() | |
| { | |
| mix1=(1-i)*r.y+i*r.x; | |
| r([90,0,0]) linear_extrude(not) t([r.z-mix1,mix1,0]) intersection(){ | |
| circle(r=mix1); | |
| mirror([0,1,0]) mirror([0,0,1]) square([mix1,mix1]); | |
| } | |
| i1=i+step; | |
| mix2=(1-i1)*r.y+i1*r.x; | |
| r([90,0,step*90]) linear_extrude(not) t([r.z-mix2,mix2,0]) intersection(){ | |
| circle(r=mix2); | |
| mirror([0,1,0]) mirror([0,0,1]) square([mix1,mix1]); | |
| } | |
| } | |
| } | |
| } | |
| module rotatedCorner(r=[0.5,1,3]){ | |
| if(r.x==max3(r)){ | |
| mirror([1,0,0]) r([0,-90,0]) corner([r.z,r.y,r.x]); | |
| } else if(r.y==max3(r)){ | |
| mirror([0,1,0]) r([90,0,0]) corner([r.x,r.z,r.y]); | |
| } else { | |
| corner(r); | |
| } | |
| } | |
| module halfTriangle3D(angle=45,h=10,z=10){ | |
| linear_extrude(z) polygon([[0,0],[h*tan(angle),0],[0,h]]); | |
| } | |
| _r0 = sat3(chg(r0,chg(r01,chg(r02,chg(r0123,r))))); | |
| _r1 = sat3(chg(r1,chg(r01,chg(r13,chg(r0123,r))))); | |
| _r2 = sat3(chg(r2,chg(r23,chg(r02,chg(r0123,r))))); | |
| _r3 = sat3(chg(r3,chg(r23,chg(r13,chg(r0123,r))))); | |
| _r4 = sat3(chg(r4,chg(r45,chg(r46,chg(r4567,r))))); | |
| _r5 = sat3(chg(r5,chg(r45,chg(r57,chg(r4567,r))))); | |
| _r6 = sat3(chg(r6,chg(r67,chg(r46,chg(r4567,r))))); | |
| _r7 = sat3(chg(r7,chg(r67,chg(r57,chg(r4567,r))))); | |
| module cubeR(){ | |
| hull() | |
| { | |
| rotatedCorner(_r0); | |
| t([size.x,0,0]) mirror([1,0,0]) rotatedCorner(_r1); | |
| t([0,size.y,0]) mirror([0,1,0]) rotatedCorner(_r2); | |
| t([size.x,size.y,0]) mirror([0,1,0]) mirror([1,0,0]) rotatedCorner(_r3); | |
| t([0,0,size.z]) mirror([0,0,1]) rotatedCorner(_r4); | |
| t([size.x,0,size.z]) mirror([0,0,1]) mirror([1,0,0]) rotatedCorner(_r5); | |
| t([0,size.y,size.z]) mirror([0,0,1]) mirror([0,1,0]) rotatedCorner(_r6); | |
| t([size.x,size.y,size.z]) mirror([0,0,1]) mirror([0,1,0]) mirror([1,0,0]) rotatedCorner(_r7); | |
| } | |
| //chamfering | |
| if(chamfer[0]) r([0,90,0]) halfTriangle3D(90-chamferAngle,size.y/(chamfer[2]+1),size.x); | |
| if(chamfer[2]) tr([0,size.y,0],[0,90,0]) mirror([0,1,0]) halfTriangle3D(90-chamferAngle,size.y/(chamfer[0]+1),size.x); | |
| if(chamfer[1]) tr([0,size.y,0],[90,90,0]) halfTriangle3D(90-chamferAngle,size.x/(chamfer[3]+1),size.y); | |
| if(chamfer[3]) tr([size.x,size.y,0],[90,90,0]) mirror([0,1,0]) halfTriangle3D(90-chamferAngle,size.x/(chamfer[1]+1),size.y); | |
| } | |
| t([-size.x/2*center.x,-size.y/2*center.y,-size.z/2*center.z]) cubeR(); | |
| } | |
| module bolt(bolt=3, boltHead=6, boltPad=3, boltHeadL=10, boltL=30, nut=6.3, nutPad=5, nutL=4, nutR=0, sideCutL=20, sideCutSlot=4, layer1=0, layer2=0, tol=0, not=0.001){ | |
| bottom=layer1>0?true:false; | |
| top=layer2>0?true:false; | |
| t([0,0,-boltL+not+boltPad]) cylinder(d=bolt+tol,h=boltL); | |
| t([0,0,boltPad-2*layer1]) difference(){ | |
| cylinder(d=boltHead+tol,h=boltHeadL+2*layer1); | |
| //easy print bolt | |
| if(layer1>0){ | |
| t([(bolt+tol)/2,-(boltHead+tol)/2,-not]) cube([(boltHead-bolt)/2,boltHead+tol,2*layer1+not]); | |
| t([-(boltHead+tol)/2,-(boltHead+tol)/2,-not]) cube([(boltHead-bolt)/2,boltHead+tol,2*layer1+not]); | |
| t([-(boltHead+tol)/2,-(boltHead+tol)/2,-not]) cube([boltHead+tol,(boltHead-bolt)/2,layer1+not]); | |
| t([-(boltHead+tol)/2,(bolt+tol)/2,-not]) cube([boltHead+tol,(boltHead-bolt)/2,layer1+not]); | |
| } | |
| } | |
| //nut | |
| if(nut>0 && nutL>0){ | |
| rotate([0,0,nutR]) difference(){ | |
| t([0,0,-nutPad-nutL-sideCutSlot-2*layer1]){ | |
| cylinder(d=nut+tol,h=nutL+sideCutSlot+2*layer1+2*layer2,$fn=6); | |
| hull(){ | |
| for(x=[0,sideCutL]) t([x,0,0]) cylinder(d=nut+tol,h=nutL+2*layer1,$fn=6); | |
| } | |
| } | |
| //easy print nut slot | |
| if(layer1>0){ | |
| t([(bolt+tol)/2,-nut/2,-nutPad-nutL-sideCutSlot-2*layer1-not]) cube([sideCutL+nut+tol,nut,2*layer1+not]); | |
| t([-(bolt+tol)/2-nut,-nut/2,-nutPad-nutL-sideCutSlot-2*layer1-not]) cube([nut,nut,2*layer1+not]); | |
| t([-nut/2,-(bolt+tol)/2-nut,-nutPad-nutL-sideCutSlot-2*layer1-not]) cube([nut,nut,layer1+not]); | |
| t([-nut/2,+(bolt+tol)/2,-nutPad-nutL-sideCutSlot-2*layer1-not]) cube([nut,nut,layer1+not]); | |
| } | |
| //easy print nut | |
| if(layer2>0){ | |
| t([(bolt+tol)/2,-nut/2,-nutPad]) cube([nut,nut,2*layer2+not]); | |
| t([-(bolt+tol)/2-nut,-nut/2,-nutPad]) cube([nut,nut,2*layer2+not]); | |
| t([-nut/2,-(bolt+tol)/2-nut,-nutPad+layer2]) cube([nut,nut,layer2+not]); | |
| t([-nut/2,+(bolt+tol)/2,-nutPad+layer2]) cube([nut,nut,layer2+not]); | |
| } | |
| } | |
| } | |
| } | |
| module cylinderRounded(d=[20,40],h=30,center=false,r=[0,0,0,0],chamfer=0.001, ellipse=[1,1]){ | |
| t([0,0,-h/2* (center?1:0)]) scale([ellipse.y,ellipse.x,1]) | |
| rotate_extrude(convexity = 10) | |
| { | |
| //square | |
| difference(){ | |
| t([d[0]/2,0,0]) square([(d[1]-d[0])/2,h]); | |
| if(r[0]>0) t([d[0]/2,0,0]) square([r[0],r[0]]); | |
| if(r[1]>0) t([d[1]/2-r[1],0,0]) square([r[1],r[1]]); | |
| if(r[2]>0) t([d[0]/2,h-r[2],0]) square([r[2],r[2]]); | |
| if(r[3]>0) t([d[1]/2-r[3],h-r[3],0]) square([r[3],r[3]]); | |
| } | |
| //corners | |
| if(r[0]>0){ | |
| intersection(){ | |
| t([d[0]/2+r[0], r[0], 0]) circle(r = r[0]); | |
| t([d[0]/2,0,0]) square([r[0],r[0]]); | |
| } | |
| polygon([[d[0]/2+r[0],0],[d[0]/2+r[0]-r[0]*cos(90-chamfer),r[0]-r[0]*sin(90-chamfer)],[d[0]/2+r[0]-r[0]*cos(90-chamfer)+tan(90-chamfer)*(r[0]-r[0]*sin(90-chamfer)),0]]); | |
| } else { | |
| difference(){ | |
| t([d[0]/2+r[0], 0, 0]) square([-r[0],-r[0]]); | |
| t([d[0]/2+r[0], -r[0], 0]) circle(r = -r[0]); | |
| } | |
| } | |
| if(r[1]>0){ | |
| intersection(){ | |
| t([d[1]/2-r[1], r[1], 0]) circle(r = r[1]); | |
| t([d[1]/2-r[1],0,0]) square([r[1],r[1]]); | |
| } | |
| polygon([[d[1]/2-r[1],0],[d[1]/2-r[1]+r[1]*cos(90-chamfer),r[1]-r[1]*sin(90-chamfer)],[d[1]/2-r[1]+r[1]*cos(90-chamfer)-tan(90-chamfer)*(r[1]-r[1]*sin(90-chamfer)),0]]); | |
| } else { | |
| difference(){ | |
| t([d[1]/2, 0, 0]) square([-r[1],-r[1]]); | |
| t([d[1]/2-r[1], -r[1], 0]) circle(r = -r[1]); | |
| } | |
| } | |
| if(r[2]>0){ | |
| intersection(){ | |
| t([d[0]/2+r[2], h-r[2], 0]) circle(r = r[2]); | |
| t([d[0]/2,h-r[2],0]) square([r[2],r[2]]); | |
| } | |
| } else { | |
| difference(){ | |
| t([d[0]/2+r[2], h+r[2], 0]) square([-r[2],-r[2]]); | |
| t([d[0]/2+r[2], h+r[2], 0]) circle(r = -r[2]); | |
| } | |
| } | |
| if(r[3]>0){ | |
| intersection(){ | |
| t([d[1]/2-r[3], h-r[3], 0]) circle(r = r[3]); | |
| t([d[1]/2-r[3],h-r[3],0]) square([r[3],r[3]]); | |
| } | |
| } else { | |
| difference(){ | |
| t([d[1]/2, h+r[3], 0]) square([-r[3],-r[3]]); | |
| t([d[1]/2-r[3], h+r[3], 0]) circle(r = -r[3]); | |
| } | |
| } | |
| } | |
| } | |
| module t(v=[0,0,0]){translate(v) children();} | |
| module r(a=[0,0,0],rp=[0,0,0]){translate(rp) rotate(a) translate(-rp) children();} | |
| module tr(v=[0,0,0],a=[0,0,0],rp=[0,0,0]){t(v) r(a,rp) children();} | |
| module rt(a=[0,0,0],rp=[0,0,0],v=[0,0,0]){r(a,rp) t(v) children();} | |
| module u(){union() children();} | |
| module d(){if($children<=1) children(); if($children>1) difference(){children(0); children([1:$children-1]);}} | |
| module i(){if($children<=1) children(); else intersection_for(i=[0:$children-1]) children(i);} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment