Skip to content

Instantly share code, notes, and snippets.

@thehans
Created February 6, 2023 00:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thehans/1547e5f8477b63351f2723d1e557f2c6 to your computer and use it in GitHub Desktop.
Save thehans/1547e5f8477b63351f2723d1e557f2c6 to your computer and use it in GitHub Desktop.
A pistol-style grip for a pvc pipe
// 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 = 12;
plot_zstep = 0.6;
plot_asteps = 180;
barrelOD = 33.401;
barrelSurroundTh = 3;
barrelXOffset = 1;
barrelZOffset = 4; // 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.8; // 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 = 50;
r_cyl = d_cyl / 2;
h_transition = r_cyl - r_cyl * cos(transition_angle) + barrelZOffset;
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) + barrelZOffset;
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([barrelXOffset,0,-d_cyl/2-barrelZOffset/2-err])
cube([h_cyl,d_cyl+err,d_cyl+barrelZOffset+2*err], center=true);
}
translate([barrelXOffset,0,-d_cyl/2-barrelZOffset]) rotate([0,90,0])
cylinder(d=d_cyl, h=h_cyl, center=true);
}
translate([barrelXOffset,0,-d_cyl/2-barrelZOffset]) 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