Clearance tweaks based on recent print.

Clearance tweaks based on recent print.

// Modified from: https://github.com/luisibanez/ShapesFor3DPrinting/tree/master/OpenSCA

module piCameraEnclosure()
{

	module piCameraBackCoverBevel(width, height, clearance) {
		c = clearance;
		hh = height / 2;
		hw = ( width / 2 ) + c;
		he = hw + 1.5 + c;
		polyhedron(
			points = [
				[ hw, -15-c, -hh-c ],
				[ hw,  15+c, -hh-c ],
				[ hw,  15+c, hh ],
				[ hw, -15-c, hh ],
				[ he, -15-c, -hh-c ],
				[ he,  15+c, -hh-c ]
				],
			faces = [
				[ 5, 1, 0, 4],
				[ 4, 0, 3 ],
				[ 2, 1, 5 ],
				[ 5, 4, 3, 2],
				[ 0, 1, 2, 3],
			]
		);
	}

	module piCameraBackCoverBevels(width, height, clearance) {
		union() {
			piCameraBackCoverBevel(width, height, clearance);
			mirror([1,0,0])
				piCameraBackCoverBevel(width, height, clearance);
		}
	}

	module piCameraBackCover(width, height, clearance=0, indent=true) {
		c = 2*clearance;
		translate([0,-5.5,10-height/2])
			difference() {
				union() {
					piCameraBackCoverBevels(width, height, clearance);
					cube(size=[width+c,30+c,height+c],center=true);
				}
				translate([0,12,0])
					cube(size=[width-5-c,7,height+c],center=true);
				if (indent)
					translate([0,-12,height/2])
					rotate([0,90,0])
						cylinder(r=1, h=width-0.5, center=true, $fn=20);
			}
	}

	module cableOpening() {
		translate([0,14,8.1])
			cube(size=[17,12,4],center=true);
	}

	module chipOpening() {
		clearance = 0.5;
		c = 2 * clearance;
		translate([0,-9.5,5])
			cube(size=[8+c,10+c,4],center=true);
	}

	module lensOpening() {
		clearance = 0.5;
		c = 2 * clearance;
		translate([0,0,2.5])
			cube(size=[8+c,8+c,5+c], center=true);
	}

	module boardOpening() {
		clearance = 0.3;
		c = 2 * clearance;
		translate([0,-3,7.5])
			cube(size=[25+c,24+c,5+clearance], center=true);
	}

	module cameraFrame() {
		translate([0,-0.5,5])
			cube(size=[40,40,10], center=true);
	}

	module roundedCorner(radius) {
		translate([-radius, -radius, 0])
		difference() {
			translate([0,0,-50])
				cube(size=[radius+0.1,radius+0.1,100]);
			cylinder(h=100, r=radius, $fn=50, center=true);
		}
   }

   module cornerRounding(radius) {
		// vertical corners
		translate([20,19.5,0])
			roundedCorner(radius);
		translate([-20,19.5,0])
		rotate([0,0,90])
			roundedCorner(radius);
		translate([-20,-20.5,0])
		rotate([0,0,180])
			roundedCorner(radius);
		translate([20,-20.5,0])
		rotate([0,0,-90])
			roundedCorner(radius);

		// top corners
		translate([-20,0,10])
		rotate([0,-90,0])
		rotate([90,0,0])
			roundedCorner(radius/2);
		translate([20,0,10])
		rotate([90,0,0])
			roundedCorner(radius/2);
   }

	module piCameraAdapter() {
		difference() {
			cameraFrame();
			boardOpening();
			chipOpening();
			cableOpening();
			lensOpening();
			cornerRounding(radius=8);
			piCameraBackCover(width=27, height=2, clearance=0.3, indent=false);
		}
	}

	union() {
		piCameraAdapter();
		// Comment out translate to see
		// back cover in place.
		translate([40,5,-8])
			piCameraBackCover(width=27, height=2);
	}
}

piCameraEnclosure();

// Modified from: https://github.com/luisibanez/ShapesFor3DPrinting/tree/master/OpenSCA

module piCameraEnclosure()
{

	module piCameraBackCoverBevel(clearance) {
		c = clearance;
		hw = ( 25 / 2 ) + c;
		he = hw + 1.5 + c;
		polyhedron(
			points = [
				[ hw, -15-c, -1-c ],
				[ hw,  15+c, -1-c ],
				[ hw,  15+c,  1 ],
				[ hw, -15-c,  1 ],
				[ he, -15-c, -1-c ],
				[ he,  15+c, -1-c ]
				],
			faces = [
				[ 5, 1, 0, 4],
				[ 4, 0, 3 ],
				[ 2, 1, 5 ],
				[ 5, 4, 3, 2],
				[ 0, 1, 2, 3],
			]
		);
	}

	module piCameraBackCoverBevels(clearance) {
		union() {
			piCameraBackCoverBevel(clearance);
			mirror([1,0,0])
				piCameraBackCoverBevel(clearance);
		}
	}

	module piCameraBackCover(clearance=0, indent=true) {
		c = 2*clearance;
		translate([0,-5.5,9])
			difference() {
				union() {
					piCameraBackCoverBevels(clearance);
					cube(size=[25+c,30+c,2+c],center=true);
				}
				translate([0,12,0])
					cube(size=[20.5-c,7,3],center=true);
				if (indent)
					translate([0,-12,1.5])
					rotate([0,90,0])
						cylinder(r=1, h=40, center=true, $fn=20);
			}
	}

	module cableOpening() {
		translate([0,14,8.1])
			cube(size=[17,12,4],center=true);
	}

	module chipOpening() {
		clearance = 0.5;
		c = 2 * clearance;
		translate([0,-9.5,5])
			cube(size=[8+c,10+c,4],center=true);
	}

	module lensOpening() {
		clearance = 0.5;
		c = 2 * clearance;
		translate([0,0,2.5])
			cube(size=[8+c,8+c,5+c], center=true);
	}

	module boardOpening() {
		clearance = 0.2;
		c = 2 * clearance;
		translate([0,-3,7.5])
			cube(size=[25+c,24+c,5+clearance], center=true);
	}

	module cameraFrame() {
		translate([0,-0.5,5])
			cube(size=[40,40,10], center=true);
	}

	module roundedCorner(radius) {
		translate([-radius, -radius, 0])
		difference() {
			translate([0,0,-50])
				cube(size=[radius+0.1,radius+0.1,100]);
			cylinder(h=100, r=radius, $fn=50, center=true);
		}
   }

   module cornerRounding(radius) {
		// vertical corners
		translate([20,19.5,0])
			roundedCorner(radius);
		translate([-20,19.5,0])
		rotate([0,0,90])
			roundedCorner(radius);
		translate([-20,-20.5,0])
		rotate([0,0,180])
			roundedCorner(radius);
		translate([20,-20.5,0])
		rotate([0,0,-90])
			roundedCorner(radius);

		// top corners
		translate([-20,0,10])
		rotate([0,-90,0])
		rotate([90,0,0])
			roundedCorner(radius/2);
		translate([20,0,10])
		rotate([90,0,0])
			roundedCorner(radius/2);
   }

	module piCameraAdapter() {
		difference() {
			cameraFrame();
			boardOpening();
			chipOpening();
			cableOpening();
			lensOpening();
			cornerRounding(radius=8);
			piCameraBackCover(clearance=0.3, indent=false);
		}
	}

	union() {
		piCameraAdapter();
		// Comment out translate to see
		// back cover in place.
		translate([40,5,-8])
			piCameraBackCover();
	}
}

piCameraEnclosure();


add sturdy box here for now

add sturdy box here for now

$fn=20;

case_length=300;
case_width=300;
min_height=40;
panel_thickness=3.1; //3.1, 1.55, 5.7 ?

corner_pieces = floor(min_height/panel_thickness);
case_height=corner_pieces*panel_thickness;
corner_radius=10;
length_slots=13;
width_slots=13;

hole_size=3.2;
part_separation=10;

module corner_stack(hex_hole=false){
  hex_hole_size=5.4;
  radius = corner_radius;
  difference() {
    circle(r=radius);
    translate([radius, 0]) square([radius, panel_thickness], center=true);
    rotate(90) translate([radius, 0]) square([radius, panel_thickness], center=true);
    if (hex_hole){
      circle(d=hex_hole_size, $fn=6);
    } else {
      circle(d=hole_size);
    }
  }
}

module make_slots(length, slot_count,  panel_thickness, reverse=false, slop=0){

  slot_size=length/slot_count;
  offset= reverse?slot_size:0;
  odd= (slot_count%2) == 1?1:0;
  extra = odd && !reverse?1:0;

  for(x=[0:floor((slot_count + extra)/2) - 1]){
    translate([2*x*slot_size + offset -slop/2, 0]) square([slot_size + slop, panel_thickness]);
  }
}

module rounded_square(width, height, radius){
  hull(){
    translate([radius,         radius]) circle(r=radius);
    translate([width - radius, radius]) circle(r=radius);
    translate([radius,         height - radius]) circle(r=radius);
    translate([width - radius, height - radius]) circle(r=radius);
  }
}

module rounded_square_clamping_holes(length, width, radius, hole_size){
  translate([radius, radius]) circle(d=hole_size);
  translate([length - radius, radius]) circle(d=hole_size);
  translate([radius, width - radius]) circle(d=hole_size);
  translate([length - radius, width - radius]) circle(d=hole_size);
}

module width_side(){
  plate_height = case_height;
  plate_width = case_width - 3*corner_radius;
  union(){
    square([plate_height, plate_width]);
    translate([plate_height + panel_thickness -0.0001, 0]) rotate(90) make_slots(case_width - 3*corner_radius, width_slots, panel_thickness, true);
    rotate(90) make_slots(case_width - 3*corner_radius, width_slots, panel_thickness, true);
  }
}

module length_side(){
  plate_height = case_height;
  plate_width = case_length - 3*corner_radius;
  standoff_height=5;
  centered_board_offset = (case_length - 2*corner_radius - board_widths)/2;
  union(){
    square([plate_width, plate_height]);
    translate([0, plate_height]) make_slots(case_length - 3*corner_radius, length_slots, panel_thickness, true);
    translate([0, - panel_thickness ]) make_slots(case_length - 3*corner_radius, length_slots, panel_thickness, true);
  }
}

module base(){
  difference() {
    rounded_square(case_length, case_width, corner_radius);
    translate([1.5*corner_radius, corner_radius - panel_thickness/2 ]) make_slots(case_length - 3*corner_radius, length_slots, panel_thickness, true);
    translate([1.5*corner_radius, case_width -corner_radius - panel_thickness/2 ]) make_slots(case_length - 3*corner_radius, length_slots, panel_thickness, true);
    translate([corner_radius + panel_thickness/2, 1.5*corner_radius]) rotate(90) make_slots(case_width - 3*corner_radius, width_slots, panel_thickness, true);
    translate([case_length - corner_radius + panel_thickness/2, 1.5*corner_radius]) rotate(90) make_slots(case_width - 3*corner_radius, width_slots, panel_thickness, true);
    rounded_square_clamping_holes(case_length, case_width, corner_radius);
  }
}

translate([-case_length/2, -case_width/2]) base();
translate([-case_length/2, case_width/2 + 2*part_separation + case_height]) base();

translate([1.5*corner_radius -case_length/2, +case_width/2 + part_separation]) length_side();
translate([1.5*corner_radius -case_length/2, -case_width/2 - case_height - part_separation]) length_side();

translate([-case_length/2 - part_separation - case_height, -case_width/2 + 1.5*corner_radius]) width_side();
translate([+case_length/2 + part_separation, -case_width/2 + 1.5*corner_radius]) width_side();

translate([-case_length/2 + corner_radius, -case_width/2 - 2*case_height - part_separation]){
  corner_pieces_per_base=floor(case_length/(2*corner_radius + part_separation));
  rows = floor(corner_pieces*4/corner_pieces_per_base);
  for(y=[0:rows]){
    for(x=[0:corner_pieces_per_base]){
        translate([2*x*corner_radius + x*part_separation/2, -(2*corner_radius*y + y*part_separation)]) corner_stack();
    }
  }
}

error: pathspec 'src/sturdy_box/sturdy_box.scad' did not match any file(s) known to git


feat: add an arrow on top and bottom of the test element to better see its direction when rotated or mirrored

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2022 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Testing helpers for visual tests.
 *
 * @package shape/context
 * @author jsconan
 */

/**
 * Places the children at the proper test area.
 * @param Number length - The length of the test area.
 * @param Number width - The width of the test area.
 * @param Number [index] - The index number of the test.
 * @param Number|Vector [margin] - A margin between each test.
 * @param Number [cols] - The number of columns per lines.
 * @param Boolean [center] - Whether or not the children are centered and need to be moved.
 */
module placeVisualTest(length, width, index=0, margin=0, cols=0, center=false) {
    margin = vector2D(margin);
    x = cols ? index % cols : index;
    y = cols ? floor(index / cols) : 0;
    offset = center ? [length, width, 0] / 2 : ORIGIN_3D;

    translate(offset + [(length + margin.x) * x, (width + margin.y) * y, 0]) {
        children();
    }
}

/**
 * Renders a test element. If no children is given, a cube with an arrow on top is rendered.
 * @param String|Vector [c] - The color of the element.
 * @param Number|Vector [angle] - The angle of the element.
 * @param Number|Vector [size] - The size of the element. It only applies if no children is given.
 * @param Boolean [center] - Whether or not the element is centered. It only applies if no children is given.
 */
module testElement(c="red", angle=0, size=1, center=false) {
    color(c) {
        rotate(angle) {
            if ($children)  {
                children();
            } else let(
                size = vector3D(size),
                half = size / 2,
                quarter = size / 4,
                offset = center ? -half : vector3D()
            ) {
                translate(offset) {
                    linear_extrude(height=size.z, convexity=10) {
                        polygon(
                            points = path([
                                ["P", half.x, size.y],
                                ["L", half.x, -half.y],
                                ["H", -quarter.x],
                                ["V", -half.y],
                                ["H", -half.x],
                                ["V", half.y],
                                ["H", -quarter.x],
                            ]),
                            convexity = 10
                        );
                    }
                    translateZ(quarter.z) {
                        cube(size=[size.x, size.y, half.z]);
                    }
                }
            }
        }
    }
}

/**
 * Colorizes a test element.
 * @param Number alpha - The alpha level for the testbed color.
 */
module testbedColor(alpha) {
    %color(TESTBED_COLOR, alpha) {
        children();
    }
}

/**
 * Extrudes and colorizes a test element.
 * @param Number alpha - The alpha level for the testbed color.
 */
module testbedExtrude(alpha) {
    testbedColor(alpha) {
        linear_extrude(height=TESTBED_THICKNESS, convexity=10, center=true) {
            children();
        }
    }
}

/**
 * Renders a test area, moving the tested shapes in it.
 * A testbed is shown, unless the global variable `SELECT_TEST` is set to `false`.
 * @param Number index - The index number of the test.
 * @param Number length - The length of the test area.
 * @param Number width - The width of the test area.
 * @param String [title] - The title for the test.
 * @param Number|Vector [margin] - A margin between each test.
 * @param Number [cols] - The number of columns per lines.
 * @param Boolean [center] - Whether or not the children are centered and need to be moved.
 */
module visualTest(index, length, width, title="test", margin=1, cols=0, center=false) {
    title = str(title, " ", index);

    placeVisualTest(
        length = length,
        width = width,
        index = index,
        margin = margin,
        cols = cols,
        center = center
    ) {
        // test area
        if (SHOW_TESTBED) {
            testbedExtrude(.1) {
                square([length, width], center=center);
            }
            translate(center ? ORIGIN_3D : [length, width, 0] / 2) {
                testbedExtrude(1) {
                    text(title, size=min(length, width) / len(title), font="Liberation Sans", valign="center", halign="center");
                }
            }
        }

        // tested shapes
        children();
    }
}

/**
 * Renders a test area for each child module, moving the tested shapes in it.
 * A single test can be selected by its index thanks to the global variable `SELECT_TEST`.
 * @param Number length - The length of the test area.
 * @param Number width - The width of the test area.
 * @param String [title] - The title for the test.
 * @param Number|Vector [margin] - A margin between each test.
 * @param Number [cols] - The number of columns per lines.
 * @param Boolean [center] - Whether or not center the whole suite.
 * @param Boolean [centerEach] - Whether or not center each test area.
 */
module visualTestSuite(length, width, title="test", margin=1, cols=0, center=false, centerEach=false) {
    margin = vector2D(margin);
    count = $children;
    SELECT_TEST = is_undef(SELECT_TEST) ? undef : min(max(0, SELECT_TEST), count - 1);
    start = is_undef(SELECT_TEST) ? 0 : SELECT_TEST;
    end = is_undef(SELECT_TEST) ? count - 1 : SELECT_TEST;
    lines = cols ? ceil(count / cols) : 1;
    offset = center ? -([margin.x * (cols - 1), margin.y * (lines - 1), 0] + [length * cols, width * lines, 0]) / 2 : ORIGIN_3D;

    translate(offset) {
        for (i = [start : end]) {
            visualTest(
                index = i,
                length = length,
                width = width,
                title = title,
                margin = margin,
                cols = cols,
                center = centerEach
            ) {
                children(i);
            }
        }
    }
}

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2022 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Testing helpers for visual tests.
 *
 * @package shape/context
 * @author jsconan
 */

/**
 * Places the children at the proper test area.
 * @param Number length - The length of the test area.
 * @param Number width - The width of the test area.
 * @param Number [index] - The index number of the test.
 * @param Number|Vector [margin] - A margin between each test.
 * @param Number [cols] - The number of columns per lines.
 * @param Boolean [center] - Whether or not the children are centered and need to be moved.
 */
module placeVisualTest(length, width, index=0, margin=0, cols=0, center=false) {
    margin = vector2D(margin);
    x = cols ? index % cols : index;
    y = cols ? floor(index / cols) : 0;
    offset = center ? [length, width, 0] / 2 : ORIGIN_3D;

    translate(offset + [(length + margin.x) * x, (width + margin.y) * y, 0]) {
        children();
    }
}

/**
 * Renders a test element. If no children is given, a cube is rendered.
 * @param String|Vector [c] - The color of the element.
 * @param Number|Vector [size] - The size of the element. It only applies if no children is given.
 * @param Boolean [center] - Whether or not the element is centered. It only applies if no children is given.
 */
module testElement(c="red", size=1, center=false) {
    color(c) {
        if ($children)  {
            children();
        } else {
            cube(size=size, center=center);
        }
    }
}

/**
 * Colorizes a test element.
 * @param Number alpha - The alpha level for the testbed color.
 */
module testbedColor(alpha) {
    %color(TESTBED_COLOR, alpha) {
        children();
    }
}

/**
 * Extrudes and colorizes a test element.
 * @param Number alpha - The alpha level for the testbed color.
 */
module testbedExtrude(alpha) {
    testbedColor(alpha) {
        linear_extrude(height=TESTBED_THICKNESS, convexity=10, center=true) {
            children();
        }
    }
}

/**
 * Renders a test area, moving the tested shapes in it.
 * A testbed is shown, unless the global variable `SELECT_TEST` is set to `false`.
 * @param Number index - The index number of the test.
 * @param Number length - The length of the test area.
 * @param Number width - The width of the test area.
 * @param String [title] - The title for the test.
 * @param Number|Vector [margin] - A margin between each test.
 * @param Number [cols] - The number of columns per lines.
 * @param Boolean [center] - Whether or not the children are centered and need to be moved.
 */
module visualTest(index, length, width, title="test", margin=1, cols=0, center=false) {
    title = str(title, " ", index);

    placeVisualTest(
        length = length,
        width = width,
        index = index,
        margin = margin,
        cols = cols,
        center = center
    ) {
        // test area
        if (SHOW_TESTBED) {
            testbedExtrude(.1) {
                square([length, width], center=center);
            }
            translate(center ? ORIGIN_3D : [length, width, 0] / 2) {
                testbedExtrude(1) {
                    text(title, size=min(length, width) / len(title), font="Liberation Sans", valign="center", halign="center");
                }
            }
        }

        // tested shapes
        children();
    }
}

/**
 * Renders a test area for each child module, moving the tested shapes in it.
 * A single test can be selected by its index thanks to the global variable `SELECT_TEST`.
 * @param Number length - The length of the test area.
 * @param Number width - The width of the test area.
 * @param String [title] - The title for the test.
 * @param Number|Vector [margin] - A margin between each test.
 * @param Number [cols] - The number of columns per lines.
 * @param Boolean [center] - Whether or not center the whole suite.
 * @param Boolean [centerEach] - Whether or not center each test area.
 */
module visualTestSuite(length, width, title="test", margin=1, cols=0, center=false, centerEach=false) {
    margin = vector2D(margin);
    count = $children;
    SELECT_TEST = is_undef(SELECT_TEST) ? undef : min(max(0, SELECT_TEST), count - 1);
    start = is_undef(SELECT_TEST) ? 0 : SELECT_TEST;
    end = is_undef(SELECT_TEST) ? count - 1 : SELECT_TEST;
    lines = cols ? ceil(count / cols) : 1;
    offset = center ? -([margin.x * (cols - 1), margin.y * (lines - 1), 0] + [length * cols, width * lines, 0]) / 2 : ORIGIN_3D;

    translate(offset) {
        for (i = [start : end]) {
            visualTest(
                index = i,
                length = length,
                width = width,
                title = title,
                margin = margin,
                cols = cols,
                center = centerEach
            ) {
                children(i);
            }
        }
    }
}


added some extra space to squeeze root element in smoothly

module holder()
{
  cylinder(h=5, r=50);
  d=30;
  e=d+4;
  h=5+40;
  difference()
  {
    translate([-e/2, -e/2, 0])
      cube([e, e, h]);
    translate([-d/2, -d/2, 0])
      cube([d, d, h]);
    translate([-h/2, 0, h-10])
      rotate([0, 90, 0])
        cylinder(r=5+1, h=h);
  }
}

holder();


refactor

refactor

use <../../../basics/rounded-edges/doughnuts/doughnuts.scad>;

use <../../../shapes/geometry/arc/extruded/extruded-arc.scad>;

module halfCirclePhoneStand(height = 19.125,
                            minkowskiSphereRadius = 0.5,
                            arcRadius = 36,
                            arcRadiusExtension = 1.5)
{
    halfCirclePhoneStand_cradle(height = height,
                                minkowskiSphereRadius = minkowskiSphereRadius,
                                radius = arcRadius,
                                radiusExtension = arcRadiusExtension);

    halfCirclePhoneStand_stand(height = height,
                               minkowskiSphereRadius = minkowskiSphereRadius);
}

// sub-modules and functions follow

module halfCirclePhoneStand_cradle(height,
                                   minkowskiSphereRadius,
                                   radius,
                                   radiusExtension)
{
    xTranslate = 30;
    yTranslate = 32.7;

    difference()
    {
        halfCirclePhoneStand_cradle_bed(height = height,
                                           minkowskiSphereRadius = minkowskiSphereRadius,
                                           radius = radius,
                                           radiusExtension = radiusExtension,
                                           xTranslate = xTranslate,
                                           yTranslate = yTranslate);

        halfCirclePhoneStand_cradle_cutout(bedHeight = height,
                                        minkowskiSphereRadius = minkowskiSphereRadius,
                                        radius = radius,
                                        radiusExtension = radiusExtension,
                                        bed_xTranslate = xTranslate,
                                        bed_yTranslate = yTranslate);
    }
}

module halfCirclePhoneStand_cradle_bed(height,
                                       minkowskiSphereRadius,
                                       radius,
                                       radiusExtension,
                                       xTranslate,
                                       yTranslate)
{
    zTranslate = minkowskiSphereRadius;
    color("magenta")
    translate([xTranslate, yTranslate, zTranslate])
    rotate([0, 0, 213])
    roundedRectangularArc(angle = 150,
                          height = height,
                          minkowskiRadius = minkowskiSphereRadius,
                          radius = radius,
                          radiusExtension = radiusExtension);
}

module halfCirclePhoneStand_cradle_cutout(bedHeight,
                                          minkowskiSphereRadius,
                                          radius,
                                          radiusExtension,
                                          bed_xTranslate,
                                          bed_yTranslate)
{
    zLength = 4.2;

    xTranslate = bed_xTranslate;
    yTranslate = bed_yTranslate;
    zTranslate = minkowskiSphereRadius + (bedHeight / 2.0) - (zLength / 2.0);

    color("magenta")
    translate([xTranslate, yTranslate, zTranslate])
    rotate([0, 0, 227])
    roundedRectangularArc(angle = 37,
                          height = zLength,
                          minkowskiRadius = minkowskiSphereRadius,
                          radius = radius,
                          radiusExtension = radiusExtension);
}

module halfCirclePhoneStand_stand(height,
                                  minkowskiSphereRadius)
{
    halfCirclePhoneStand_stand_top(height = height,
                                   minkowskiSphereRadius = minkowskiSphereRadius);

    halfCirclePhoneStand_stand_base(height = height,
                                    minkowskiSphereRadius = minkowskiSphereRadius);
}

module halfCirclePhoneStand_stand_base(height,
                                       minkowskiSphereRadius)
{
    color("green")
    translate([0, 0, minkowskiSphereRadius])
    roundDoughnut(height = height,
                innerRadius = 4.9,      // 4.9
                outerRadius = 5.59,     // 5.59
                minkowskiSphereRadius = minkowskiSphereRadius);
}

module halfCirclePhoneStand_stand_top(height,
                                      minkowskiSphereRadius)
{
    xTranslate = 8.105;  // 8.05     // 8.1
    yTranslate = 8.85;  // 8.85     // 8.9

    color("green")
    translate([xTranslate, yTranslate, minkowskiSphereRadius])
    roundDoughnut(height = height,
                innerRadius = 1.9,  // 2.0
                outerRadius = 2.6,  // 2.6
                minkowskiSphereRadius = minkowskiSphereRadius);
}

use <../../../basics/rounded-edges/doughnuts/doughnuts.scad>;

use <../../../shapes/geometry/arc/extruded/extruded-arc.scad>;

module halfCirclePhoneStand(height = 19.125,
                            minkowskiSphereRadius = 0.5,
                            arcRadius = 36,
                            arcRadiusExtension = 1.5)
{
    halfCirclePhoneStand_cradle(height = height,
                                minkowskiSphereRadius = minkowskiSphereRadius,
                                radius = arcRadius,
                                radiusExtension = arcRadiusExtension);

    halfCirclePhoneStand_stand(height = height,
                               minkowskiSphereRadius = minkowskiSphereRadius);
}

// sub-modules and functions follow

module halfCirclePhoneStand_cradle(height,
                                   minkowskiSphereRadius,
                                   radius,
                                   radiusExtension)
{
    difference()
    {
        halfCirclePhoneStand_cradle_bed(height = height,
                                           minkowskiSphereRadius = minkowskiSphereRadius,
                                           radius = radius,
                                           radiusExtension = radiusExtension);

        halfCirclePhoneStand_cradle_cutout(bedHeight = height,
                                        minkowskiSphereRadius = minkowskiSphereRadius,
                                        radius = radius,
                                        radiusExtension = radiusExtension);
    }
}

module halfCirclePhoneStand_cradle_bed(height,
                                       minkowskiSphereRadius,
                                       radius,
                                       radiusExtension)
{
    xTranslate = 30;
    yTranslate = 32.7;
    zTranslate = minkowskiSphereRadius;
    color("magenta")
    translate([xTranslate, yTranslate, zTranslate])
    rotate([0, 0, 213])
    roundedRectangularArc(angle = 150,
                          height = height,
                          minkowskiRadius = minkowskiSphereRadius,
                          radius = radius,
                          radiusExtension = radiusExtension);
}

module halfCirclePhoneStand_cradle_cutout(bedHeight,
                                          minkowskiSphereRadius,
                                          radius,
                                          radiusExtension)
{
    zLength = 4.2;

    xTranslate = 30;
    yTranslate = 32.7;
    zTranslate = minkowskiSphereRadius + (bedHeight / 2.0) - (zLength / 2.0);
    color("magenta")
    translate([xTranslate, yTranslate, zTranslate])
    rotate([0, 0, 227])
    roundedRectangularArc(angle = 37,
                          height = zLength,
                          minkowskiRadius = minkowskiSphereRadius,
                          radius = radius,
                          radiusExtension = radiusExtension);
}

module halfCirclePhoneStand_stand(height,
                                  minkowskiSphereRadius)
{
    halfCirclePhoneStand_stand_top(height = height,
                                   minkowskiSphereRadius = minkowskiSphereRadius);

    halfCirclePhoneStand_stand_base(height = height,
                                    minkowskiSphereRadius = minkowskiSphereRadius);
}

module halfCirclePhoneStand_stand_base(height,
                                       minkowskiSphereRadius)
{
    color("green")
    translate([0, 0, minkowskiSphereRadius])
    roundDoughnut(height = height,
                innerRadius = 4.9,      // 4.9
                outerRadius = 5.59,     // 5.59
                minkowskiSphereRadius = minkowskiSphereRadius);
}

module halfCirclePhoneStand_stand_top(height,
                                      minkowskiSphereRadius)
{
    xTranslate = 8.105;  // 8.05     // 8.1
    yTranslate = 8.85;  // 8.85     // 8.9

    color("green")
    translate([xTranslate, yTranslate, minkowskiSphereRadius])
    roundDoughnut(height = height,
                innerRadius = 1.9,  // 2.0
                outerRadius = 2.6,  // 2.6
                minkowskiSphereRadius = minkowskiSphereRadius);
}


screw/screw_cut: add with_head param

screw/screw_cut: add with_head param

include <system.scad>
include <shapes.scad>
include <transforms.scad>
include <misc.scad>

include <metric-thread-data.scad>
include <metric-hexnut-data.scad>
include <metric-knurlnut-data.scad>

use <scad-utils/transformations.scad>

// naive, assume head height is same as thread size (generally true for cap heads)
function get_screw_head_h(nut) = lookup(ThreadSize, nut);
function get_screw_head_d(nut) = 2 * lookup(ThreadSize, nut);

module screw(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

    s = threadsize*tolerance;
    total_h = h;
    size_align(size=[s, s, total_h], orient=orient, orient_ref=[0,0,-1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head(nut, orient=[0,0,1], align=[0,0,1]);
            }

            screw_thread(thread=thread, h=h+.1, tolerance=tolerance, orient=[0,0,1], align=[0,0,0]);

            if(with_nut)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut(nut=nut, tolerance=tolerance, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

module screw_cut(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, with_head=true, nut_offset=0, cut_access=true, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

    s = threadsize*tolerance;
    total_h = h;
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            if(with_head)
            {
                translate([0,0,h/2+.01])
                screw_head_cut(nut, tolerance=1.25, override_h=1000, align=[0,0,1]);
            }

            screw_thread_cut(thread=thread, h=h+.1, tolerance=tolerance, align=[0,0,0]);

            if(with_nut)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut_cut(nut=nut, tolerance=tolerance, align=[0,0,-1]);
            }
        }
    }

    if($show_vit)
    {
        %screw(nut, h, tolerance, head_embed, with_nut, nut_offset, orient, align);
    }
}

module screw_thread(thread=ThreadM3, h=10, tolerance=1.00, orient=[0,0,1], align=[0,0,0])
{
    // TODO render thread
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

module screw_thread_cut(thread=ThreadM3, h=10, tolerance=1.05, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    difference()
    {
        cylindera(d=head_d, h = override_h==undef?head_h:override_h);
        translate([0,0,head_h/2])
        cylindera(d=threadsize, h = head_d/2);
    }
}

module screw_head_cut(nut=MHexNutM3, tolerance=1.05, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    translate([0,0,-head_h/2])
    cylindera(d=head_d, h=override_h==undef?head_h:override_h, align=[0,0,1]);
}

module screw_nut(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    facets = lookup(MHexNutFacets, nut);
    cylindera($fn=lookup(MHexNutFacets, nut), d=d, h=override_h==undef?thickness:override_h, orient=orient, align=align);
}

module screw_nut_cut(nut=MHexNutM3, tolerance=1.05, h=1000, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    size_align(size=[d,d,thickness], orient=orient, align=align)
    {
        translate([0,0,thickness/2])
        {
            screw_nut(nut, tolerance, orient=[0,0,1], align=[0,0,-1]);
            translate([0,0,-thickness+.01])
            {
                cylindera(d=d*1.1, h=h, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

module nut_trap_cut(nut=MHexNutM3, trap_offset=10, screw_l=10*mm, screw_l_extra=2*mm, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)+.5*mm;
    thread = get(MHexNutThread, nut);

    nut_width_min = lookup(MHexNutWidthMin, nut)+.2*mm;
    nut_width_max = lookup(MHexNutWidthMax, nut)+.2*mm;
    s = nut_width_min;
    total_h = nut_h;

    size_align(size=[s, s, total_h], orient=orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,nut_h/2-.1])
        screw_thread_cut(thread=thread, tolerance=1.1, h=screw_l, orient=[0,0,-1], align=[0,0,1]);

        if(screw_l_extra>0)
        translate([0,0,-nut_h/2+.1])
        screw_thread_cut(thread=thread, tolerance=1.1, h=screw_l_extra+.1, orient=[0,0,1], align=[0,0,-1]);

        hull()
        {
            orient(-orient)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(orient)
                cylindera($fn=lookup(MHexNutFacets, nut), d=nut_width_max, h=nut_h, align=[0,0,0]);

                orient(orient)
                cubea(size=[nut_width_min,nut_width_min,nut_h], align=[0,0,0]);
            }
        }

        if($show_vit)
        {
            translate([0,0, screw_l])
            translate([0,0, -nut_h/2])
            %screw(nut, tolerance=1, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);

            %screw_nut(nut, tolerance=1, orient=[0,0,-1], align=[0,0,0]);
        }

    }

}

function get(key, dict) =
    let(x= search(MHexNutThread, MHexNutM3))
    dict[x[0]];

if(false)
{
    nut1 = MHexNutM3;
    nut2 = MHexNutM5;
    nut3 = MKnurlInsertNutM3_3_42;
    nut4 = MKnurlInsertNutM3_5_42;

    /*translate([0,20,0])*/
    /*translate([0,20,0])*/
    /*for(axis1=[0:len(AXES)-1])*/
    /*[>for(axis2=AXES)<]*/
    /*translate(20*AXES[axis1])*/
    /*{*/
        /*ta = v_rotate(90, AXES[axis1])*AXES[axis1];*/
        /*echo(AXES[axis1], ta);*/
        /*nut_trap_cut(nut=nut1, trap_axis=ta, orient=AXES[axis1]);*/
    /*}*/

    /*stack(d=30, axis=[1,0,0])*/
    /*{*/
        /*stack(d=20, axis=[0,1,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[1,0,0]);*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[-1,0,0]);*/
        /*}*/

        /*stack(d=20, axis=[1,0,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,1,0]);*/

            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,-1,0]);*/
        /*}*/
    /*}*/

    box_w = 100;
    box_h = 10;
    box_d = 10;
    o = 10;

    /*$show_vit = true;*/
    $fs= 0.5;
    $fa = 4;

    difference()
    {
        cubea([box_w,box_d/2,box_h], align=[1,1,1]);

        test_cuts();
    }
    /*difference()*/
    /*{*/
        /*cubea([box_w,box_d/2,box_h], align=[1,-1,1]);*/

        /*test_cuts();*/
    /*}*/

}

module test_cuts()
{
    union()
    {
        offset = 0;
        /*offset = -5;*/
        translate([0,offset,0])
        translate([5,0,0])
        stack(dist=10,axis=[1,0,0])
        {
            screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);

            screw_cut(nut=nut1, h=box_h*mm, nut_offset=0*mm, head_embed=true, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut2, h=box_h*mm, nut_offset=3*mm, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut4, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);

            /*translate([0,5,0])*/
            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,-1], align=[0,0,0]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,1,0], orient=[0,0,1], align=[0,0,0]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,1], orient=[0,1,0], align=[0,0,0]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,-1], orient=[0,1,0], align=[0,0,0]);
        }
    }
}

include <system.scad>
include <shapes.scad>
include <transforms.scad>
include <misc.scad>

include <metric-thread-data.scad>
include <metric-hexnut-data.scad>
include <metric-knurlnut-data.scad>

use <scad-utils/transformations.scad>

// naive, assume head height is same as thread size (generally true for cap heads)
function get_screw_head_h(nut) = lookup(ThreadSize, nut);
function get_screw_head_d(nut) = 2 * lookup(ThreadSize, nut);

module screw(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, nut_offset=0, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

    s = threadsize*tolerance;
    total_h = h;
    size_align(size=[s, s, total_h], orient=orient, orient_ref=[0,0,-1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            translate([0,0,h/2+.01])
            {
                screw_head(nut, orient=[0,0,1], align=[0,0,1]);
            }
            screw_thread(thread=thread, h=h+.1, tolerance=tolerance, orient=[0,0,1], align=[0,0,0]);

            if(with_nut)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut(nut=nut, tolerance=tolerance, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

module screw_cut(nut=MHexNutM3, h=10, tolerance=1.05, head_embed=false, with_nut=true, nut_offset=0, cut_access=true, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)*tolerance;
    thread = get(MHexNutThread, nut);

    s = threadsize*tolerance;
    total_h = h;
    size_align(size=[s, s, total_h], orient=-orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,head_embed?-head_h:0])
        {
            translate([0,0,h/2+.01])
            {
                screw_head_cut(nut, tolerance=1.25, override_h=1000, align=[0,0,1]);
            }
            screw_thread_cut(thread=thread, h=h+.1, tolerance=tolerance, align=[0,0,0]);

            if(with_nut)
            {
                translate([0,0,-h/2+nut_h+nut_offset+(head_embed?head_h:0)])
                screw_nut_cut(nut=nut, tolerance=tolerance, align=[0,0,-1]);
            }
        }
    }

    if($show_vit)
    {
        %screw(nut, h, tolerance, head_embed, with_nut, nut_offset, orient, align);
    }
}

module screw_thread(thread=ThreadM3, h=10, tolerance=1.00, orient=[0,0,1], align=[0,0,0])
{
    // TODO render thread
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize, h=h, orient=orient, align=align);
}

module screw_thread_cut(thread=ThreadM3, h=10, tolerance=1.05, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, thread[1]);
    cylindera(d=threadsize*tolerance, h=h, orient=orient, align=align);
}

module screw_head(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut);
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    difference()
    {
        cylindera(d=head_d, h = override_h==undef?head_h:override_h);
        translate([0,0,head_h/2])
        cylindera(d=threadsize, h = head_d/2);
    }
}

module screw_head_cut(nut=MHexNutM3, tolerance=1.05, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    head_d = get_screw_head_d(nut)*tolerance;
    size_align(size=[head_d, head_d, head_h], orient=orient, align=align)
    translate([0,0,-head_h/2])
    cylindera(d=head_d, h=override_h==undef?head_h:override_h, align=[0,0,1]);
}

module screw_nut(nut=MHexNutM3, tolerance=1.00, override_h=undef, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    facets = lookup(MHexNutFacets, nut);
    cylindera($fn=lookup(MHexNutFacets, nut), d=d, h=override_h==undef?thickness:override_h, orient=orient, align=align);
}

module screw_nut_cut(nut=MHexNutM3, tolerance=1.05, h=1000, orient=[0,0,1], align=[0,0,0])
{
    thickness = lookup(MHexNutThickness,nut)*tolerance;
    d = lookup(MHexNutWidthMin, nut)*tolerance;
    size_align(size=[d,d,thickness], orient=orient, align=align)
    {
        translate([0,0,thickness/2])
        {
            screw_nut(nut, tolerance, orient=[0,0,1], align=[0,0,-1]);
            translate([0,0,-thickness+.01])
            {
                cylindera(d=d*1.1, h=h, orient=[0,0,1], align=[0,0,-1]);
            }
        }
    }
}

module nut_trap_cut(nut=MHexNutM3, trap_offset=10, screw_l=10*mm, screw_l_extra=2*mm, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,1], align=[0,0,0])
{
    threadsize = lookup(ThreadSize, nut);
    head_h = get_screw_head_h(nut);
    nut_h = lookup(MHexNutThickness,nut)+.5*mm;
    thread = get(MHexNutThread, nut);

    nut_width_min = lookup(MHexNutWidthMin, nut)+.2*mm;
    nut_width_max = lookup(MHexNutWidthMax, nut)+.2*mm;
    s = nut_width_min;
    total_h = nut_h;

    size_align(size=[s, s, total_h], orient=orient, orient_ref=[0,0,1], align=align)
    {
        translate([0,0,nut_h/2-.1])
        screw_thread_cut(thread=thread, tolerance=1.1, h=screw_l, orient=[0,0,-1], align=[0,0,1]);

        if(screw_l_extra>0)
        translate([0,0,-nut_h/2+.1])
        screw_thread_cut(thread=thread, tolerance=1.1, h=screw_l_extra+.1, orient=[0,0,1], align=[0,0,-1]);

        hull()
        {
            orient(-orient)
            stack(dist=trap_h, axis=trap_axis)
            {
                orient(orient)
                cylindera($fn=lookup(MHexNutFacets, nut), d=nut_width_max, h=nut_h, align=[0,0,0]);

                orient(orient)
                cubea(size=[nut_width_min,nut_width_min,nut_h], align=[0,0,0]);
            }
        }

        if($show_vit)
        {
            translate([0,0, screw_l])
            translate([0,0, -nut_h/2])
            %screw(nut, tolerance=1, with_nut=false, orient=[0,0,-1], align=[0,0,-1]);

            %screw_nut(nut, tolerance=1, orient=[0,0,-1], align=[0,0,0]);
        }

    }

}

function get(key, dict) =
    let(x= search(MHexNutThread, MHexNutM3))
    dict[x[0]];

if(false)
{
    nut1 = MHexNutM3;
    nut2 = MHexNutM5;
    nut3 = MKnurlInsertNutM3_3_42;
    nut4 = MKnurlInsertNutM3_5_42;

    /*translate([0,20,0])*/
    /*translate([0,20,0])*/
    /*for(axis1=[0:len(AXES)-1])*/
    /*[>for(axis2=AXES)<]*/
    /*translate(20*AXES[axis1])*/
    /*{*/
        /*ta = v_rotate(90, AXES[axis1])*AXES[axis1];*/
        /*echo(AXES[axis1], ta);*/
        /*nut_trap_cut(nut=nut1, trap_axis=ta, orient=AXES[axis1]);*/
    /*}*/

    /*stack(d=30, axis=[1,0,0])*/
    /*{*/
        /*stack(d=20, axis=[0,1,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[1,0,0]);*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[-1,0,0]);*/
        /*}*/

        /*stack(d=20, axis=[1,0,0])*/
        /*{*/
            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,1,0]);*/

            /*nut_trap_cut(nut=nut1, trap_axis=[0,0,1], orient=[0,-1,0]);*/
        /*}*/
    /*}*/

    box_w = 100;
    box_h = 10;
    box_d = 10;
    o = 10;

    /*$show_vit = true;*/
    $fs= 0.5;
    $fa = 4;

    difference()
    {
        cubea([box_w,box_d/2,box_h], align=[1,1,1]);

        test_cuts();
    }
    /*difference()*/
    /*{*/
        /*cubea([box_w,box_d/2,box_h], align=[1,-1,1]);*/

        /*test_cuts();*/
    /*}*/

}

module test_cuts()
{
    union()
    {
        offset = 0;
        /*offset = -5;*/
        translate([0,offset,0])
        translate([5,0,0])
        stack(dist=10,axis=[1,0,0])
        {
            screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut1, h=box_h, head_embed=false, orient=[0,0,1], align=[0,0,1]);

            screw_cut(nut=nut1, h=box_h*mm, nut_offset=0*mm, head_embed=true, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut2, h=box_h*mm, nut_offset=3*mm, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut3, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);
            screw_cut(nut=nut4, h=box_h, head_embed=false, orient=[0,0,-1], align=[0,0,1]);

            /*translate([0,5,0])*/
            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,-1,0], orient=[0,0,-1], align=[0,0,0]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=5, head_embed=false, trap_h=10, trap_axis=[0,1,0], orient=[0,0,1], align=[0,0,0]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,1], orient=[0,1,0], align=[0,0,0]);

            translate([0,0,box_h/2])
                nut_trap_cut(nut=nut1, h=box_d, head_embed=false, trap_h=10, screw_l_extra=2*mm, trap_axis=[0,0,-1], orient=[0,1,0], align=[0,0,0]);
        }
    }
}


Clip for openbeam to hold bed isolation

Clip for openbeam to hold bed isolation

// render with wall 1.5
beam_size = 15;
beam_size_half = beam_size/2;

$fn=50;
// dependency: https://cdn.thingiverse.com/assets/95/99/30/ae/e4/TL-400-0101-001CLR_-_OpenBeam_1515_Extrusion_Clear_Anodized.STL
//color("green") translate([-beam_size_half,-beam_size,-1000]) import("TL-400-0101-001CLR_-_OpenBeam_1515_Extrusion_Clear_Anodized.stl");

opening = 0.4;

module negative() {
    module half() {
        offset(r=+0.5) offset(delta=-0.5) polygon([[10,0],[1.6,0],[1.6,1.4],[10,1.4]]);
        polygon([[2,1],[10,20],[10,1]]);
        polygon([[0,0],[opening,0],[0.6,1.7],[8.6,20.7],[0,20]]);
        offset(r=-0.5) offset(delta=0.5) polygon([[2.9,0],[2.9,4],[0,4.9],[0,20],[10,20],[10,0]]);
    }

    linear_extrude(height=1000, center=true) {
        half();
        mirror() half();
        polygon([[-opening,0],[opening,0],[0.7,-2],[0,-2]]);
    }
}

module clip(clip_width = 20) {
    module positive() {
        linear_extrude(height=clip_width, center=true) {
            polygon([[-beam_size_half,-2],[-beam_size_half,10],[beam_size_half,10],[beam_size_half,-2]]);

            translate([-1.5,-20]) square([1.5,20]);
            translate([0,-20]) rotate([0,0,-7]) translate([-1.5,0]) square([1.5,20]);
        }
    }
    difference() {
        positive();
        negative();
    }
}

module clips(count=6, clip_width=20) {
    for(a=[0:1:count-1]) {
        x = a * 7 + 1*(a%2);
        y = -a*3 + 30*(a%2);
        translate([x,y,0]) rotate([0,0,180+180 * (a % 2)]) clip();
    }
}

clips(1);

error: pathspec 'kossel/bed_isolation_clip.scad' did not match any file(s) known to git


Some documentation was added.

Some documentation was added.

use <../oval/oval.scad>
use <../triangle/triangle.scad>

/**
 *  This a fish.  I used the following thing as an example of how to do the main fish
 *  body:
 *
 *          https://www.thingiverse.com/thing:844015
 *
 */
module fish(bodyRadius = 7, height = 1)
{
	rotate([0, 0, 135])
	union()
	{
		// body
		cylinder(height,bodyRadius,bodyRadius);

		// head end
		translate([-bodyRadius,-bodyRadius,0])
		{
			cube([bodyRadius,bodyRadius,height]);
		}

		// back end
		cube([bodyRadius,bodyRadius,height]);

		// tail
		size = 6.00015;
		xTranslate = bodyRadius + 3;
		yTranslate = bodyRadius + 2;//radius * 2 + 1;
		translate([xTranslate, yTranslate, 0])
		triangle(size= size, height=2);
	}
}

module fishThumbnail()
{
	fish();
}

/** Support functions and modules follow **/

module fish_tail(radius)
{

}

use <../oval/oval.scad>
use <../triangle/triangle.scad>

module fish(bodyRadius = 7, height = 1)
{
	rotate([0, 0, 135])
	union()
	{
		// body
		cylinder(height,bodyRadius,bodyRadius);

		// head end
		translate([-bodyRadius,-bodyRadius,0])
		{
			cube([bodyRadius,bodyRadius,height]);
		}

		// back end
		cube([bodyRadius,bodyRadius,height]);

		// tail
		size = 6.00015;
		xTranslate = bodyRadius + 3;
		yTranslate = bodyRadius + 2;//radius * 2 + 1;
		translate([xTranslate, yTranslate, 0])
		triangle(size= size, height=2);
	}
}

module fishThumbnail()
{
	fish();
}

/** Support functions and modules follow **/

module fish_tail(radius)
{

}


new line added

new line added

module batteryAA()
{
  cylinder(h=48.5, r=14.5/2, $fs=0.1);
  translate([0,0, 48.5])
    cylinder(h=2, r=5.5/2, $fs=0.1);
}

module batteryAAA()
{
  cylinder(h=42.5, r=10.5/2, $fs=0.1);
  translate([0,0, 42.5])
    cylinder(h=1.5, r=4/2, $fs=0.1);
}

// just an exhibition - not used directly
translate([20,0,0])
  batteryAA();
translate([0,0,0])
  batteryAAA();


Delete LifeLoggingCameraV6.scad

Delete LifeLoggingCameraV6.scad

$fs = 0.1; // smoothness of curves in render
$fa = 0.1;

/* Box */
{
    thickness = 2; //wall thickness
    extraThickness = 0.1; // required for proper rendering when $fs is large
    curve = 4; // curve on the edges of the box, must be > thickness
    internalDimensions = [65, 65, 30]; //internal dimensions
    externalDimensions = [internalDimensions[0] + (thickness * 2), internalDimensions[1] + (thickness * 2), internalDimensions[2] + (thickness * 2)];
    bottomHeight = 28; // height of the bottom half of the box
    topHeight = internalDimensions[2] - bottomHeight; // height of the top half of the box
    FR4Thickness = 1.7;
    overlap = 3;
}
//

cameraHolePos = [externalDimensions[0] / 2, externalDimensions[1] / 2];
ledHolePos = [externalDimensions[2] / 2, externalDimensions[1] - (externalDimensions[2] / 2)];
usbHolePos = [-0.01, 31.25 + curve, thickness + FR4Thickness];
sdHolePos = [-0.01, 6.5 + curve, thickness + FR4Thickness];
resetHolePos = [externalDimensions[2] / 2, externalDimensions[1] - (thickness / 2), externalDimensions[2] / 3];
powerHolePos = [externalDimensions[0] * ((sqrt(5) - 1) / 2), externalDimensions[1] - (thickness / 2) - 0.5, externalDimensions[2] / 3];
usbSize = [21.5, 36, 7.2];
sdSize = [25, 31, 3.55];
resetHoleSize = 6;
powerHoleSize = [6.5, thickness + extraThickness + 1, 3.5];
ledHoleRad = 2.5;
cameraHoleRad = 3.7;
cameraStandoffHeight = 4;

{
    /*
loc =   [
            [externalDimensions[0] + 3 , 0, 0],
            [externalDimensions[0] + 3 , 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0], 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0], 0, 22 + (thickness * 2)],
            [externalDimensions[0], 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0] + 3 , 0, 22 + 5 + (thickness * 2)],
            [externalDimensions[0] + 3 , 0, 0],
            [externalDimensions[0] + 3 , 0, 0]
        ];

function xyz(t,i) =
    lookup(t, [
    [0/len(loc),loc[0][i]],
    [1/len(loc),loc[1][i]],
    [2/len(loc),loc[2][i]],
    [3/len(loc),loc[3][i]],
    [4/len(loc),loc[4][i]],
    [5/len(loc),loc[5][i]],
    [6/len(loc),loc[6][i]],
    [7/len(loc),loc[7][i]],

]);

loc2 =   [
            [0, 0, 0],
            [0, 0, 0],
            [0, -180, 0],
            [0, -180, 0],
            [0, -180, 0],
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]
        ];

function xyz2(t,i) =
    lookup(t, [
    [0/len(loc2),loc2[0][i]],
    [1/len(loc2),loc2[1][i]],
    [2/len(loc2),loc2[2][i]],
    [3/len(loc2),loc2[3][i]],
    [4/len(loc2),loc2[4][i]],
    [5/len(loc2),loc2[5][i]],
    [6/len(loc2),loc2[6][i]],
    [7/len(loc2),loc2[7][i]],

]);

loc3 =   [
            [0, 0, 0],
            [0, 0, 90],
            [0, 0, 180],
            [0, 0, 270],
            [0, 0, 360],
            [0, 0, 180],
            [0, 0, 0],
            [0, 0, 0]
        ];

function xyz3(t,i) =
    lookup(t, [
    [0/len(loc3),loc3[0][i]],
    [1/len(loc3),loc3[1][i]],
    [2/len(loc3),loc3[2][i]],
    [3/len(loc3),loc3[3][i]],
    [4/len(loc3),loc3[4][i]],
    [5/len(loc3),loc3[5][i]],
    [6/len(loc3),loc3[6][i]],
    [7/len(loc3),loc3[7][i]],

]);
*/
}
//

module cylinderHull(a, r)
{
    hull()
        {
            cylinder(r = r, h = a[2]);
            translate([a[0], 0, 0])
                cylinder(r = r, h = a[2]);
            translate([0, a[1], 0])
                cylinder(r = r, h = a[2]);
            translate([a[0], a[1], 0])
                cylinder(r = r, h = a[2]);
        }
}
//

module box(height, lip)
{
    // 0 = outer lip, 1 = inner lip
    translate([curve, curve, 0]) difference()
    {
        union()
        {
            cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), height + thickness], curve);
            if(lip == 1)
            {
                translate([0, 0, thickness])
                    cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), height + overlap],curve - (thickness / 2));
            }
        }
        {
            translate([0, 0, thickness])
                cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), height + thickness + overlap], curve - thickness);
            if(lip == 0)
            {
                translate([0, 0, height + thickness - overlap])
                    cylinderHull([externalDimensions[0] - (curve * 2), externalDimensions[1] - (curve * 2), 0.01 + overlap], curve - (thickness / 2));
            }
        }
    }
}
//

module bottom(height)
{
    difference()
    {
        union()
        {
            box(height, 0);
            if(thickness < 3)
            {
                translate([externalDimensions[0] * ((sqrt(5) - 1) / 2) - 9.5, externalDimensions[1] - 3, thickness])
                cube([19, 3 - thickness, height - overlap]);//power switch extra thickness
            }
            translate([usbHolePos[0] + thickness, usbHolePos[1] - ((usbSize[0] - 11) / 2), thickness])
            {
                translate([2.6, usbSize[0] - 2.6, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
                translate([2.6, 2.6, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
                translate([usbSize[1] - 2.25, usbSize[0] - 2 - 2.25, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
                translate([usbSize[1] - 2.25, 2 + 2.25, 0])
                {
                    cylinder(h = usbSize[2] - FR4Thickness, r = 2);
                    cylinder(h = usbSize[2], r = 1);
                }
            }
            translate([sdHolePos[0] + thickness, sdHolePos[1] - ((sdSize[0] - 14) / 2) - 1, thickness])
            {
                translate([2.575, sdSize[0] - 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
                translate([2.575, 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
                translate([sdSize[1] - 5.6 - 2.575, sdSize[0] - 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
                translate([sdSize[1] - 5.6 - 2.575, 2.575, 0])
                    cylinder(h = FR4Thickness, r = 0.8);
            }
            translate([powerHolePos[0], powerHolePos[1], powerHolePos[2]])
            {
                translate([-7.5, 0, 0])
                    rotate([90, 0, 0])
                        cylinder(h = 3, r = 0.8);
                translate([7.5, 0, 0])
                    rotate([90, 0, 0])
                        cylinder(h = 3, r = 0.8);
            }
        }
        {
            translate([usbHolePos[0], usbHolePos[1], usbHolePos[2]])
                cube([thickness + extraThickness, 11, 6]);//usb hole
            translate([sdHolePos[0], sdHolePos[1], sdHolePos[2]])
                cube([thickness + extraThickness, 14, 4]);//sd hole
            translate([resetHolePos[0], resetHolePos[1], resetHolePos[2]])
                cube([resetHoleSize, thickness + extraThickness, resetHoleSize], center = true);//reset switch hole
            translate([powerHolePos[0], powerHolePos[1], powerHolePos[2]])
                cube([powerHoleSize[0], powerHoleSize[1], powerHoleSize[2]], center = true);//power switch hole
            hull ()
            {
                translate([sdHolePos[0], sdHolePos[1] + (thickness / 2), sdHolePos[2]]) sphere(r = thickness / 2, center = true);
                translate([sdHolePos[0], sdHolePos[1] + 14 - (thickness / 2), sdHolePos[2]]) sphere(r = thickness / 2, center = true);
            }
            hull ()
            {
                translate([sdHolePos[0], sdHolePos[1] + (thickness / 2), sdHolePos[2] + 4]) sphere(r = thickness / 2, center = true);
                translate([sdHolePos[0], sdHolePos[1] + 14 - (thickness / 2), sdHolePos[2] + 4]) sphere(r = thickness / 2, center = true);
            }
            translate([0, 61 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([0, 54 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([65 + thickness, 61 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([65 + thickness, 54 + thickness, 15 + thickness])
                rotate([0, 90, 0])
                    cylinderHull([10, 0, thickness + extraThickness], 1);
            translate([usbHolePos[0] + thickness, usbHolePos[1] - ((usbSize[0] - 11) / 2), 0])
            {
                translate([7, usbSize[0] - 2.6, 0])
                {
                    cylinder(h = usbSize[2], r = 1.5);
                }
                translate([7, 2.6, 0])
                {
                    cylinder(h = usbSize[2], r = 1.5);
                }
                translate([usbSize[1] - 2.25, usbSize[0] - 2 - 2.25 + 4, 0])
                {
                    cylinder(h = usbSize[2], r = 1.5);
                }
            }
        }
    }
}
//

module top(height)
{
    difference()
    {
        union()
        {
            box(height, 1);
            translate([cameraHolePos[0], cameraHolePos[1], thickness])
            {
                translate([-8.5, 19.9, 0])// Top L
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
                translate([8.5, 19.9, 0])// Top R
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
                translate([-8.5, -5.5, 0])// Bottom L
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
                translate([8.5, -5.5, 0])// Bottom R
                {
                    cylinder(h = cameraStandoffHeight, r = 1.5);
                    cylinder(h = cameraStandoffHeight + FR4Thickness, r = 0.6);
                }
            }
        }
        {
            translate([cameraHolePos[0], cameraHolePos[1], -0.01])
                cylinder(r = cameraHoleRad, h = thickness + extraThickness);//camera hole
            translate([ledHolePos[0], ledHolePos[1], -0.01])
                cylinder(r = ledHoleRad, h = thickness + extraThickness);//led hole
        }
    }
}
//

bottom(bottomHeight);

//top(topHeight);

//translate([externalDimensions[0], 0, 22 + 2 + (thickness * 2)]) rotate([0,180,0]) top(topHeight);

//translate([xyz($t,0),xyz($t,1),xyz($t,2)]) rotate([xyz2($t,0),xyz2($t,1),xyz2($t,2)]) top(topHeight);

//translate([2, 4, 3]) cube([31, 25, 3.55]);//sd
//translate([2, 30, 3]) cube([36, 21.5, 7.2]);//usb


main: show xaxis idler holders

main: show xaxis idler holders

use <thing_libutils/metric-screw.scad>
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/transforms.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/linear-extrusion.scad>;
include <thing_libutils/timing-belts.scad>;

include <MCAD/stepper.scad>
include <MCAD/motors.scad>

/*include <extruder-direct.scad>*/
include <x-axis-end.scad>
include <x-carriage.scad>
include <y-axis-motor-mount.scad>
include <y-axis-carriage-bearing-mount.scad>
include <y-axis-carriage-belt-clamp.scad>
include <y-axis-idler.scad>
include <z-axis-motor-mount.scad>
use <gantry-upper-connector.scad>
use <gantry-lower-connector.scad>
include <psu.scad>
use <rod-clamps.scad>

/*use <scad-utils/trajectory.scad>*/
/*use <scad-utils/trajectory_path.scad>*/
/*use <scad-utils/transformations.scad>*/
/*use <scad-utils/shapes.scad>*/
/*use <list-comprehension-demos/skin.scad>*/

axis_range_x=[0*mm,200*mm];
axis_pos_x = axis_range_x[0];
axis_range_y=[0*mm,200*mm];
axis_pos_y = axis_range_y[0];
axis_range_z=[98*mm,353*mm];
axis_pos_z = axis_range_z[0];

echo(str("Build area Z: " , axis_range_z[1]-axis_range_z[0] , " mm"));

module x_axis()
{
    // x axis
    translate([0,0,axis_pos_z])
    {
        if(!preview_mode)
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(z=[-1,1])
            for(z=xaxis_beltpath_z_offsets)
            translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
            belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);
        }

        for(x=[-1,1])
        translate([axis_pos_x+x*148,0,0])
        {
            // x carriage
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])
            {
                x_carriage_withmounts(show_vitamins=true, beltpath_offset=x);

                x_carriage_extruder(show_vitamins=true, with_sensormount=x<=0);
            }
        }

        // x smooth rods
        color(color_rods)
        for(z=[-1,1])
            translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
                cylindera(h=xaxis_rod_l,d=xaxis_rod_d+.1, orient=[1,0,0]);

        for(x=[-1,1])
        {
            translate([x*(main_width/2), 0, 0])
            translate([0, xaxis_zaxis_distance_y, 0])
            translate([x*zmotor_mount_rod_offset_x, 0, 0])
            {
                mirror([max(0,x),0,0])
                xaxis_end(with_motor=true, beltpath_index=max(0,x), show_nut=true, show_motor=true, show_nut=true);

                translate([x*25, 0, 0])
                mirror([0,0,max(0,x)])
                mirror([max(0,x),0,0])
                xaxis_end_idlerholder();
            }
        }
    }
}

module y_axis()
{
    // y axis
    color(color_part)
    attach([[yaxis_belt_path_offset_x,main_depth/2,yaxis_motor_offset_z], [0,-1,0]], yaxis_motor_mount_conn)
    {
        yaxis_motor_mount(show_motor=true);
    }

    extrusion_idler_conn = [[yaxis_belt_path_offset_x, -main_depth/2-extrusion_size, -extrusion_size+yaxis_idler_offset_z], [0,-1,0]];
    attach(extrusion_idler_conn, yaxis_idler_conn)
    {
        color(color_part)
        yaxis_idler();

        attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)
        {
            color(color_part)
            yaxis_idler_pulleyblock(show_pulley=true);
        }
    }

    translate([yaxis_belt_path_offset_x,0,yaxis_belt_path_offset_z])
    {
        if(!preview_mode)
        {
            translate([0,main_depth/2-yaxis_motor_offset_x,0])
            {
                /*cubea([10,main_depth-yaxis_motor_offset_x,10], align=[0,-1,0]);*/
                belt_path(main_depth-yaxis_motor_offset_x-yaxis_idler_pulley_offset_y, 6, yaxis_pulley_inner_d, align=[0,-1,0], orient=[0,1,0]);
            }
        }
    }

    color(color_part)
    translate([0,-axis_pos_y,yaxis_bearing[0]/2])
    attach(yaxis_carriage_bearing_mount_conn_bearing, yaxis_belt_mount_conn)
    {
        yaxis_belt_holder();
    }

    translate([0,0,yaxis_bearing[0]/2])
    {
        for(x=[-1,1])
        for(y=[-1,1])
        {
            attach([[x*(yaxis_rod_distance/2),y*(main_depth/2+extrusion_size/2),0],[0,0,1]],mount_rod_clamp_conn_rod)
            {
                mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=zmotor_mount_clamp_thread, orient=[0,1,0]);
            }
        }

        // y smooth rods
        for(x=[-1,1])
        translate([x*(yaxis_rod_distance/2), 0, 0])
        {
            color(color_rods)
            cylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=[0,1,0]);

            for(y=[-1,1])
            {
                attach([[0,y*(yaxis_bearing_distance_y/2)-axis_pos_y,0],[0,0,-1]], yaxis_carriage_bearing_mount_conn_bearing)
                {
                    yaxis_carriage_bearing_mount(show_bearing=true, show_zips=true);
                }
            }
        }

        attach(yaxis_carriage_bearing_mount_conn_bearing, [[0,axis_pos_y,0],[0,0,1]])
        {
            /*translate([x*yaxis_carriage_size[0]/2, y*(yaxis_carriage_size[1]-16*mm)/2, 0])*/
            // y axis plate
            for(x=[-1,1])
            for(y=[-1,1])
            hull()
            {
                translate([x*yaxis_carriage_size[0]/2, y*(yaxis_carriage_size[1])/2, 0])
                {
                    cylindera(d=10*mm, h=yaxis_carriage_size[2], align=[-x,-y,1]);
                }
                translate([x*(yaxis_carriage_size[0]/2-16*mm), y*(yaxis_carriage_size[1]/2-16*mm), 0])
                {
                    cylindera(d=10*mm, h=yaxis_carriage_size[2], align=[-x,-y,1]);
                }
            }

            cubea([yaxis_carriage_size[0]-16*mm*2,yaxis_carriage_size[1]-16*mm*2, yaxis_carriage_size[2]], align=[0,0,1]);

            translate([0,0,10*mm])
                cubea(yaxis_carriage_size, align=[0,0,1]);
        }
    }

}

module z_axis()
{
    // z axis
    for(x=[-1,1])
    {
        translate([x*(main_width/2),0,main_height])
        {
            mirror([x==-1?1:0,0,0])
            {
                color(color_part)
                translate([zmotor_mount_rod_offset_x, 0, extrusion_size/2])
                {
                    mount_rod_clamp_half(
                            rod_d=zaxis_rod_d,
                            screw_dist=zmotor_mount_clamp_dist,
                            thick=5,
                            base_thick=5,
                            width=zmotor_mount_thickness_h,
                            thread=zmotor_mount_clamp_thread);
                }
            }
        }

        translate([x*(main_width/2), 0, 0])
        {
            translate([0,0,zaxis_motor_offset_z])
                mirror([x==-1?1:0,0,0])
                {
                    color(color_part)
                    zaxis_motor_mount(show_motor=true);

                    color(color_part)
                    translate([zmotor_mount_rod_offset_x, 0, zmotor_mount_thickness_h/2])
                    {
                        mount_rod_clamp_half(
                                rod_d=zaxis_rod_d,
                                screw_dist=zmotor_mount_clamp_dist,
                                thick=5,
                                base_thick=5,
                                width=zmotor_mount_thickness_h,
                                thread=zmotor_mount_clamp_thread);
                    }
                }

            // z smooth rods
            translate([x*(zmotor_mount_rod_offset_x),0,0])
            {
                // z rods
                color(color_rods)
                translate([0,0,zaxis_motor_offset_z-50])
                    cylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=[0,0,1]);

                for(z=[-1,1])
                    translate([0,0,axis_pos_z-z*xaxis_rod_distance/2])
                        bearing(zaxis_bearing);

            }
        }
    }

}

module main()
{
    translate([0,0,-main_lower_dist_z/2])
    gantry_lower();

    gantry_upper();

    x_axis();
    y_axis();
    z_axis();

    if(!preview_mode)
    {
        for(x=[-1,1])
        translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
        {
            translate([-x*psu_a_w/2, -psu_a_d/2, psu_a_h/2])
            {
                psu_a();

                mirror([x==-1?1:0,0,0])
                    translate([0, -psu_a_screw_dist_y/2, 0])
                    psu_a_extrusion_bracket_side();

                translate([0, psu_a_screw_dist_y/2, 0])
                    psu_a_extrusion_bracket_back();
            }
        }

        translate([0,-main_depth/2,-main_lower_dist_z-extrusion_size])
            translate([-100,100,0])
            rotate([0,0,270])
            import("stl/RAMPS1_4.STL");
    }
}

module gantry_upper()
{
    color(color_extrusion)
    for(y=[-1,1])
    translate([0,y*(main_upper_dist_y/2),0])
    {
        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        {
            if(preview_mode)
            {
                cubea(size=[extrusion_size, extrusion_size, main_height], align=[-x,0,1]);
            }
            else
            {
                linear_extrusion(h=main_height, align=[-x,0,1], orient=[0,0,1]);
            }
        }

        translate([0, 0, main_height])
        {
            if(preview_mode)
            {
                cubea(size=[main_upper_width, extrusion_size, extrusion_size], align=[0,0,1]);
            }
            else
            {
                linear_extrusion(h=main_upper_width, align=[0,0,1], orient=[1,0,0]);
            }
        }
    }

    // upper gantry connectors
    for(x=[-1,1])
    {
        translate([x*(main_width/2),0,main_height])
        {
            mirror([x==-1?1:0,0,0])
            {
                color(color_gantry_connectors)
                    gantry_upper_connector();
            }

        }
    }
}

module gantry_lower()
{
    color(color_extrusion)
    for(z=[-1,1])
    {
        translate([0,0,z*-main_lower_dist_z/2])
        {
            for(y=[-1,1])
            translate([0, y*(main_depth/2), 0])
            {
                if(preview_mode)
                {
                    cubea([main_width, extrusion_size, extrusion_size], align=[0,y,-1]);
                }
                else
                {
                    linear_extrusion(h=main_width, align=[0,y,-1], orient=[1,0,0]);
                }
            }

            for(x=[-1,1])
            translate([x*(main_width/2), 0, 0])
            {
                if(preview_mode)
                {
                    cubea([extrusion_size, main_depth, extrusion_size], align=[-x,0,-1]);
                }
                else
                {
                    linear_extrusion(h=main_depth, align=[-x,0,-1], orient=[0,1,0]);
                }
            }
        }

    }

    // lower gantry connectors
    for(x=[-1,1])
    for(y=[-1,1])
    {
        translate([x*(main_width/2),y*(main_depth/2),-extrusion_size/2])
        {
            mirror([x==1?0:-1,0,0])
            mirror([0,y==1?1:0,0])
            {
                color(color_gantry_connectors)
                    gantry_lower_connector();
            }

        }
    }
}

module enclosure()
{
    w=60*cm;
    h=60*cm;
    d=60*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

    translate([0, 0, h/2])
    {
        // left/right walls
        for(x=[-1,1])
            translate([x*w/2,0,0])
                cubea([wallthick,d,h], align=[-x, 0, 0]);

        // back plate
        translate([0,d/2,0])
            cubea([w,backthick,h], align=[0,-1, 0]);

        // top/bottom plate
        for(z=[-1,1])
        translate([0,0,z*h/2])
            cubea([w-wallthick*2,d,wallthick], align=[0,0, -z]);
    }
}

translate([0, 0, main_lower_dist_z+extrusion_size*2])
main();

/*psu();*/

/*%enclosure();*/

use <thing_libutils/metric-screw.scad>
use <thing_libutils/shapes.scad>;
use <thing_libutils/misc.scad>;
use <thing_libutils/transforms.scad>;
use <thing_libutils/attach.scad>;
use <thing_libutils/linear-extrusion.scad>;
include <thing_libutils/timing-belts.scad>;

include <MCAD/stepper.scad>
include <MCAD/motors.scad>

/*include <extruder-direct.scad>*/
include <x-axis-end.scad>
include <x-carriage.scad>
include <y-axis-motor-mount.scad>
include <y-axis-carriage-bearing-mount.scad>
include <y-axis-carriage-belt-clamp.scad>
include <y-axis-idler.scad>
include <z-axis-motor-mount.scad>
use <gantry-upper-connector.scad>
use <gantry-lower-connector.scad>
include <psu.scad>
use <rod-clamps.scad>

/*use <scad-utils/trajectory.scad>*/
/*use <scad-utils/trajectory_path.scad>*/
/*use <scad-utils/transformations.scad>*/
/*use <scad-utils/shapes.scad>*/
/*use <list-comprehension-demos/skin.scad>*/

axis_range_x=[0*mm,200*mm];
axis_pos_x = axis_range_x[0];
axis_range_y=[0*mm,200*mm];
axis_pos_y = axis_range_y[0];
axis_range_z=[98*mm,353*mm];
axis_pos_z = axis_range_z[0];

echo(str("Build area Z: " , axis_range_z[1]-axis_range_z[0] , " mm"));

module x_axis()
{
    // x axis
    translate([0,0,axis_pos_z])
    {
        if(!preview_mode)
        {
            zrod_offset = zmotor_mount_rod_offset_x;
            for(z=[-1,1])
            for(z=xaxis_beltpath_z_offsets)
            translate([-main_width/2-zrod_offset+xaxis_end_motor_offset[0], xaxis_zaxis_distance_y, z])
            belt_path(main_width+2*(zrod_offset)+xaxis_end_motor_offset[0], 6, xaxis_pulley_inner_d, orient=[1,0,0], align=[1,0,0]);
        }

        for(x=[-1,1])
        translate([axis_pos_x+x*148,0,0])
        {
            // x carriage
            attach(xaxis_carriage_conn, [[0,-xaxis_zaxis_distance_y,0],[0,0,0]])
            {
                x_carriage_withmounts(show_vitamins=true, beltpath_offset=x);

                x_carriage_extruder(show_vitamins=true, with_sensormount=x<=0);
            }
        }

        // x smooth rods
        color(color_rods)
        for(z=[-1,1])
            translate([xaxis_rod_offset_x,xaxis_zaxis_distance_y,z*(xaxis_rod_distance/2)])
                cylindera(h=xaxis_rod_l,d=xaxis_rod_d+.1, orient=[1,0,0]);

        for(x=[-1,1])
        {
            translate([x*(main_width/2), 0, 0])
            {
                translate([0, xaxis_zaxis_distance_y, 0])
                translate([x*zmotor_mount_rod_offset_x, 0, 0])
                mirror([max(0,x),0,0])
                xaxis_end(with_motor=true, beltpath_index=max(0,x), show_nut=true, show_motor=true, show_nut=true);
            }
        }
    }
}

module y_axis()
{
    // y axis
    color(color_part)
    attach([[yaxis_belt_path_offset_x,main_depth/2,yaxis_motor_offset_z], [0,-1,0]], yaxis_motor_mount_conn)
    {
        yaxis_motor_mount(show_motor=true);
    }

    extrusion_idler_conn = [[yaxis_belt_path_offset_x, -main_depth/2-extrusion_size, -extrusion_size+yaxis_idler_offset_z], [0,-1,0]];
    attach(extrusion_idler_conn, yaxis_idler_conn)
    {
        color(color_part)
        yaxis_idler();

        attach(yaxis_idler_conn_pulleyblock, yaxis_idler_pulleyblock_conn)
        {
            color(color_part)
            yaxis_idler_pulleyblock(show_pulley=true);
        }
    }

    translate([yaxis_belt_path_offset_x,0,yaxis_belt_path_offset_z])
    {
        if(!preview_mode)
        {
            translate([0,main_depth/2-yaxis_motor_offset_x,0])
            {
                /*cubea([10,main_depth-yaxis_motor_offset_x,10], align=[0,-1,0]);*/
                belt_path(main_depth-yaxis_motor_offset_x-yaxis_idler_pulley_offset_y, 6, yaxis_pulley_inner_d, align=[0,-1,0], orient=[0,1,0]);
            }
        }
    }

    color(color_part)
    translate([0,-axis_pos_y,yaxis_bearing[0]/2])
    attach(yaxis_carriage_bearing_mount_conn_bearing, yaxis_belt_mount_conn)
    {
        yaxis_belt_holder();
    }

    translate([0,0,yaxis_bearing[0]/2])
    {
        for(x=[-1,1])
        for(y=[-1,1])
        {
            attach([[x*(yaxis_rod_distance/2),y*(main_depth/2+extrusion_size/2),0],[0,0,1]],mount_rod_clamp_conn_rod)
            {
                mount_rod_clamp_full(rod_d=zaxis_rod_d, thick=4, width=extrusion_size, thread=zmotor_mount_clamp_thread, orient=[0,1,0]);
            }
        }

        // y smooth rods
        for(x=[-1,1])
        translate([x*(yaxis_rod_distance/2), 0, 0])
        {
            color(color_rods)
            cylindera(h=yaxis_rod_l,d=yaxis_rod_d, orient=[0,1,0]);

            for(y=[-1,1])
            {
                attach([[0,y*(yaxis_bearing_distance_y/2)-axis_pos_y,0],[0,0,-1]], yaxis_carriage_bearing_mount_conn_bearing)
                {
                    yaxis_carriage_bearing_mount(show_bearing=true, show_zips=true);
                }
            }
        }

        attach(yaxis_carriage_bearing_mount_conn_bearing, [[0,axis_pos_y,0],[0,0,1]])
        {
            /*translate([x*yaxis_carriage_size[0]/2, y*(yaxis_carriage_size[1]-16*mm)/2, 0])*/
            // y axis plate
            for(x=[-1,1])
            for(y=[-1,1])
            hull()
            {
                translate([x*yaxis_carriage_size[0]/2, y*(yaxis_carriage_size[1])/2, 0])
                {
                    cylindera(d=10*mm, h=yaxis_carriage_size[2], align=[-x,-y,1]);
                }
                translate([x*(yaxis_carriage_size[0]/2-16*mm), y*(yaxis_carriage_size[1]/2-16*mm), 0])
                {
                    cylindera(d=10*mm, h=yaxis_carriage_size[2], align=[-x,-y,1]);
                }
            }

            cubea([yaxis_carriage_size[0]-16*mm*2,yaxis_carriage_size[1]-16*mm*2, yaxis_carriage_size[2]], align=[0,0,1]);

            translate([0,0,10*mm])
                cubea(yaxis_carriage_size, align=[0,0,1]);
        }
    }

}

module z_axis()
{
    // z axis
    for(x=[-1,1])
    {
        translate([x*(main_width/2),0,main_height])
        {
            mirror([x==-1?1:0,0,0])
            {
                color(color_part)
                translate([zmotor_mount_rod_offset_x, 0, extrusion_size/2])
                {
                    mount_rod_clamp_half(
                            rod_d=zaxis_rod_d,
                            screw_dist=zmotor_mount_clamp_dist,
                            thick=5,
                            base_thick=5,
                            width=zmotor_mount_thickness_h,
                            thread=zmotor_mount_clamp_thread);
                }
            }
        }

        translate([x*(main_width/2), 0, 0])
        {
            translate([0,0,zaxis_motor_offset_z])
                mirror([x==-1?1:0,0,0])
                {
                    color(color_part)
                    zaxis_motor_mount(show_motor=true);

                    color(color_part)
                    translate([zmotor_mount_rod_offset_x, 0, zmotor_mount_thickness_h/2])
                    {
                        mount_rod_clamp_half(
                                rod_d=zaxis_rod_d,
                                screw_dist=zmotor_mount_clamp_dist,
                                thick=5,
                                base_thick=5,
                                width=zmotor_mount_thickness_h,
                                thread=zmotor_mount_clamp_thread);
                    }
                }

            // z smooth rods
            translate([x*(zmotor_mount_rod_offset_x),0,0])
            {
                // z rods
                color(color_rods)
                translate([0,0,zaxis_motor_offset_z-50])
                    cylindera(h=zaxis_rod_l,d=zaxis_rod_d, align=[0,0,1]);

                for(z=[-1,1])
                    translate([0,0,axis_pos_z-z*xaxis_rod_distance/2])
                        bearing(zaxis_bearing);

            }
        }
    }

}

module main()
{
    translate([0,0,-main_lower_dist_z/2])
    gantry_lower();

    gantry_upper();

    x_axis();
    y_axis();
    z_axis();

    if(!preview_mode)
    {
        for(x=[-1,1])
        translate([x*(main_width/2-extrusion_size),main_depth/2,-main_lower_dist_z-extrusion_size])
        {
            translate([-x*psu_a_w/2, -psu_a_d/2, psu_a_h/2])
            {
                psu_a();

                mirror([x==-1?1:0,0,0])
                    translate([0, -psu_a_screw_dist_y/2, 0])
                    psu_a_extrusion_bracket_side();

                translate([0, psu_a_screw_dist_y/2, 0])
                    psu_a_extrusion_bracket_back();
            }
        }

        translate([0,-main_depth/2,-main_lower_dist_z-extrusion_size])
            translate([-100,100,0])
            rotate([0,0,270])
            import("stl/RAMPS1_4.STL");
    }
}

module gantry_upper()
{
    color(color_extrusion)
    for(y=[-1,1])
    translate([0,y*(main_upper_dist_y/2),0])
    {
        for(x=[-1,1])
        translate([x*(main_width/2), 0, 0])
        {
            if(preview_mode)
            {
                cubea(size=[extrusion_size, extrusion_size, main_height], align=[-x,0,1]);
            }
            else
            {
                linear_extrusion(h=main_height, align=[-x,0,1], orient=[0,0,1]);
            }
        }

        translate([0, 0, main_height])
        {
            if(preview_mode)
            {
                cubea(size=[main_upper_width, extrusion_size, extrusion_size], align=[0,0,1]);
            }
            else
            {
                linear_extrusion(h=main_upper_width, align=[0,0,1], orient=[1,0,0]);
            }
        }
    }

    // upper gantry connectors
    for(x=[-1,1])
    {
        translate([x*(main_width/2),0,main_height])
        {
            mirror([x==-1?1:0,0,0])
            {
                color(color_gantry_connectors)
                    gantry_upper_connector();
            }

        }
    }
}

module gantry_lower()
{
    color(color_extrusion)
    for(z=[-1,1])
    {
        translate([0,0,z*-main_lower_dist_z/2])
        {
            for(y=[-1,1])
            translate([0, y*(main_depth/2), 0])
            {
                if(preview_mode)
                {
                    cubea([main_width, extrusion_size, extrusion_size], align=[0,y,-1]);
                }
                else
                {
                    linear_extrusion(h=main_width, align=[0,y,-1], orient=[1,0,0]);
                }
            }

            for(x=[-1,1])
            translate([x*(main_width/2), 0, 0])
            {
                if(preview_mode)
                {
                    cubea([extrusion_size, main_depth, extrusion_size], align=[-x,0,-1]);
                }
                else
                {
                    linear_extrusion(h=main_depth, align=[-x,0,-1], orient=[0,1,0]);
                }
            }
        }

    }

    // lower gantry connectors
    for(x=[-1,1])
    for(y=[-1,1])
    {
        translate([x*(main_width/2),y*(main_depth/2),-extrusion_size/2])
        {
            mirror([x==1?0:-1,0,0])
            mirror([0,y==1?1:0,0])
            {
                color(color_gantry_connectors)
                    gantry_lower_connector();
            }

        }
    }
}

module enclosure()
{
    w=60*cm;
    h=60*cm;
    d=60*cm;
    wallthick=2*cm;
    backthick=0.5*cm;

    translate([0, 0, h/2])
    {
        // left/right walls
        for(x=[-1,1])
            translate([x*w/2,0,0])
                cubea([wallthick,d,h], align=[-x, 0, 0]);

        // back plate
        translate([0,d/2,0])
            cubea([w,backthick,h], align=[0,-1, 0]);

        // top/bottom plate
        for(z=[-1,1])
        translate([0,0,z*h/2])
            cubea([w-wallthick*2,d,wallthick], align=[0,0, -z]);
    }
}

translate([0, 0, main_lower_dist_z+extrusion_size*2])
main();

/*psu();*/

/*%enclosure();*/


mount itself

mount itself

error: pathspec 'table_top_to_cabinet_mounting/mount.scad' did not match any file(s) known to git


Added bracket for dc inverter for AS

Added bracket for dc inverter for AS

FFF=[false,false,false];FFT=[false,false,true];
FTF=[false,true,false];FTT=[false,true,true];
TFF=[true,false,false];TFT=[true,false,true];
TTF=[true,true,false];TTT=[true,true,true];
module cube2(size, center) {
  translate([
    center[0] ? -size[0]/2 : 0,
    center[1] ? -size[1]/2 : 0,
    center[2] ? -size[2]/2 : 0]) cube(size);
}
module mirror_x() {
  for(a=[0,1])mirror([a,0,0])children();
}
module mirror_y() {
  for(a=[0,1])mirror([0,a,0])children();
}
module mirror_z() {
  for(a=[0,1])mirror([0,0,a])children();
}

holes_x=180;
holes_y=32;
holed_d=6.2;
difference() {
    union() mirror_y() {
        for(a=[0,1])translate([holes_x*a+10,holes_y/2]) cylinder(d=16,h=9);
        cube2([36,50,17],FTF);
        cube2([45,50,9],FTF);
        translate([50,94/2])cube2([130,10,9],FTF);
        translate([holes_x+10,0])cube2([16,50,9],TTF);
        hull() {
            translate([170,94/2+4])cube2([16,1,9],FFF);
            translate([holes_x+10,24])cube2([16,1,9],TTF);
        }
        hull() {
            translate([50,94/2+4])cube2([16,1,9],FFF);
            translate([36,24])cube2([16,1,9],TTF);
        }
    }
    mirror_y() {
        for(a=[0,1])translate([holes_x*a+10,holes_y/2]) {
           cylinder(d=6.2,h=30,center=true,$fn=24);
           translate([0,0,4])rotate([0,0,30])cylinder(d=10*2/sqrt(3),h=30,$fn=6);
        }
        translate([0,94/2,6])cube2([500,5,10],TTF);
        for(a=[62,171])translate([a,0]) {
            cube2([5,200,4],TTT);
            translate([0,0,7])cube2([5,200,4],TTF);
        }
    }
}

error: pathspec 'small/dc_inverter_bracket.scad' did not match any file(s) known to git


Update 3D_printed_parts/threads.scad

Update 3D_printed_parts/threads.scad

/*
 * Dan Kirshner - dan_kirshner@yahoo.com
 *
 * You are welcome to make free use of this software.  Retention of my
 * authorship credit would be appreciated.
 *
 * Version 1.3.  2013-12-01   Correct loop over turns -- don't have early cut-off
 * Version 1.2.  2012-09-09   Use discrete polyhedra rather than linear_extrude()
 * Version 1.1.  2012-09-07   Corrected to right-hand threads!
 */

// Examples:
//metric_thread(8, 1, 10);
//english_thread(1/4, 20, 1);

// Rohloff hub thread:
//metric_thread(34, 1, 10, internal=true, n_starts=6);

//metric_thread(8, 2, 4);

// ----------------------------------------------------------------------------
pi = 3.14159265;

// ----------------------------------------------------------------------------
function segments(diameter) = min(50, ceil(diameter*6));

// ----------------------------------------------------------------------------
// internal - true = clearances for internal thread (e.g., a nut).
//            false = clearances for external thread (e.g., a bolt).
//            (Internal threads should be "cut out" from a solid using
//            difference()).
// n_starts - Number of thread starts (e.g., DNA, a "double helix," has
//            n_starts=2).  See wikipedia Screw_thread.
module metric_thread(diameter=8, pitch=1, length=1, internal=false, n_starts=1)
{
   // Number of turns needed.
   n_turns = floor(length/pitch);
   n_segments = segments(diameter);
   h = pitch * cos(30);

   union() {
      intersection() {
         // Start one below z = 0.  Gives an extra turn at each end.
         for (i=[-1*n_starts : n_turns+1]) {
            translate([0, 0, i*pitch]) {
               metric_thread_turn(diameter, pitch, internal, n_starts);
            }
         }

         // Cut to length.
         translate([0, 0, length/2]) {
            cube([diameter*1.1, diameter*1.1, length], center=true);
         }
      }

      // Solid center, including Dmin truncation.
      if (internal) {
         cylinder(r=diameter/2 - h*5/8, h=length, $fn=n_segments);
      } else {

         // External thread includes additional relief.
         cylinder(r=diameter/2 - h*5.3/8, h=length, $fn=n_segments);
      }
   }
}

// ----------------------------------------------------------------------------
// Input units in inches.
// Note: units of measure in drawing are mm!
module english_thread(diameter=0.25, threads_per_inch=20, length=1,
                      internal=false, n_starts=1)
{
   // Convert to mm.
   mm_diameter = diameter*25.4;
   mm_pitch = (1.0/threads_per_inch)*25.4;
   mm_length = length*25.4;

   echo(str("mm_diameter: ", mm_diameter));
   echo(str("mm_pitch: ", mm_pitch));
   echo(str("mm_length: ", mm_length));
   metric_thread(mm_diameter, mm_pitch, mm_length, internal, n_starts);
}

// ----------------------------------------------------------------------------
module metric_thread_turn(diameter, pitch, internal, n_starts)
{
   n_segments = segments(diameter);
   fraction_circle = 1.0/n_segments;
   for (i=[0 : n_segments-1]) {
      rotate([0, 0, i*360*fraction_circle]) {
         translate([0, 0, i*n_starts*pitch*fraction_circle]) {
            thread_polyhedron(diameter/2, pitch, internal, n_starts);
         }
      }
   }
}

// ----------------------------------------------------------------------------
// z (see diagram) as function of current radius.
// (Only good for first half-pitch.)
function z_fct(current_radius, radius, pitch)
   = 0.5*(current_radius - (radius - 0.875*pitch*cos(30)))
                                                       /cos(30);

// ----------------------------------------------------------------------------
module thread_polyhedron(radius, pitch, internal, n_starts)
{
   n_segments = segments(radius*2);
   fraction_circle = 1.0/n_segments;

   h = pitch * cos(30);
   outer_r = radius + (internal ? h/20 : 0); // Adds internal relief.
   //echo(str("outer_r: ", outer_r));

   inner_r = radius - 0.875*h; // Does NOT do Dmin_truncation - do later with
                               // cylinder.

   // Make these just slightly bigger (keep in proportion) so polyhedra will
   // overlap.
   x_incr_outer = outer_r * fraction_circle * 2 * pi * 1.005;
   x_incr_inner = inner_r * fraction_circle * 2 * pi * 1.005;
   z_incr = n_starts * pitch * fraction_circle * 1.005;

   /*
    (angles x0 and x3 inner are actually 60 deg)

                          /\  (x2_inner, z2_inner) [2]
                         /  \
   (x3_inner, z3_inner) /    \
                  [3]   \     \
                        |\     \ (x2_outer, z2_outer) [6]
                        | \    /
                        |  \  /|
             z          |   \/ / (x1_outer, z1_outer) [5]
             |          |   | /
             |   x      |   |/
             |  /       |   / (x0_outer, z0_outer) [4]
             | /        |  /     (behind: (x1_inner, z1_inner) [1]
             |/         | /
    y________|          |/
   (r)                  / (x0_inner, z0_inner) [0]

   */

   x1_outer = outer_r * fraction_circle * 2 * pi;

   z0_outer = z_fct(outer_r, radius, pitch);
   //echo(str("z0_outer: ", z0_outer));

   //polygon([[inner_r, 0], [outer_r, z0_outer],
   //        [outer_r, 0.5*pitch], [inner_r, 0.5*pitch]]);
   z1_outer = z0_outer + z_incr;

   // Rule for triangle ordering: look at polyhedron from outside: points must
   // be in clockwise order.
   polyhedron(
      points = [
                [-x_incr_inner/2, -inner_r, 0],                                    // [0]
                [x_incr_inner/2, -inner_r, z_incr],                    // [1]
                [x_incr_inner/2, -inner_r, pitch + z_incr],            // [2]
                [-x_incr_inner/2, -inner_r, pitch],                                // [3]

                [-x_incr_outer/2, -outer_r, z0_outer],                             // [4]
                [x_incr_outer/2, -outer_r, z0_outer + z_incr],         // [5]
                [x_incr_outer/2, -outer_r, pitch - z0_outer + z_incr], // [6]
                [-x_incr_outer/2, -outer_r, pitch - z0_outer]                      // [7]
               ],

      triangles = [
                [0, 3, 4],  // This-side trapezoid, bottom
                [3, 7, 4],  // This-side trapezoid, top

                [1, 5, 2],  // Back-side trapezoid, bottom
                [2, 5, 6],  // Back-side trapezoid, top

                [0, 1, 2],  // Inner rectangle, bottom
                [0, 2, 3],  // Inner rectangle, top

                [4, 6, 5],  // Outer rectangle, bottom
                [4, 7, 6],  // Outer rectangle, top

                [7, 2, 6],  // Upper rectangle, bottom
                [7, 3, 2],  // Upper rectangle, top

                [0, 5, 1],  // Lower rectangle, bottom
                [0, 4, 5]   // Lower rectangle, top
               ]
   );
}

error: pathspec '3D_printed_parts/threads.scad' did not match any file(s) known to git