Last active
September 25, 2018 02:54
-
-
Save thehans/39435a8c3d7ce98a0bd226b6189ea5a8 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
// Created in 2018 by Ryan A. Colyer. | |
// This work is released with CC0 into the public domain. | |
// https://creativecommons.org/publicdomain/zero/1.0/ | |
include <plot_function.scad> // https://www.thingiverse.com/thing:2391851 | |
finger_spacing = 21; | |
oblong_factor = 1.8; | |
ripple_sharpness = 0.6; // range [0:1] | |
grip_width = 20; | |
grip_start = -1; | |
grip_end = 3; | |
tilt_frac = 0.2; | |
square_size = 10; | |
plot_zstep = 0.6; | |
plot_asteps = 180; | |
barrelOD = 21.55; | |
barrelSurroundTh = 3; | |
barrelOffset = 3; // vertical gap added for extra space to transition between grip and barrel surround | |
transition_angle = 60; // angle at which transition meets barrel cylinder (90 max to meet at side, less to meet below that) | |
transitionXScale = 1.5; // scale cylinder cross section along X for transition to match better | |
clearance_tight = 0.2; | |
$fs=plot_zstep; | |
$fa=0.2; | |
// calculated values | |
a = finger_spacing / (2*PI); | |
b = a*ripple_sharpness; // scale b based on a, closer to 1 is sharper, closer to 0 is flatter | |
plot_height = 4*finger_spacing + grip_start + grip_end; | |
// transition to barrel surround | |
d_cyl = barrelOD+barrelSurroundTh*2; | |
h_cyl = 39; | |
r_cyl = d_cyl / 2; | |
h_transition = r_cyl - r_cyl * cos(transition_angle) + barrelOffset; | |
x_transition = h_cyl / 2; | |
y_transition = r_cyl * sin(transition_angle); | |
y1_transition = r_cyl * sin(transition_angle-0.1); | |
h1_transition = r_cyl - r_cyl * cos(transition_angle-0.1) + barrelOffset; | |
h_step = h_transition / round(h_transition / plot_zstep); | |
ripple_points = MakeAxialPoints(1, [0, plot_zstep, plot_height], plot_asteps); | |
square_points = MakeAxialPoints(3, [0, plot_zstep, plot_height], plot_asteps); | |
grip_points = SmoothXY(square_points, 15); | |
vertical_grip = SubtractXY(ripple_points, StretchX(grip_points, oblong_factor)); | |
plot_points = TiltX(vertical_grip, -tilt_frac); | |
extrap_grip = MakeExtrapolatedPoints(plot_points[1], plot_points[0], [-h_transition, h_step, 0]); | |
// calculate tangent at transitionplot_z | |
cyl_points0 = ScaleLayerXY(MakeAxialLayer(3, -h_transition, plot_asteps), [transitionXScale*-x_transition/square_size,-y_transition/square_size]); | |
cyl_points1 = ScaleLayerXY(MakeAxialLayer(3, -h1_transition, plot_asteps), [transitionXScale*-x_transition/square_size,-y1_transition/square_size]); | |
extrap_barrel = MakeExtrapolatedPoints(cyl_points0, cyl_points1, [-h_transition, h_step, 0]); | |
blend_points = BlendPoints(extrap_barrel, extrap_grip); | |
function BlendPoints(arr1, arr2) = | |
let(l1 = len(arr1) - 1) | |
[ for(i = [0:1:l1]) let(t = smoother_step(i/l1), a1 = arr1[i], a2 = arr2[i], lj = len(a1)-1) | |
[for (j = [0:1:lj]) (1-t)*a1[j] + t * a2[j]] | |
]; | |
//ScaleXY(square_points); | |
//PlotClosePoints(ripple_points); | |
//PlotClosePoints(grip_points); | |
PlotClosePoints(plot_points); | |
//PlotClosePoints(extrap_grip); | |
//PlotClosePoints(extrap_barrel); | |
// transition between grip and barrel | |
difference() { | |
union() { | |
intersection() { // limit the X ends of extended transition | |
err = 0.001; | |
PlotClosePoints(blend_points); | |
translate([0,0,-d_cyl/2-barrelOffset/2-err]) | |
cube([h_cyl,d_cyl+err,d_cyl+barrelOffset+2*err], center=true); | |
} | |
translate([0,0,-d_cyl/2-barrelOffset]) rotate([0,90,0]) | |
cylinder(d=d_cyl, h=h_cyl, center=true); | |
} | |
translate([0,0,-d_cyl/2-barrelOffset]) rotate([0,90,0]) | |
cylinder(d=barrelOD+clearance_tight, h=h_cyl+2, center=true); | |
} | |
function smoother_step(x) = 6*pow(x,5)-15*pow(x,4)+10*pow(x,3); | |
function AxialFunc1(z, ang) = let( | |
angsc = 1-abs(ang/90 - 2), | |
on = angsc > 0 ? smoother_step(angsc) : 0, | |
zgrip = z - grip_start, | |
ripple = on * | |
ParametricSolver(zgrip)[1] | |
) | |
ripple; | |
//function AxialFunc2(z, ang) = ExtrapolateZgrip_width/2; | |
//!polygon( [for(x=[0:0.5:90]) ParametricSolver(x) ]); | |
function AxialFunc3(z, ang) = let( | |
loop_ang = (ang+45)%90 - 45 | |
) | |
square_size / cos(loop_ang); | |
// curtate cycloid (for b < a) | |
function ParametricFunc(t) = | |
let(r = a-b) | |
// (a - b*cos(t*180/PI) // default cycloid | |
// (a - b*cos(t*180/PI) - (a-b) // zero out the bottom, simplified below | |
[(a*t-b*sin(t*180/PI)), (b - b*cos(t*180/PI))]; | |
function ParametricSolver(x, t0=0, dt=0.1, err=0.001) = | |
let( | |
t1 = t0 + dt, | |
x0 = ParametricFunc(t0)[0], | |
x1 = ParametricFunc(t1)[0], | |
dx = x1 - x0, | |
m = dt/dx, | |
xerr1 = x1 - x, | |
dt1 = -m * xerr1 | |
) | |
abs(xerr1) < err ? ParametricFunc(t1) : ParametricSolver(x, t1, dt1, err); | |
function MakeAxialLayer(AxialFuncN, z, num_circle_steps=360, minplot=0.0001) = | |
let( | |
ang_step = 360 / num_circle_steps | |
) | |
[for (ai = [0:num_circle_steps-1]) let( | |
a = ai * ang_step, | |
r = CallAxialFunc(z, a, AxialFuncN), | |
rchecked = r < minplot ? minplot : r | |
) | |
[rchecked * cos(a), rchecked * sin(a), z] | |
]; | |
function MakeAxialPoints(AxialFuncN, minz_stepz_maxz, num_circle_steps=360) = | |
let( | |
minz = minz_stepz_maxz[0], | |
stepz = minz_stepz_maxz[1], | |
maxz = minz_stepz_maxz[2] + 0.001*stepz, | |
minplot = 0.001*stepz | |
) | |
[ | |
for (z = [minz:stepz:maxz]) | |
MakeAxialLayer(AxialFuncN, z, num_circle_steps, minplot) | |
]; | |
function ExtrapolateZ(arr1, arr2, l, z) = | |
[for (i = [0:1:l-1]) let(p = arr2[i], dp = p-arr1[i]) (z-p.z)/dp.z * dp + [p.x,p.y,p.z]]; | |
function MakeExtrapolatedPoints(arr1, arr2, minz_stepz_maxz) = | |
let( | |
minz = minz_stepz_maxz[0], | |
stepz = minz_stepz_maxz[1], | |
maxz = minz_stepz_maxz[2] + 0.001*stepz, | |
l = len(arr1) | |
) | |
[ | |
for (z = [minz:stepz:maxz]) | |
ExtrapolateZ(arr1, arr2, l, z) | |
]; | |
function TiltX(pointarrays, factor) = | |
[for (h = pointarrays) | |
[for (p = h) | |
[p[0] + factor*p[2], p[1], p[2]] | |
] | |
]; | |
function StretchX(pointarrays, factor) = | |
[for (h = pointarrays) | |
[for (p = h) | |
[p[0]*factor, p[1], p[2]] | |
] | |
]; | |
function ScaleLayerXY(pointarray, factor) = | |
[for (p = pointarray) | |
[p[0]*factor[0], p[1]*factor[1], p[2]] | |
]; | |
function SubtractXY(arr1, arr2) = let ( | |
size = len(arr1) > len(arr2) ? len(arr1) : len(arr2) | |
) | |
[for (hind = [0:size-1]) let( | |
h1 = arr1[hind], | |
h2 = arr2[hind] | |
) | |
[for (pind = [0:len(arr1[0])-1]) let( | |
p1 = h1[pind], | |
p2 = h2[pind] | |
) | |
[p1[0]-p2[0], p1[1]-p2[1], (p1[2]+p2[2])/2] | |
] | |
]; | |
function sumfrom(start, end, arr) = start<end ? | |
arr[start%len(arr)] + sumfrom(start+1, end, arr) : | |
arr[start%len(arr)]; | |
function SmoothXY(pointarrays, smoothby) = | |
[for (h = pointarrays) | |
[for (pind = [0:len(h)-1]) | |
sumfrom(pind+len(h)-smoothby, pind+len(h)+smoothby, h) / | |
(2*smoothby+1) | |
] | |
]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment