Skip to content

Instantly share code, notes, and snippets.

@cameronkerrnz
Created March 29, 2025 06:21
Show Gist options
  • Save cameronkerrnz/3672e35a545c25e3c5feffe2b82f5d70 to your computer and use it in GitHub Desktop.
Save cameronkerrnz/3672e35a545c25e3c5feffe2b82f5d70 to your computer and use it in GitHub Desktop.
OpenSCAD Magnifying Glass
$fn = 12;
rope_diam = 6;
rope_strand_eccentricity = 0.3; // prop. of diam. it should move from center
lens_radius = 50;
hoop_radius = lens_radius + rope_diam * 0.5; // fudge factor allows for strand packing + lens overlap
handle_length = 100;
module rope_crosssection() {
offset(r=-0.2) offset(r=0.2)
for(i = [0: 120: 360]) {
rotate([0,0,i]) translate([rope_diam * rope_strand_eccentricity,0,0]) circle(d=rope_diam);
}
}
module rope_strand_crosssection(angle) {
rotate([0,0,angle])
translate([rope_diam * rope_strand_eccentricity, 0, 0]) circle(d=rope_diam);
}
module stranded_handle() {
rope_length = 100;
rope_twist_per_unit = 360 / 28; // one twist per 100 units of length
linear_extrude(height=100, twist=rope_length * rope_twist_per_unit)
rope_crosssection();
}
module stranded_hoop(radius=50, slice_angle=2, twist_factor=12) {
for(start_angle = [0:slice_angle:359]) {
rotate([0,0,start_angle])
for(strand_angle = [0:120:359])
hull() {
rotate_extrude(angle=0.001)
translate([radius,0,0])
rotate([0,0,(start_angle)*twist_factor])
rope_strand_crosssection(strand_angle);
rotate([0,0,slice_angle])
rotate_extrude(angle=0.001)
translate([radius,0,0])
rotate([0,0,(start_angle + slice_angle)*twist_factor])
rope_strand_crosssection(strand_angle);
}
}
}
module color_if_zero(x, color_arg) {
if(x == 0) {
echo(x, x==0);
color(color_arg) children();
} else {
children();
}
}
module stranded_hoop_exploration(radius=50, slice_angle=2, twist_factor=12) {
for(start_angle = [0:slice_angle:59]) { // just part of the hoop
rotate([0,0,start_angle]) {
color_if_zero(start_angle, "yellow") {
for(strand_angle = [0:120:119]) { // just one strand
hull() {
rotate_extrude(angle=0.001)
translate([radius,0,0])
rotate([0,0,(start_angle)*twist_factor])
rope_strand_crosssection(strand_angle);
rotate([0,0,slice_angle])
rotate_extrude(angle=0.1)
translate([radius,0,0])
rotate([0,0,(start_angle + slice_angle)*twist_factor])
rope_strand_crosssection(strand_angle);
}
}
}
}
}
}
// !stranded_hoop_exploration();
module convex_lens(radius=50, edge_thickness=2.5, center_thickness=5) {
// a rough approximation; better than a sphere of radus 1000
hull() {
translate([0,0,edge_thickness/2])
cylinder(h=center_thickness-edge_thickness, r1=radius, r2=radius*0.45, $fn=64);
rotate([180,0,0])
translate([0,0,edge_thickness/2])
cylinder(h=center_thickness-edge_thickness, r1=radius, r2=radius*0.45, $fn=64);
}
}
module handle() {
// hoop/handle interface
minkowski() {
translate([0,-hoop_radius,0])
rotate([0,90,0])
cylinder(h=15, d=rope_diam*2-1, center=true, $fn=32);
sphere(r=0.5, $fn=4);
}
// handle shank
translate([0,-hoop_radius,0])
rotate([90,0,0])
//cylinder(h=handle_length, d=11, $fn=16);
cylinder(h=handle_length, d1=11, d2=15, $fn=32);
// handle pommel
translate([0,-hoop_radius-handle_length])
sphere(d=15, $fn=32);
}
module assembly() {
difference() {
union() {
stranded_hoop(radius=hoop_radius);
handle();
}
convex_lens(radius=lens_radius);
}
}
module printing_half(is_upper=true) {
difference() {
intersection() {
assembly();
translate([0,0,25*(is_upper?1:-1)]) cube([500, 500, 50], center=true);
}
translate([0,-hoop_radius - handle_length*0.1,0]) // bottom of hoop / top of handle
cylinder(h=3,d=1.5,center=true);
translate([0,hoop_radius,0]) // top of hoop
cylinder(h=3,d=1.5,center=true);
translate([hoop_radius,0,0]) // sides of hoop
cylinder(h=3,d=1.5,center=true);
translate([-hoop_radius,0,0])
cylinder(h=3,d=1.5,center=true);
translate([0,-hoop_radius - handle_length*0.8,0]) // bottom of handle
cylinder(h=3,d=1.5,center=true);
}
}
module printing() {
printing_half();
translate([hoop_radius * 1.5, -handle_length, 0])
rotate([180,0,0])
printing_half(is_upper=false);
}
module display() {
assembly();
}
// printing();
assembly();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment