include ; include ; include ; include ; module step(radius, angle, height, overhang = 2, underslope = 45) { step_depth = (PI * radius) * (angle / 360); echo("step_depth", step_depth); union() { difference() { linear_extrude(height=height * 2, center=true) { pie_slice(radius, 0, angle); } rotate([0,90,0]) translate([height,0,radius]) { rotate([0,0,0]) rotate([0,180,-underslope]) translate([0,0,0]) cube([step_depth * 4,step_depth * 4,radius], center=false); } } if (!draft) { translate([0,0,height - overhang / 2]) rotate([0,90,0]){ cylinder(r=overhang / 2, h=radius + 1, center=false, $fn=8); } } } } /* module step() { union() { linear_extrude(height=actual_step_height * 2, center=true) { pie_slice(radius + 1, 0, step_depth_deg); } rotate([0,90,0]) translate([step_height * 2,0,radius]) { rotate([0,0,0]) for (s = [0,10]) { translate([0,-step_depth * 2,s * 10]) cube([5,5,5], center=false); } } if (!draft) { translate([0,0,step_height - overhang / 2]) rotate([0,90,0]){ cylinder(r=overhang / 2, h=radius + 1, center=false, $fn=8); } } } } //*/ module stairs(radius, height, twists = 1, step_height = 1, step_depth = 1, overhang = 2, underslope = 45) { steps = floor((PI * radius * twists) / step_depth); step_depth_deg = (360 * twists) / steps; actual_step_height = height / floor(height / step_height); actual_step_depth = (step_depth_deg / 360) * (PI * radius * 2); floor_degree = atan2(actual_step_height, actual_step_depth); /* module step() { union() { linear_extrude(height=actual_step_height * 2, center=true) { pie_slice(radius + 1, 0, step_depth_deg); } rotate([0,90,0]) translate([step_height * 2,0,radius]) { rotate([0,0,0]) for (s = [0,10]) { translate([0,-step_depth * 2,s * 10]) cube([5,5,5], center=false); } } if (!draft) { translate([0,0,step_height - overhang / 2]) rotate([0,90,0]){ cylinder(r=overhang / 2, h=radius + 1, center=false, $fn=8); } } } } // */ module underside() { // linear_extrude( // height = height, // center = false, // twist = -twists * 360 - step_depth_deg, // $fn = 250 // ) { // pie_slice(radius * 2, 0, 90, $fn=16); // } } module all_steps() { for (s = [0:steps]) { translate([0, 0, s * actual_step_height]) { rotate([0, 0, step_depth_deg * s]) { step(radius, step_depth_deg, actual_step_height, 2, underslope); } } } } intersection() { cylinder(r=radius, h=height, center=false, $fn=256); difference() { all_steps(); if (!draft) { rotate([0,0,step_depth_deg / 2]) { underside(); } } } } } module banister() { // Banister y = 10; left = 1; right = 2; { intersection() { translate([-tower_radius, 0, 0]) rotate([0,0,exit]) scale([-1, 1, 1]) { difference() { cylinder(r=tower_radius + left, h=tower_radius+y, center=false); translate([0,0,-1]) cylinder(r=tower_radius - 4, h=tower_radius + 2+y, center=false); } } translate([0,0,-2]) cylinder(r=tower_radius - right, h=tower_radius + 4 + y, center=false); } } } module bottom_stairs_and_banister() { difference() { union() { translate([-tower_radius, 0, 0]) rotate([0,0,exit]) scale([-1, 1, 1]) { difference() { stairs(tower_radius, bottom_stairs, twists=.14, step_height = 5.8, step_depth = 5); cylinder(r=5/2, h=bottom_stairs, center=false); } } } translate([0,0,bottom_stairs]) cylinder(r=tower_radius, h=tower_height, center=false); rotate([0,0,193]) translate([-10,0,0]) cube(size=[tower_radius + 10, tower_radius, bottom_stairs * 2], center=false); } difference() { union() { banister(); } rotate([0,0,180]) translate([-10,0,0]) cube(size=[tower_radius + 10, tower_radius, bottom_stairs * 3], center=false); } } module double_stairs() { intersection() { cylinder(r=tower_radius - brick_depth / 2, h=tower_height, center=false); union() { translate([0,0,bottom_stairs]) { rotate([0,0,180]) stairs(tower_radius, tower_height - bottom_stairs, step_height = step_height, step_depth = step_depth, twists = twists, underslope = underslope); difference() { stairs(tower_radius, tower_height - bottom_stairs, step_height = step_height, step_depth = step_depth, twists = twists, underslope = underslope); //translate([0,0,-1]) cylinder(r=tower_radius, h=dungeon_extra + 1, center=false); // Banister translate([0,0,-1]) intersection() { translate([-tower_radius, 0, 0]) rotate([0,0,exit]) scale([-1, 1, 1]) { difference() { cylinder(r=tower_radius * 2, h=tower_radius, center=false); translate([0,0,-1]) cylinder(r=tower_radius, h=tower_radius + 2, center=false); } } translate([0,0,-2]) cylinder(r=tower_radius - 2, h=tower_radius + 4, center=false); } } } } } } module floor() { cylinder(r=tower_radius, h=2, center=false); } module dungeon_bars() { max=8; module loop(n) { if (n >= 0) { rotate([0,0,n * -14.5]) translate([0, tower_radius - (2.5 * 1.5), 0]) scale([1,1.25,1]) { bonus=sin((n/max) * 180) * 18.5 + 4; difference() { cylinder(r=2.5, h=dungeon_height + bonus, center=false); cylinder(r=0.1, h=dungeon_height + bonus, center=false); } } loop(n - 1); } } rotate([0,0,exit + dungeon_angle]) loop(max); } module generic_neg(angle, size, ratio) { rotate([0,0,angle]) scale([1,1,ratio]) pinch(tower_radius + 10, size); } module generic_rim(angle, size, ratio, offset, border = 5) { rotate([0,0,angle]) difference() { translate([0,0,offset]) scale([1,1,ratio]) pinch(tower_radius + border, size + border); scale([1,1,ratio]) pinch(tower_radius + 10, size); } } module front_door_neg() { generic_neg(exit, tower_radius / 2, 2); } module front_door_rim() { generic_rim(exit, tower_radius / 2, 2, -4); } module dungeon_window_neg() { generic_neg(dungeon_angle, tower_radius); } module dungeon_window_rim() { generic_rim(dungeon_angle, tower_radius, 1, 2); } module window_neg(h, z) { difference() { translate([0,0,h]) rotate([0,0,exit+z]) generic_neg(90, 10, 1.5); cylinder(r=tower_radius + 10, h); } } module window_rim(h, z) { difference() { translate([0,0,h]) rotate([0,0,exit+z]) generic_rim(90, 10, 1.5, border=2); cylinder(r=tower_radius + 10, h); } translate([0,0,h]) mirror([0,0,1]) rotate([0,0,z - 121.5]) linear_extrude(height=2, center=false, convexity=10, twist=0, scale=[.95,1]) { pie_slice(tower_radius + 2, -15.5, 15.5 ); } } module detents(clearance = 0) { rotate([0,0,45]) { rotate([0,0,0]) translate([tower_radius - brick_depth / 2,0,0]) sphere(1.5 + clearance, $fn=16); rotate([0,0,180]) translate([tower_radius - brick_depth / 2,0,0]) sphere(1.5 + clearance, $fn=16); detent_r = pin_diameter / 2 + pin_clearance * 2; //translate([0,0,pin_height - detent_r]) sphere(detent_r + clearance); } } scale([-1,1,1]) { if (false) union() { color("grey") floor(); color("grey") difference() { tower(tower_radius, tower_height); front_door_neg(); dungeon_window_neg(); window_neg(100, 0); window_neg(100, 180); window_neg(75, 60); window_neg(75, 240); window_neg(50, 120); window_neg(50, 300); } color("grey") intersection() { //tower(tower_radius + 5, 60); difference() { cylinder(r=tower_radius + 5, h=60, center=false); cylinder(r=tower_radius + 5 - brick_depth, h=60, center=false); } union() { front_door_rim(); dungeon_window_rim(); } } color("grey") intersection() { //tower(tower_radius + 2, tower_height); difference() { cylinder(r=tower_radius + 2, h=tower_height, center=false); cylinder(r=tower_radius + 2 - brick_depth, h=tower_height, center=false); } union() { window_rim(100, 0); window_rim(100, 180); window_rim(75, 60); window_rim(75, 240); window_rim(50, 120); window_rim(50, 300); } } color("grey") dungeon_bars(); color("grey") bottom_stairs_and_banister(); difference() { union() { color("grey") double_stairs(); color("grey") cylinder(r=pin_diameter / 2, h=tower_height, center=false); } translate([0,0,tower_height - screw_length]) cylinder(r=screw_diameter / 2, h=screw_length + 1, center=false, $fn=16); } color("red") translate([0,0,tower_height - 0.25]) detents(); } //$fn=25; // Top //if (false) color("grey") translate([0,0,tower_height]) { radius = tower_radius + 5; difference() { union() { //translate([0, 0, 20]) sphere(7); difference() { union() { tower(radius, 25); difference() { cylinder(r=radius - brick_depth / 2, h=2, center=false); linear_extrude(height=5, center=true) { pie_slice(tower_radius - brick_depth, -100, 45); } translate([0,0,2]) { // Grooves rotate_extrude(convexity=10) { translate([(radius - brick_depth / 2) * .25, 0, 0]) rotate([0,0,45]) square([groove,groove], center=true); translate([(radius - brick_depth / 2) * .5, 0, 0]) rotate([0,0,45]) square([groove,groove], center=true); translate([(radius - brick_depth / 2) * .75, 0, 0]) rotate([0,0,45]) square([groove,groove], center=true); } for (i=[1:5]) { rotate([0,90+180,45+180 + 35 * i]) rotate([0,0,45]) linear_extrude(height=tower_radius, center=false, convexity=10, twist=0) { square(groove, groove, center=true); } } } } // Wall rotate([0,0,-100]) translate([0, -2]) { translate([25,0,0]) cube([radius - brick_depth / 2 - 25, 2, 20]); intersection() { cube([radius - brick_depth / 2, 2, 20]); rotate([90, 0]) translate([25,0,0]) cylinder(r=20, h=10, center=true, $fn=100); } } //cylinder(r=pin_diameter / 2 + pin_clearance * 2 + 2, h=20, center=false); translate([0,0,25 - 3.5]) { difference() { rotate_extrude(convexity=10) { translate([radius - brick_depth / 2, 0, 0]) rotate([0,0,45]) square([7,7]); } } } } rampart_width = 15; ramparts = 8; translate([0,0,20]) { for (z = [0:ramparts - 1]) { rotate([0,0,360 / ramparts * z]) linear_extrude(height=20, center=false, convexity=10, twist=0) { pie_slice(radius + 10, -rampart_width / 2, rampart_width / 2); } } } } translate([0,0,2]) { // Lip rotate([0,90+180,45+180]) rotate([0,0,45]) linear_extrude(height=tower_radius, center=false, convexity=10, twist=0) { square(groove, groove, center=true); } } translate([0,0,2]) { // Rim rotate_extrude(convexity=10) { translate([radius - .25, 0, 0]) circle(2, center=true); } } cylinder(r=5, h=2 + screw_head_height, center=false); } color("red") detents(pin_clearance); //cylinder(r=pin_diameter / 2 + pin_clearance * 2, h=pin_height + pin_clearance, center=true); // Stress relief // rotate([0,0,-30]) translate([0,-.5, -1]) cube([10,2,10]); translate([0,0,0]) { // Groove rotate_extrude(convexity=10, $fn=50) { translate([tower_radius - brick_depth / 2, 0, 0]) circle(1, center=true, $fn=15); } } cylinder(r=screw_diameter/2, h=10, center=true, $fn=16); translate([0,0,2]) cylinder(r=screw_head_diameter/2, h=100, center=false, $fn=16); } } // Bottom if (false) color("grey") rotate([0,0,exit]) translate([0, -tower_radius,0]) { radius = tower_radius + 5; difference() { union() { tower(radius, bottom_height); difference() { cylinder(r=radius - brick_depth / 2, h=2, center=false); translate([0,0,2]) { // Grooves rotate_extrude(convexity=10) { translate([(radius - brick_depth / 2) * .25, 0, 0]) rotate([0,0,45]) square([groove,groove], center=true); translate([(radius - brick_depth / 2) * .5, 0, 0]) rotate([0,0,45]) square([groove,groove], center=true); translate([(radius - brick_depth / 2) * .75, 0, 0]) rotate([0,0,45]) square([groove,groove], center=true); } for (i=[4:10]) { rotate([0,90+180,45+180 + 35 * i]) rotate([0,0,45]) linear_extrude(height=tower_radius, center=false, convexity=10, twist=0) { square(groove, groove, center=true); } } } } } translate([0, tower_radius,0]) cylinder(r=tower_radius - brick_depth / 2, h=26, center=false); } } }