config: remove zaxis rod offset in X

config: remove zaxis rod offset in X

include <thing_libutils/units.scad>
include <thing_libutils/system.scad>
include <thing_libutils/bearing_data.scad>
include <thing_libutils/pulley.scad>
include <thing_libutils/bearing-linear-data.scad>
/*include <thing_libutils/thread-data.scad>*/
include <thing_libutils/nut-data.scad>
include <thing_libutils/timing-belts-data.scad>
include <thing_libutils/stepper-data.scad>

use <thing_libutils/misc.scad>

e=0.01*mm;

// high quality etc
is_build = false;

// minimum size of a fragment
// resolution of any round object (segment length)
// Because of this variable very small circles have a smaller number of fragments than specified using $fa.
// The default value is 2.
$fs = is_build ? 0.5 : 1;

// minimum angle for a fragment.
// The default value is 12 (i.e. 30 fragments for a full circle)
$fa = is_build ? 4 : 16;

$show_vit = is_build ? false : true;

// enable preview model (faster openscad)
$preview_mode = is_build ? false : true;

extrusion_height            = 0.4*mm;

// width of a single wall, should match your slicer settings
extrusion_width             = 0.4*mm;

// how many lines should a normal wall have (i.e. 0.6(extrusion_width)*6(normal_wall_factor)= 3.6mm wall width)
normal_wall_factor          = 3;

thick_wall_factor           = 4;

// diameter of your filament.
filament_d                  = 1.75*mm;
filament_r                  = filament_d/2;
Mat_filament = Mat_PlasticBlack;

main_width = 420*mm;
main_depth = 420*mm;
main_height = 400*mm;
main_upper_width = 500*mm;

extrusion_size = 20*mm;
extrusion_thread = ThreadM5;
extrusion_thread_dia = lookup(ThreadSize, extrusion_thread);
extrusion_nut = NutHexM5;
extrusion_nut_dia = lookup(NutWidthMax, extrusion_nut);

extrusion_mount_thread = ThreadM4;

// for tapped ends
extrusion_end_nut = NutHexM6;

main_lower_dist_z = 80*mm;
main_upper_dist_y = 160*mm;

gantry_connector_thickness = 5;
gantry_upper_offset_y = -25;

rod_fit_tolerance=1.01;

ziptie_type = [2.5*mm, 3*mm];
ziptie_thickness = ziptie_type[0];
ziptie_width = ziptie_type[1]+0.6*mm;
ziptie_bearing_distance = 3*mm;

xaxis_rod_distance = 65*mm;
xaxis_rod_d = 9.975*mm;
xaxis_rod_l = 500*mm;
// relative to entire machine
xaxis_rod_offset_x = 0*mm;
xaxis_bearings_top=1;
xaxis_bearings_bottom=1;
xaxis_bearing_top = LinearBearingLM10L;
xaxis_bearing_bottom = LinearBearingLM10;;

xaxis_pulley = pulley_2GT_20T;
xaxis_pulley_inner_d = xaxis_pulley[2];
xaxis_pulley_outer_d = xaxis_pulley[3];
xaxis_idler_pulley = pulley_2GT_20T_idler;
xaxis_idler_pulley_inner_d = xaxis_idler_pulley[2];
xaxis_idler_pulley_outer_d = xaxis_idler_pulley[3];

xaxis_belt = TimingBelt_GT2_2;
xaxis_belt_width = 6*mm;
xaxis_beltpath_width = max(xaxis_belt_width+3*mm, xaxis_pulley[0]+2*mm);
xaxis_beltpath_z_offset_pulley = xaxis_pulley_inner_d/2;
/*xaxis_beltpath_z_offsets = [xaxis_beltpath_z_offset_pulley];*/
xaxis_beltpath_z_offsets = [-3*mm-xaxis_beltpath_z_offset_pulley, 3*mm+xaxis_beltpath_z_offset_pulley];
xaxis_beltpath_height_body = xaxis_pulley_outer_d/2+3*mm+v_sum(v_abs(xaxis_beltpath_z_offsets))+5*mm;
xaxis_beltpath_height_holders = max(xaxis_pulley_outer_d+2*mm, xaxis_pulley_inner_d+xaxis_beltpath_z_offsets[0]+3*mm);

xaxis_carriage_bearing_offset_y = ziptie_thickness+3*mm;
xaxis_carriage_beltpath_offset_y = xaxis_carriage_bearing_offset_y+get(LinearBearingOuterDiameter, xaxis_bearing_top)/2;

xaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);
xaxis_motor_thread=ThreadM3;
xaxis_motor_nut=NutHexM3;

xaxis_endstop_type = "SWITCH";
/*xaxis_endstop_type = "SN04";*/

yaxis_rod_distance = 170*mm;
yaxis_rod_d = 11.975*mm;
yaxis_rod_l = 500*mm;
yaxis_bearing = LinearBearingLM12;
yaxis_bearing_distance_y = 7*cm;

yaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);

yaxis_pulley = pulley_2GT_20T;
yaxis_pulley_inner_d = yaxis_pulley[2];
ymotor_mount_thickness = 5;
ymotor_mount_thickness_h = 5;
yaxis_motor_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;

yaxis_belt = TimingBelt_GT2_2;
yaxis_belt_width = 6*mm;
yaxis_belt_path_offset_x = -yaxis_pulley_inner_d/2;
yaxis_belt_path_offset_z = 5*mm;

yaxis_motor_offset_z = yaxis_belt_path_offset_z - 10*mm;

yaxis_idler_pulley = pulley_2GT_20T_idler;
yaxis_idler_pulley_inner_d = yaxis_idler_pulley[2];
yaxis_idler_pulley_outer_d = yaxis_idler_pulley[3];
yaxis_idler_pulley_h = yaxis_idler_pulley[0];
yaxis_idler_mount_thickness = 5;
yaxis_idler_pulley_tight_len = 10*mm;
yaxis_idler_pulley_offset_y = yaxis_idler_mount_thickness + yaxis_pulley_inner_d/2 + yaxis_idler_pulley_tight_len;
yaxis_idler_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_idler_offset_z = 10*mm;

yaxis_carriage_offset =
    Z*get(LinearBearingInnerDiameter, yaxis_bearing)/2;

zaxis_rod_d = 11.975*mm;
zaxis_rod_l = 500*mm;
// relative to entire machine
zaxis_rod_offset = [0,0*mm,0];
zaxis_bearing = LinearBearingLMH12L;
zaxis_bearing_ID=get(LinearBearingInnerDiameter,zaxis_bearing);
zaxis_bearing_OD=get(LinearBearingOuterDiameter,zaxis_bearing);
zaxis_bearing_L=get(LinearBearingLength,zaxis_bearing);

// Nema17 motor w/340mm long 8*mm leadscrew
zaxis_motor = dict_replace_multiple(Nema17,
        [
        [NemaAxleDiameter, 8*mm],
        [NemaFrontAxleLength, 340*mm],
        [NemaAxleFlatDepth, 0*mm],
        ]);

zmotor_w = lookup(NemaSideSize,zaxis_motor);
zmotor_h = lookup(NemaLengthLong,zaxis_motor);

// inner_d, outer_d, thread, outer_h, full_h, screw_dist, screw_thread
zaxis_nut = [20*mm, 36*mm, 8*mm, 5*mm, 23*mm, 13.5*mm, ThreadM3];
zaxis_nut_mat = Mat_PlasticBlack;

zaxis_motor_offset_z = 10*mm;
zmotor_mount_thickness = 5;
zmotor_mount_thickness_h = 10;
zmotor_mount_motor_offset=5;

zmotor_mount_thread_dia = lookup(ThreadSize, extrusion_thread);
zmotor_mount_width = zmotor_w+zmotor_mount_thickness*2 + zmotor_mount_thread_dia*8;
zmotor_mount_h = main_lower_dist_z+extrusion_size+zaxis_motor_offset_z;

zmotor_mount_clamp_dist = zaxis_rod_d*2.5;
zmotor_mount_clamp_thread = extrusion_mount_thread;
zmotor_mount_clamp_nut = NutHexM4;
zmotor_mount_clamp_thread_dia = lookup(ThreadSize, zmotor_mount_clamp_thread);
zmotor_mount_clamp_nut_dia = lookup(NutWidthMin, zmotor_mount_clamp_nut);
zmotor_mount_clamp_nut_thick = lookup(NutThickness, zmotor_mount_clamp_nut);
zmotor_mount_clamp_width = zmotor_mount_clamp_dist+zmotor_mount_clamp_thread_dia*3.5;

xaxis_zaxis_distance_y_ = max(xaxis_rod_d/2 + zaxis_bearing_OD/2, zaxis_nut[1]/2 - xaxis_rod_d/2);
xaxis_zaxis_distance_y = xaxis_zaxis_distance_y_ + ziptie_type[0]+.5*mm + 1*mm;

zaxis_nut_mount_outer = zaxis_nut[1]/2 + zaxis_rod_d/2 + 1*mm;

// offset between Z motor screw and z rod
// place z rod as close as possible (depends on z nut and also motor etc)
zaxis_rod_screw_distance_x = max(zaxis_nut_mount_outer, zaxis_rod_d/2 + zmotor_w/2 + 1*mm);

// z screw offset from lower extrusion (outer)
zmotor_mount_screw_offset_x = zmotor_w/2 + zmotor_mount_motor_offset;

// z rod offset from lower extrusion (outer)
zmotor_mount_rod_offset_x = zmotor_mount_screw_offset_x + zaxis_rod_screw_distance_x;

include <thing_libutils/units.scad>
include <thing_libutils/system.scad>
include <thing_libutils/bearing_data.scad>
include <thing_libutils/pulley.scad>
include <thing_libutils/bearing-linear-data.scad>
/*include <thing_libutils/thread-data.scad>*/
include <thing_libutils/nut-data.scad>
include <thing_libutils/timing-belts-data.scad>
include <thing_libutils/stepper-data.scad>

use <thing_libutils/misc.scad>

e=0.01*mm;

// high quality etc
is_build = false;

// minimum size of a fragment
// resolution of any round object (segment length)
// Because of this variable very small circles have a smaller number of fragments than specified using $fa.
// The default value is 2.
$fs = is_build ? 0.5 : 1;

// minimum angle for a fragment.
// The default value is 12 (i.e. 30 fragments for a full circle)
$fa = is_build ? 4 : 16;

$show_vit = is_build ? false : true;

// enable preview model (faster openscad)
$preview_mode = is_build ? false : true;

extrusion_height            = 0.4*mm;

// width of a single wall, should match your slicer settings
extrusion_width             = 0.4*mm;

// how many lines should a normal wall have (i.e. 0.6(extrusion_width)*6(normal_wall_factor)= 3.6mm wall width)
normal_wall_factor          = 3;

thick_wall_factor           = 4;

// diameter of your filament.
filament_d                  = 1.75*mm;
filament_r                  = filament_d/2;
Mat_filament = Mat_PlasticBlack;

main_width = 420*mm;
main_depth = 420*mm;
main_height = 400*mm;
main_upper_width = 500*mm;

extrusion_size = 20*mm;
extrusion_thread = ThreadM5;
extrusion_thread_dia = lookup(ThreadSize, extrusion_thread);
extrusion_nut = NutHexM5;
extrusion_nut_dia = lookup(NutWidthMax, extrusion_nut);

extrusion_mount_thread = ThreadM4;

// for tapped ends
extrusion_end_nut = NutHexM6;

main_lower_dist_z = 80*mm;
main_upper_dist_y = 160*mm;

gantry_connector_thickness = 5;
gantry_upper_offset_y = -25;

rod_fit_tolerance=1.01;

ziptie_type = [2.5*mm, 3*mm];
ziptie_thickness = ziptie_type[0];
ziptie_width = ziptie_type[1]+0.6*mm;
ziptie_bearing_distance = 3*mm;

xaxis_rod_distance = 65*mm;
xaxis_rod_d = 9.975*mm;
xaxis_rod_l = 500*mm;
// relative to entire machine
xaxis_rod_offset_x = 0*mm;
xaxis_bearings_top=1;
xaxis_bearings_bottom=1;
xaxis_bearing_top = LinearBearingLM10L;
xaxis_bearing_bottom = LinearBearingLM10;;

xaxis_pulley = pulley_2GT_20T;
xaxis_pulley_inner_d = xaxis_pulley[2];
xaxis_pulley_outer_d = xaxis_pulley[3];
xaxis_idler_pulley = pulley_2GT_20T_idler;
xaxis_idler_pulley_inner_d = xaxis_idler_pulley[2];
xaxis_idler_pulley_outer_d = xaxis_idler_pulley[3];

xaxis_belt = TimingBelt_GT2_2;
xaxis_belt_width = 6*mm;
xaxis_beltpath_width = max(xaxis_belt_width+3*mm, xaxis_pulley[0]+2*mm);
xaxis_beltpath_z_offset_pulley = xaxis_pulley_inner_d/2;
/*xaxis_beltpath_z_offsets = [xaxis_beltpath_z_offset_pulley];*/
xaxis_beltpath_z_offsets = [-3*mm-xaxis_beltpath_z_offset_pulley, 3*mm+xaxis_beltpath_z_offset_pulley];
xaxis_beltpath_height_body = xaxis_pulley_outer_d/2+3*mm+v_sum(v_abs(xaxis_beltpath_z_offsets))+5*mm;
xaxis_beltpath_height_holders = max(xaxis_pulley_outer_d+2*mm, xaxis_pulley_inner_d+xaxis_beltpath_z_offsets[0]+3*mm);

xaxis_carriage_bearing_offset_y = ziptie_thickness+3*mm;
xaxis_carriage_beltpath_offset_y = xaxis_carriage_bearing_offset_y+get(LinearBearingOuterDiameter, xaxis_bearing_top)/2;

xaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);
xaxis_motor_thread=ThreadM3;
xaxis_motor_nut=NutHexM3;

xaxis_endstop_type = "SWITCH";
/*xaxis_endstop_type = "SN04";*/

yaxis_rod_distance = 170*mm;
yaxis_rod_d = 11.975*mm;
yaxis_rod_l = 500*mm;
yaxis_bearing = LinearBearingLM12;
yaxis_bearing_distance_y = 7*cm;

yaxis_motor = dict_replace(Nema17, NemaFrontAxleLength, 22*mm);

yaxis_pulley = pulley_2GT_20T;
yaxis_pulley_inner_d = yaxis_pulley[2];
ymotor_mount_thickness = 5;
ymotor_mount_thickness_h = 5;
yaxis_motor_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;

yaxis_belt = TimingBelt_GT2_2;
yaxis_belt_width = 6*mm;
yaxis_belt_path_offset_x = -yaxis_pulley_inner_d/2;
yaxis_belt_path_offset_z = 5*mm;

yaxis_motor_offset_z = yaxis_belt_path_offset_z - 10*mm;

yaxis_idler_pulley = pulley_2GT_20T_idler;
yaxis_idler_pulley_inner_d = yaxis_idler_pulley[2];
yaxis_idler_pulley_outer_d = yaxis_idler_pulley[3];
yaxis_idler_pulley_h = yaxis_idler_pulley[0];
yaxis_idler_mount_thickness = 5;
yaxis_idler_pulley_tight_len = 10*mm;
yaxis_idler_pulley_offset_y = yaxis_idler_mount_thickness + yaxis_pulley_inner_d/2 + yaxis_idler_pulley_tight_len;
yaxis_idler_offset_x = lookup(NemaSideSize,yaxis_motor)/2+ymotor_mount_thickness;
yaxis_idler_offset_z = 10*mm;

yaxis_carriage_offset =
    Z*get(LinearBearingInnerDiameter, yaxis_bearing)/2;

zaxis_rod_d = 11.975*mm;
zaxis_rod_l = 500*mm;
// relative to entire machine
zaxis_rod_offset = [0,-20*mm,0];
zaxis_bearing = LinearBearingLMH12L;
zaxis_bearing_ID=get(LinearBearingInnerDiameter,zaxis_bearing);
zaxis_bearing_OD=get(LinearBearingOuterDiameter,zaxis_bearing);
zaxis_bearing_L=get(LinearBearingLength,zaxis_bearing);

// Nema17 motor w/340mm long 8*mm leadscrew
zaxis_motor = dict_replace_multiple(Nema17,
        [
        [NemaAxleDiameter, 8*mm],
        [NemaFrontAxleLength, 340*mm],
        [NemaAxleFlatDepth, 0*mm],
        ]);

zmotor_w = lookup(NemaSideSize,zaxis_motor);
zmotor_h = lookup(NemaLengthLong,zaxis_motor);

// inner_d, outer_d, thread, outer_h, full_h, screw_dist, screw_thread
zaxis_nut = [20*mm, 36*mm, 8*mm, 5*mm, 23*mm, 13.5*mm, ThreadM3];
zaxis_nut_mat = Mat_PlasticBlack;

zaxis_motor_offset_z = 10*mm;
zmotor_mount_thickness = 5;
zmotor_mount_thickness_h = 10;
zmotor_mount_motor_offset=5;

zmotor_mount_thread_dia = lookup(ThreadSize, extrusion_thread);
zmotor_mount_width = zmotor_w+zmotor_mount_thickness*2 + zmotor_mount_thread_dia*8;
zmotor_mount_h = main_lower_dist_z+extrusion_size+zaxis_motor_offset_z;

zmotor_mount_clamp_dist = zaxis_rod_d*2.5;
zmotor_mount_clamp_thread = extrusion_mount_thread;
zmotor_mount_clamp_nut = NutHexM4;
zmotor_mount_clamp_thread_dia = lookup(ThreadSize, zmotor_mount_clamp_thread);
zmotor_mount_clamp_nut_dia = lookup(NutWidthMin, zmotor_mount_clamp_nut);
zmotor_mount_clamp_nut_thick = lookup(NutThickness, zmotor_mount_clamp_nut);
zmotor_mount_clamp_width = zmotor_mount_clamp_dist+zmotor_mount_clamp_thread_dia*3.5;

xaxis_zaxis_distance_y_ = max(xaxis_rod_d/2 + zaxis_bearing_OD/2, zaxis_nut[1]/2 - xaxis_rod_d/2);
xaxis_zaxis_distance_y = xaxis_zaxis_distance_y_ + ziptie_type[0]+.5*mm + 1*mm;

zaxis_nut_mount_outer = zaxis_nut[1]/2 + zaxis_rod_d/2 + 1*mm;

// offset between Z motor screw and z rod
// place z rod as close as possible (depends on z nut and also motor etc)
zaxis_rod_screw_distance_x = max(zaxis_nut_mount_outer, zaxis_rod_d/2 + zmotor_w/2 + 1*mm);

// z screw offset from lower extrusion (outer)
zmotor_mount_screw_offset_x = zmotor_w/2 + zmotor_mount_motor_offset;

// z rod offset from lower extrusion (outer)
zmotor_mount_rod_offset_x = zmotor_mount_screw_offset_x + zaxis_rod_screw_distance_x;


added 3d printed box

added 3d printed box

$fn=80; // resolutie (zet lager om te debuggen)

thickness = 1.5;
bottom_thickness = 1.05;
width = 100;
depth = 185;
height = 35;

fudge = 12.1;

xlr_diameter = 24;

xlr_srew_diameter = 3.53;
xlr_width = 26.03;
xlr_height = 31.04;
xlr_srew_distance_from_side = 1.80;
xlr_screw_centerdistance_width = xlr_width/2 - xlr_srew_distance_from_side - xlr_srew_diameter/2;
xlr_screw_centerdistance_height = xlr_height/2 - xlr_srew_distance_from_side - xlr_srew_diameter/2;

yun_bottom_offset = 6.00;
yun_pcb_thickness = 1.67;
yun_connector_offset = yun_bottom_offset + yun_pcb_thickness;

xlr_spacing = 2;
xlr_distance = xlr_width + xlr_spacing;

module gat (){
	translate([0,0,-(thickness+fudge)/2]) cylinder(thickness+fudge,d=xlr_diameter,true);
	translate([xlr_screw_centerdistance_width,12.5,-(thickness+fudge)/2]) cylinder(thickness+fudge,d=xlr_srew_diameter,true);
	translate([-xlr_screw_centerdistance_width,-12.5,-(thickness+fudge)/2]) cylinder(thickness+fudge,d=xlr_srew_diameter,true);
}

//left side:
translate([-depth/2, -width/2, 0]) cube([depth, thickness, height]);
//right side:
translate([-depth/2, width/2-thickness, 0]) {
	difference() {

 		cube([depth, thickness, height]);
		for ( i = [0 : 5] ) {
			translate([(-xlr_distance/2+xlr_distance*6)+(depth-6*xlr_distance)/2-i*xlr_distance, 0, 18]) rotate(a=[90,0,0]) gat();
		}

	}
}
//back:
translate([-depth/2, -width/2, 0]) cube([thickness, width, height]);

// bottom:
translate([-depth/2, -width/2, 0]) cube([depth, width, bottom_thickness]);

//front:

ethernet_ypos = -width/2+thickness+16;
difference() {

	// plate:
	translate([depth/2-thickness, -width/2, 0]) cube([thickness, width, height]);

	// holes:

	// ehternet hole
	translate([depth/2-20, ethernet_ypos, yun_connector_offset]) cube([40, 16.20, 14]);

	// micro usb hole:
	translate([depth/2-20, ethernet_ypos+24.32, yun_connector_offset]) cube([40, 8.02, 4]);

	// usb hole
	translate([depth/2-20, ethernet_ypos+35.56, yun_connector_offset]) cube([40, 7, 15]);

}

// support holes:
supportholes_height = yun_bottom_offset;
module supporthole(){
	translate([0,0,supportholes_height/2]){
		difference() {
			cylinder(h=supportholes_height, d=5, center=true);
			cylinder(h=supportholes_height*2, d=2.1, center=true);
		}
	}
}

// voorste:
translate([depth/2-thickness-13.83, ethernet_ypos-2.28, bottom_thickness]) supporthole();
translate([depth/2-thickness-13.83, ethernet_ypos+45.39, bottom_thickness]) supporthole();

// achterste:
translate([depth/2-thickness-65.88, ethernet_ypos+12.51, bottom_thickness]) supporthole();
translate([depth/2-thickness-65.88, ethernet_ypos+12.51+28.07, bottom_thickness]) supporthole();

module lidhole(height){
	translate([0,0,height/2]) difference() {
		cube(size=[5,5,height], center=true);
		cylinder(h=height*2, d=2.1, center=true);
	}
}

translate([(depth/2-5/2-thickness),+(width/2-5/2-thickness),0]) lidhole(height);
translate([(depth/2-5/2-thickness),-(width/2-5/2-thickness),0]) lidhole(height);

translate([-(depth/2-5/2-thickness),+(width/2-5/2-thickness),0]) lidhole(height);
translate([-(depth/2-5/2-thickness),-(width/2-5/2-thickness),0]) lidhole(height);

error: pathspec '3d-printed-box/box.scad' did not match any file(s) known to git


shoe drying box

shoe drying box

//Modules
module cut() {
    square([16,10.5]);
    translate([134,0])square([16,10.5]);
    translate([134+139,0])square([16,10.5]);
}
module fanCut() {
    tr_xy(x=20)circle(r=1.5);
    circle(r=10);
}
//Translations
module tr_xy(x,y=0) {
	if(y==0) {
		for(i=[-1,1])for(j=[-1,1])translate([x*i,x*j])children();
	} else {
		for(i=[-1,1])for(j=[-1,1])translate([x*i,y*j])children();
	}
}

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


baseline

baseline

use <../../../basics/rounded-edges/rounded-cube/rounded-cube.scad>

boardLength = 150;
boardWidth = 100;
size = [boardLength, boardWidth, 1];

roundedCube(cornerRadius = 5,
            sides=20,
            sidesOnly=true,
            size=size);

error: pathspec 'openscad/models/src/main/openscad/connectors/rounded-corners-square/end-cap/rounded-corner-end-cap.scad' did not match any file(s) known to git


Add shape pipeSegment

Add shape pipeSegment

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2017 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.
 *
 * Ellipsoid shapes.
 *
 * @package shape/3D
 * @author jsconan
 */

/**
 * Computes the size of an ellipsoid.
 *
 * @param Number|Vector [r] - The radius or a vector that contains 3D radius.
 * @param Number|Vector [d] - The diameter or a vector that contains 3D diameters.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [rz] - The height radius.
 * @param Number [dx] - The length diameter.
 * @param Number [dy] - The width diameter.
 * @param Number [dz] - The height diameter.
 * @returns Vector - Returns a vector containing the 3D radius.
 */
function sizeEllipsoid(r, d, rx, ry, rz, dx, dy, dz) =
    let(
        r = apply3D(r, rx, ry, rz),
        d = apply3D(d, dx, dy, dz)
    )
    [
        // use divisor() to ensure the values will be forced to anything but 0
        divisor(d[0] && !rx ? d[0] / 2 : r[0]),
        divisor(d[1] && !ry ? d[1] / 2 : r[1]),
        divisor(d[2] && !rz ? d[2] / 2 : r[2])
    ]
;

/**
 * Creates a shaft (extruded ellipse) at the origin.
 *
 * @param Number|Vector [r] - The radius or a vector that contains length and width radius.
 * @param Number|Vector [d] - The diameter or a vector that contains length and width diameters.
 * @param Number [h] - The height of the shaft.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [dx] - The length of the shaft.
 * @param Number [dy] - The width of the shaft.
 * @param Boolean [center] - Whether or not center the shaft on the vertical axis.
 */
module shaft(r, h, d, rx, ry, dx, dy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        ellipse(size);
    }
}

/**
 * Creates a wedge (extruded pie slice) at the origin.
 *
 * @param Number|Vector [r] - The radius or a vector that contains length and width radius.
 * @param Number|Vector [d] - The diameter or a vector that contains length and width diameters.
 * @param Number [h] - The height of the wedge.
 * @param Number [a] - The angle of the wedge
 * @param Number [a1] - The start angle of the wedge
 * @param Number [a2] - The end angle of the wedge
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [dx] - The length of the wedge.
 * @param Number [dy] - The width of the wedge.
 * @param Boolean [center] - Whether or not center the wedge on the vertical axis.
 */
module wedge(r, h, a=90, d, a1, a2, rx, ry, dx, dy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        pie(size, a=a, a1=a1, a2=a2);
    }
}

/**
 * Creates an ellipsoid at the origin.
 *
 * @param Number|Vector [r] - The radius or a vector that contains 3D radius.
 * @param Number|Vector [d] - The diameter or a vector that contains 3D diameters.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [rz] - The height radius.
 * @param Number [dx] - The length diameter.
 * @param Number [dy] - The width diameter.
 * @param Number [dz] - The height diameter.
 */
module ellipsoid(r, d, rx, ry, rz, dx, dy, dz) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=rz, dx=dx, dy=dy, dz=dz);
    r = max(size);
    scale(size / r) {
        sphere(r);
    }
}

/**
 * Creates a pipe at the origin.
 *
 * @param Number|Vector [r] - The radius of the pipe or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [w] - The thickness of the pipe.
 * @param Number [h] - The height of the pipe.
 * @param Number|Vector [d] - The diameter of the pipe or a vector that contains horizontal and vertical diameters.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Number [wx] - The horizontal thickness of the pipe hole.
 * @param Number [wy] - The vertical thickness of the pipe hole.
 * @param Boolean [center] - Whether or not center the pipe on the vertical axis.
 */
module pipe(r, h, w=0.1, d, rx, ry, dx, dy, wx, wy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        ring(r=size, w=w, wx=wx, wy=wy);
    }
}

/**
 * Creates a pipe segment at the origin.
 *
 * @param Number|Vector [r] - The radius of the pipe or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [w] - The thickness of the pipe.
 * @param Number [h] - The height of the pipe.
 * @param Number|Vector [d] - The diameter of the pipe or a vector that contains horizontal and vertical diameters.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Number [wx] - The horizontal thickness of the pipe hole.
 * @param Number [wy] - The vertical thickness of the pipe hole.
 * @param Boolean [center] - Whether or not center the pipe on the vertical axis.
 */
module pipeSegment(r, h, w=0.1, a=90, d, a1, a2, rx, ry, dx, dy, wx, wy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        ringSegment(r=size, a=a, a1=a1, a2=a2, w=w, wx=wx, wy=wy);
    }
}

/**
 * Creates a torus at the origin.
 * Note: the tore can be deformed if the ring is not perfectly circular.
 *
 * @param Number|Vector [r] - The radius of the torus ring or a vector that contains 3D radius.
 * @param Number|Vector [d] - The diameter of the torus ring or a vector that contains 3D diameters.
 * @param Number|Vector [w] - The radius of the torus pipe.
 * @param Number|Vector [W] - The diameter of the torus pipe.
 * @param Number [rx] - The length radius of the torus ring.
 * @param Number [ry] - The width radius of the torus ring.
 * @param Number [dx] - The length diameter of the torus ring.
 * @param Number [dy] - The width diameter of the torus ring.
 * @param Number [wx] - The length radius of the torus pipe.
 * @param Number [wy] - The width radius of the torus pipe.
 * @param Number [Wx] - The length diameter of the torus pipe.
 * @param Number [Wy] - The width diameter of the torus pipe.
 * @param Boolean [center] - Whether or not center the torus on the vertical axis.
 */
module torus(r, w=0.1, d, W, rx, ry, dx, dy, wx, wy, Wx, Wy, center) {
    sizeRing = sizeEllipse(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy);
    sizePipe = sizeEllipse(r=w, d=W, rx=wx, ry=wy, dx=Wx, dy=Wy);

    translate([0, 0, center ? 0 : sizePipe[1]]) {
        resize(apply3D(vadd(sizeRing, sizePipe[0]), z=sizePipe[1]) * 2) {
            rotate_extrude(convexity=10) {
                translate([max(sizeRing) - sizePipe[0], 0, 0]) {
                    ellipse(sizePipe);
                }
            }
        }
    }
}

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2017 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.
 *
 * Ellipsoid shapes.
 *
 * @package shape/3D
 * @author jsconan
 */

/**
 * Computes the size of an ellipsoid.
 *
 * @param Number|Vector [r] - The radius or a vector that contains 3D radius.
 * @param Number|Vector [d] - The diameter or a vector that contains 3D diameters.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [rz] - The height radius.
 * @param Number [dx] - The length diameter.
 * @param Number [dy] - The width diameter.
 * @param Number [dz] - The height diameter.
 * @returns Vector - Returns a vector containing the 3D radius.
 */
function sizeEllipsoid(r, d, rx, ry, rz, dx, dy, dz) =
    let(
        r = apply3D(r, rx, ry, rz),
        d = apply3D(d, dx, dy, dz)
    )
    [
        // use divisor() to ensure the values will be forced to anything but 0
        divisor(d[0] && !rx ? d[0] / 2 : r[0]),
        divisor(d[1] && !ry ? d[1] / 2 : r[1]),
        divisor(d[2] && !rz ? d[2] / 2 : r[2])
    ]
;

/**
 * Creates a shaft (extruded ellipse) at the origin.
 *
 * @param Number|Vector [r] - The radius or a vector that contains length and width radius.
 * @param Number|Vector [d] - The diameter or a vector that contains length and width diameters.
 * @param Number [h] - The height of the shaft.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [dx] - The length of the shaft.
 * @param Number [dy] - The width of the shaft.
 * @param Boolean [center] - Whether or not center the shaft on the vertical axis.
 */
module shaft(r, h, d, rx, ry, dx, dy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        ellipse(size);
    }
}

/**
 * Creates a wedge (extruded pie slice) at the origin.
 *
 * @param Number|Vector [r] - The radius or a vector that contains length and width radius.
 * @param Number|Vector [d] - The diameter or a vector that contains length and width diameters.
 * @param Number [h] - The height of the wedge.
 * @param Number [a] - The angle of the wedge
 * @param Number [a1] - The start angle of the wedge
 * @param Number [a2] - The end angle of the wedge
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [dx] - The length of the wedge.
 * @param Number [dy] - The width of the wedge.
 * @param Boolean [center] - Whether or not center the wedge on the vertical axis.
 */
module wedge(r, h, a=90, d, a1, a2, rx, ry, dx, dy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        pie(size, a=a, a1=a1, a2=a2);
    }
}

/**
 * Creates an ellipsoid at the origin.
 *
 * @param Number|Vector [r] - The radius or a vector that contains 3D radius.
 * @param Number|Vector [d] - The diameter or a vector that contains 3D diameters.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [rz] - The height radius.
 * @param Number [dx] - The length diameter.
 * @param Number [dy] - The width diameter.
 * @param Number [dz] - The height diameter.
 */
module ellipsoid(r, d, rx, ry, rz, dx, dy, dz) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=rz, dx=dx, dy=dy, dz=dz);
    r = max(size);
    scale(size / r) {
        sphere(r);
    }
}

/**
 * Creates a pipe at the origin.
 *
 * @param Number|Vector [r] - The radius of the pipe or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [w] - The thickness of the pipe.
 * @param Number [h] - The height of the pipe.
 * @param Number|Vector [d] - The diameter of the pipe or a vector that contains horizontal and vertical diameters.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Number [wx] - The horizontal thickness of the pipe hole.
 * @param Number [wy] - The vertical thickness of the pipe hole.
 * @param Boolean [center] - Whether or not center the pipe on the vertical axis.
 */
module pipe(r, h, w=0.1, d, rx, ry, dx, dy, wx, wy, center) {
    size = sizeEllipsoid(r=r, d=d, rx=rx, ry=ry, rz=h, dx=dx, dy=dy);
    linear_extrude(height=size[2], center=center, convexity=10) {
        ring(r=size, w=w, wx=wx, wy=wy);
    }
}

/**
 * Creates a torus at the origin.
 * Note: the tore can be deformed if the ring is not perfectly circular.
 *
 * @param Number|Vector [r] - The radius of the torus ring or a vector that contains 3D radius.
 * @param Number|Vector [d] - The diameter of the torus ring or a vector that contains 3D diameters.
 * @param Number|Vector [w] - The radius of the torus pipe.
 * @param Number|Vector [W] - The diameter of the torus pipe.
 * @param Number [rx] - The length radius of the torus ring.
 * @param Number [ry] - The width radius of the torus ring.
 * @param Number [dx] - The length diameter of the torus ring.
 * @param Number [dy] - The width diameter of the torus ring.
 * @param Number [wx] - The length radius of the torus pipe.
 * @param Number [wy] - The width radius of the torus pipe.
 * @param Number [Wx] - The length diameter of the torus pipe.
 * @param Number [Wy] - The width diameter of the torus pipe.
 * @param Boolean [center] - Whether or not center the torus on the vertical axis.
 */
module torus(r, w=0.1, d, W, rx, ry, dx, dy, wx, wy, Wx, Wy, center) {
    sizeRing = sizeEllipse(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy);
    sizePipe = sizeEllipse(r=w, d=W, rx=wx, ry=wy, dx=Wx, dy=Wy);

    translate([0, 0, center ? 0 : sizePipe[1]]) {
        resize(apply3D(vadd(sizeRing, sizePipe[0]), z=sizePipe[1]) * 2) {
            rotate_extrude(convexity=10) {
                translate([max(sizeRing) - sizePipe[0], 0, 0]) {
                    ellipse(sizePipe);
                }
            }
        }
    }
}


shapes/fncylindera: fix r1/r2 and d1/d2 params

use <misc.scad>

// translate children
module lineup(arr=undef)
{
    /*echo(arr);*/
    /*echo($children);*/
    if($children>0)
    {
        for (i = [0 : $children-1])
            translate(arr[i]) children(i);
    }
}

module stack(separations)
{
    union()
    {
        for (i = [0:len(separations)-1])
        {
            offset = v_sum(separations,i);
            /*echo("i",i,"offset",offset);*/
            translate ([0,0,offset])
            {
                child(i);
            }
        }
    }
}

module orient(zaxes, roll=0)
{
    zaxes = len(zaxes.x) == undef && zaxes.x != undef? [zaxes] : zaxes;
    for(zaxis=zaxes)
    {
        rotate(_orient_angles(zaxis))
        /*rotate(roll*z)*/
            children();
    }
}

module size_align(size=[10,10,10], align=[0,0,0], orient=[0,0,1])
{
    bounds = _rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1];
    t=hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]);
    translate(t)
    {
        orient(orient)
        {
            children();
        }
    }
}

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module cuberounda(size=[10,10,10], facets=32, rounding_radius=1, align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cuberound(size=size+extrasize, facets=facets, rounding_radius=rounding_radius);
        }
    }
}

module cuberound(size=[10,10,10], facets=32, rounding_radius=1)
{
    translate(-size/2)
    hull()
    {
        translate([rounding_radius,rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([rounding_radius,size[1]-rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,size[1]-rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([rounding_radius,rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([rounding_radius,size[1]-rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,size[1]-rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
    }
}

module cylindera(h=10, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, align=[0,0,0], extra_h=0,extra_r=undef,extra_d=undef,extra_align=[0,0,0])
{
    extra_r_=(extra_r==undef?0:extra_r);
    extra_d_=(extra_d==undef?0:extra_d);
    extra_sizexy=extra_r_*2 + extra_d_;
    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {
        r_=(r==undef?0:r);
        d_=(d==undef?0:d);
        sizexy=r_*2 + d_;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r+extra_r_, r1=r1, r2=r2, d=d+extra_d_, d1=d1, d2=d2, center=true);
        }
    }
}

module fncylinder(r, r2, d, d2, h, fn, center=false, enlarge=0, fnr=0.8){
    translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
        if (fn==undef) {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            }
        } else {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
            }
        }
    }
}

// specify segment length with fnr, $fn not needed but if desired use fn instead but if desired use fn instead
module fncylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,1],
        fn,
        fnr=0.8,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    r_= useDia?d/2:(r==undef?0:r);
    r1r2max = max(r1,r2) == undef ? max(d1,d2)/2 : max(r1,r2);
    r__ = r_==undef? r1r2max : r_;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    sizexy=r__*2;
    extra_sizexy=extra_r_*2;

    // some orient hax here to properly support extra_align
    orient(-orient)
    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align, orient=orient)
    orient(orient)
    {
        fn_r = r__;

        fn_=fn==undef?(floor(2*(r__)*pi/fnr)):fn;

        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align, fn_);
        }

        // some orient hax here to properly support extra_align
        orient(-orient)
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true, $fn=fn_);
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

/*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/
/*fncylindera(h=10, r=5, extra_r=2, align=[0,0,1], orient=[1,0,0]);*/

/*fncylindera(h=10, d=5, extra_r=2, align=[0,0,-1], orient=[0,0,1]);*/
/*translate([0,-10,0])*/
/*fncylindera(h=10, d=5, extra_r=2, align=[0,0,1], orient=[0,0,1]);*/
/*translate([0,-20,0])*/
/*fncylindera(h=10, d=10, extra_h=5, orient=[1,0,0], align=[1,0,0], extra_align=[1,0,0]);*/
/*translate([0,-30,0])*/
/*fncylindera(h=10, d=7.5, extra_h=5, orient=[1,0,0], align=[-1,0,0], extra_align=[1,0,0]);*/

/*fncylindera(h=10, r1=5, r2=10, orient=[1,0,0], align=[-1,0,0], extra_align=[1,0,0]);*/
/*fncylindera(h=10, d1=5, d2=30, orient=[0,0,1], align=[0,0,1]);*/

use <misc.scad>

// translate children
module lineup(arr=undef)
{
    /*echo(arr);*/
    /*echo($children);*/
    if($children>0)
    {
        for (i = [0 : $children-1])
            translate(arr[i]) children(i);
    }
}

module stack(separations)
{
    union()
    {
        for (i = [0:len(separations)-1])
        {
            offset = v_sum(separations,i);
            /*echo("i",i,"offset",offset);*/
            translate ([0,0,offset])
            {
                child(i);
            }
        }
    }
}

module orient(zaxes, roll=0)
{
    zaxes = len(zaxes.x) == undef && zaxes.x != undef? [zaxes] : zaxes;
    for(zaxis=zaxes)
    {
        rotate(_orient_angles(zaxis))
        /*rotate(roll*z)*/
            children();
    }
}

module size_align(size=[10,10,10], align=[0,0,0], orient=[0,0,1])
{
    bounds = _rotate_matrix(_orient_angles(orient)) * [size.x,size.y,size.z,1];
    t=hadamard(align, [abs(bounds.x/2),abs(bounds.y/2),abs(bounds.z/2)]);
    translate(t)
    {
        orient(orient)
        {
            children();
        }
    }
}

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module cuberounda(size=[10,10,10], facets=32, rounding_radius=1, align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cuberound(size=size+extrasize, facets=facets, rounding_radius=rounding_radius);
        }
    }
}

module cuberound(size=[10,10,10], facets=32, rounding_radius=1)
{
    translate(-size/2)
    hull()
    {
        translate([rounding_radius,rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([rounding_radius,size[1]-rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,size[1]-rounding_radius,rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([rounding_radius,rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([rounding_radius,size[1]-rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
        translate([size[0]-rounding_radius,size[1]-rounding_radius,size[2]-rounding_radius]) sphere (r=rounding_radius,$fn=facets);
    }
}

module cylindera(h=10, r=undef, r1=undef, r2=undef, d=undef, d1=undef, d2=undef, align=[0,0,0], extra_h=0,extra_r=undef,extra_d=undef,extra_align=[0,0,0])
{
    extra_r_=(extra_r==undef?0:extra_r);
    extra_d_=(extra_d==undef?0:extra_d);
    extra_sizexy=extra_r_*2 + extra_d_;
    size_align([extra_sizexy,extra_sizexy,extra_h],extra_align)
    {
        r_=(r==undef?0:r);
        d_=(d==undef?0:d);
        sizexy=r_*2 + d_;
        size_align([sizexy,sizexy,h],align)
        {
            cylinder(h=h+extra_h, r=r+extra_r_, r1=r1, r2=r2, d=d+extra_d_, d1=d1, d2=d2, center=true);
        }
    }
}

module fncylinder(r, r2, d, d2, h, fn, center=false, enlarge=0, fnr=0.8){
    translate(center==false?[0,0,-enlarge]:[0,0,-h/2-enlarge]) {
        if (fn==undef) {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=floor(2*(r?r:d?d/2:1)*PI/fnr));
            }
        } else {
            if (r2==undef && d2==undef) {
                cylinder(r=r?r:d?d/2:1,h=h+enlarge*2,$fn=fn);
            } else {
                cylinder(r=r?r:d?d/2:1,r2=r2?r2:d2?d2/2:1,h=h+enlarge*2,$fn=fn);
            }
        }
    }
}

// specify segment length with fnr, $fn not needed but if desired use fn instead but if desired use fn instead
module fncylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,1],
        fn,
        fnr=0.8,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r_= useDia?d/2:(r==undef?0:r);
    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    sizexy=r_*2;
    extra_sizexy=extra_r_*2;

    // some orient hax here to properly support extra_align
    orient(-orient)
    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align, orient=orient)
    orient(orient)
    {
        fn_=fn==undef?(floor(2*(r_+extra_r_)*pi/fnr)):fn;

        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align, fn_);
        }

        // some orient hax here to properly support extra_align
        orient(-orient)
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true, $fn=fn_);
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

/*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/
/*fncylindera(h=10, r=5, extra_r=2, align=[0,0,1], orient=[1,0,0]);*/

/*fncylindera(h=10, d=5, extra_r=2, align=[0,0,-1], orient=[0,0,1]);*/
/*translate([0,-10,0])*/
/*fncylindera(h=10, d=5, extra_r=2, align=[0,0,1], orient=[0,0,1]);*/
/*translate([0,-20,0])*/
/*fncylindera(h=10, d=10, extra_h=5, orient=[1,0,0], align=[1,0,0], extra_align=[1,0,0]);*/
/*translate([0,-30,0])*/
/*fncylindera(h=10, d=7.5, extra_h=5, orient=[1,0,0], align=[-1,0,0], extra_align=[1,0,0]);*/


shapes: add rtriangle

shapes: add rtriangle

use <misc.scad>
use <transforms.scad>

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module rcubea(size=[10,10,10], rounding_radius=1, align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            rcube(size=size+extrasize, rounding_radius=rounding_radius);
        }
    }
}

module rcube(size=[20,20,20], rounding_radius=1)
{
    hull()
    for(x=[-(size[0]/2-rounding_radius),(size[0]/2-rounding_radius)])
    for(y=[-(size[1]/2-rounding_radius),(size[1]/2-rounding_radius)])
    for(z=[-(size[2]/2-rounding_radius),(size[2]/2-rounding_radius)])
    translate([x,y,z])
    sphere(r=rounding_radius);
}

module cylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,1],
        round_radius=undef,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    r_= useDia?d/2:(r==undef?0:r);
    r1r2max = max(r1,r2) == undef ? max(d1,d2)/2 : max(r1,r2);
    r__ = r_==undef? r1r2max : r_;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    sizexy=r__*2;
    extra_sizexy=extra_r_*2;

    // some orient hax here to properly support extra_align
    orient(-orient)
    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align, orient=orient)
    orient(orient)
    {
        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align);
        }

        // some orient hax here to properly support extra_align
        orient(-orient)
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            if(round_radius==undef)
            {
                cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true);
            }
            else
            {
                rcylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, round_radius=round_radius);
            }
        }
    }
}

/*translate([10,0,0])*/
/*rotate_extrude()*/
        /*translate([10-2,2,0])*/
/*$fa = 5.6;*/
/*$fs = 0.3;*/
/*circle(r = 100);*/
/*torus(10, 2, align=[0,0,0], orient=[0,0,1]);*/

module torus(radius, radial_width, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[radius*2+radial_width*2, radius*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate([radius, 0, 0])
    circle(radial_width);
}

module rcylinder(d=undef, r1=undef, r2=undef, h=10, round_radius=2, align=[0,0,0], orient=[0,0,1])
{
    useDia = r == undef && (r1 == undef && r2 == undef);

    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    r_= useDia?[d/2,d/2]:(r==undef?[r1_,r2_]:[r,r]);
    size_align(align=align, orient=orient)
    /*translate([0,0,-h/2])*/
    hull()
    {
        /*a = r_[0]-r_[1];*/
        /*b = h;*/
        /*c = pythag_hyp(a,b);*/
        /*echo(c);*/
        /*d = c;//pythag_leg(a,c);*/
        /*echo(d);*/
        /*translate([0,r1-round_radius,0])*/
        /*cube([d,d,d]);*/
        /*angle2 = -atan2(-h, r1-r2);*/
        /*echo(angle2);*/
        /*x2 = r2-r1 < 0 ? (round_radius*2*cos(angle2)) : (round_radius*2*sin(angle2));*/
        /*echo(x2)*/
        /*translate([0, 0, h/2-round_radius])*/
        /*torus(radius=r_[1]-round_radius, radial_width=round_radius, align=[0,0,0]);*/

        for(z=[-1,1])
        translate([0, 0, z*(-h/2)])
        {
            /*rd = abs(r1-r2);*/
            /*angle1 = atan2(h, abs(r2-r1));*/
            /*x1 = round_radius*2*cos(angle1);*/
            /*echo(angle1, x1);*/
            r__=z!=-1?r_[0]:r_[1];
            torus(radius=r__-round_radius/2, radial_width=round_radius/2, align=[0,0,z]);

            /*translate([0, 0, -round_radius])*/
            /*cubea([r__*2,r__*2,5], align=[0,0,-z]);*/
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

module hollow_cylinder(d=10, thickness=1, h=10, taper=false, taper_h=undef, orient=[0,0,1], align=[0,0,0])
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    size_align(size=[outer_d, outer_d, h], orient=orient, align=align)
    difference()
    {
        /*hull()*/
        union()
        {
            cylindera(h=h-taper_h*2, d=outer_d, orient=[0,0,1], align=[0,0,0]);
            taper_h = taper_h == undef ? (outer_d-inner_d)/4 : taper_h;
            /*taper_h_ = pythag_leg(taper_h, outer_d-inner_d);*/
            /*echo(taper_h_);*/
            if(taper)
            {
                for(z=[-1,1])
                translate([0,0,z*(h/2-taper_h)])
                mirror([0,0,z==-1?1:0])
                difference()
                {
                    cylindera(d1=outer_d, d2=outer_d-inner_d/4, h=taper_h*2, align=[0,0,1]);
                    cylindera(d1=inner_d, d2=outer_d, h=taper_h*2+.1, align=[0,0,1]);
                }
            }
        }

        cylindera(h=h+.4, d=inner_d, orient=[0,0,1], align=[0,0,0]);
    }
}

/**
 * Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module triangle(o_len, a_len, depth, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[a_len, depth, o_len], align=align, orient=orient)
    rotate([90,0,0])
    translate([-a_len/2, -o_len/2, -depth/2])
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]);
    }
}

/**
 * Rounded Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module rtriangle(o_len, a_len, depth, rounding_radius=2, align=[0,0,0], orient=[0,0,1])
{
    size = [a_len-rounding_radius, depth-rounding_radius, o_len-rounding_radius];
    r_x = rounding_radius;
    r_y = rounding_radius;
    r_z = -rounding_radius;

    hyp = pythag_hyp(o_len,a_len);
    a_z = atan(a_len/o_len);

    translate([0,0,size[2]+2])
    color([1,0,0])
    rotate([90,90,0])
    pie_slice(r=2, start_angle=0, end_angle=a_z, h=depth);

    /*translate([size[0]+4,0,0])*/
    /*color([1,0,0])*/
    /*rotate([90,90,0])*/
    /*pie_slice(r=2, start_angle=90, end_angle=90+a_z, h=depth);*/

    size_align(size=size, align=align, orient=orient)
    /*hull()*/
    for(x=[-(size[0]/2)+rounding_radius,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+rounding_radius,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+rounding_radius,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=rounding_radius);
}

/*debug();*/

module debug()
{
    $fs = 0.1;
    $fa = 1;

    /*triangle_a(45, 5, 5);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,-1]);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,1]);*/

    triangle(10, 30, 5, align=[1,1,1], orient=[0,0,1]);
    translate([0,-10,0])
    rtriangle(10, 30, 5, align=[1,1,1], orient=[0,0,1]);
}

/**
 * Standard right-angled triangle (tangent version)
 *
 * @param number angle of adjacent to hypotenuse (ie tangent)
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 */
module triangle_a(tan_angle, a_len, depth)
{
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]);
    }
}

// Tests:
module test_triangles()
{
    // Generate a bunch of triangles by sizes
    for (i = [1:10])
    {
        translate([i*7, -30, i*7])
        {
            triangle(i*5, sqrt(i*5+pow(i,2)), 5);
        }
    }

    // Generate a bunch of triangles by angle
    for (i = [1:85/5])
    {
        translate([i*7, 22, i*7])
        {
            triangle_a(i*5, 10, 5);
        }
    }
}

/*hollow_cylinder(thickness=5, h=10, taper=true, orient=[0,0,1], align=[0,0,1]);*/
/*cylindera(d=10, h=10, orient=[0,0,1], align=[0,0,1]);*/
/*translate([10,0,0])*/
/*{*/
    /*hollow_cylinder(d=10, thickness=4, h=10, taper=true, taper_h=.5, orient=[0,0,1], align=[0,0,1]);*/
    /*cylindera(d=8, h=10, orient=[0,0,1], align=[0,0,1]);*/
/*}*/

/*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/

/*hull_pairwise()*/
{
    /*sphere(30/2);*/

/*translate([30,0,0])*/
    /*rcubea(s=[35,35,35], rounding_radius=10);*/
    /*rcubea(s=[35,35,35], align=[0,-1,0]);*/

/*translate([60,0,0])*/
    /*sphere(30/2);*/
}

use <misc.scad>
use <transforms.scad>

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            cube(size+extrasize, center=true);
        }
    }
}

module rcubea(size=[10,10,10], rounding_radius=1, align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0])
{
    size_align(extrasize,extrasize_align)
    {
        size_align(size,align)
        {
            rcube(size=size+extrasize, rounding_radius=rounding_radius);
        }
    }
}

module rcube(size=[20,20,20], rounding_radius=1)
{
    hull()
    for(x=[-(size[0]/2-rounding_radius),(size[0]/2-rounding_radius)])
    for(y=[-(size[1]/2-rounding_radius),(size[1]/2-rounding_radius)])
    for(z=[-(size[2]/2-rounding_radius),(size[2]/2-rounding_radius)])
    translate([x,y,z])
    sphere(r=rounding_radius);
}

module cylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,1],
        round_radius=undef,
        debug=false
        )
{
    pi=3.1415926536;

    useDia = r == undef && (r1 == undef && r2 == undef);

    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    r_= useDia?d/2:(r==undef?0:r);
    r1r2max = max(r1,r2) == undef ? max(d1,d2)/2 : max(r1,r2);
    r__ = r_==undef? r1r2max : r_;
    extra_r_ = useDia?((extra_d==undef?0:extra_d)/2):((extra_r==undef)?0:extra_r);

    sizexy=r__*2;
    extra_sizexy=extra_r_*2;

    // some orient hax here to properly support extra_align
    orient(-orient)
    size_align([extra_sizexy,extra_sizexy,extra_h], align=extra_align, orient=orient)
    orient(orient)
    {
        if(debug)
        {
            echo(useDia, h, r_, r1_, r2_, extra_r_, align);
        }

        // some orient hax here to properly support extra_align
        orient(-orient)
        size_align([sizexy,sizexy,h], align=align, orient=orient)
        {
            if(round_radius==undef)
            {
                cylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, center=true);
            }
            else
            {
                rcylinder(h=h+extra_h, r=r_+extra_r_, r1=r1_, r2=r2_, round_radius=round_radius);
            }
        }
    }
}

/*translate([10,0,0])*/
/*rotate_extrude()*/
        /*translate([10-2,2,0])*/
/*$fa = 5.6;*/
/*$fs = 0.3;*/
/*circle(r = 100);*/
/*torus(10, 2, align=[0,0,0], orient=[0,0,1]);*/

module torus(radius, radial_width, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[radius*2+radial_width*2, radius*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate([radius, 0, 0])
    circle(radial_width);
}

module rcylinder(d=undef, r1=undef, r2=undef, h=10, round_radius=2, align=[0,0,0], orient=[0,0,1])
{
    useDia = r == undef && (r1 == undef && r2 == undef);

    r1_ = useDia?((d1==undef?undef:d1)/2):r1;
    r2_ = useDia?((d2==undef?undef:d2)/2):r2;
    r_= useDia?[d/2,d/2]:(r==undef?[r1_,r2_]:[r,r]);
    size_align(align=align, orient=orient)
    /*translate([0,0,-h/2])*/
    hull()
    {
        /*a = r_[0]-r_[1];*/
        /*b = h;*/
        /*c = pythag_hyp(a,b);*/
        /*echo(c);*/
        /*d = c;//pythag_leg(a,c);*/
        /*echo(d);*/
        /*translate([0,r1-round_radius,0])*/
        /*cube([d,d,d]);*/
        /*angle2 = -atan2(-h, r1-r2);*/
        /*echo(angle2);*/
        /*x2 = r2-r1 < 0 ? (round_radius*2*cos(angle2)) : (round_radius*2*sin(angle2));*/
        /*echo(x2)*/
        /*translate([0, 0, h/2-round_radius])*/
        /*torus(radius=r_[1]-round_radius, radial_width=round_radius, align=[0,0,0]);*/

        for(z=[-1,1])
        translate([0, 0, z*(-h/2)])
        {
            /*rd = abs(r1-r2);*/
            /*angle1 = atan2(h, abs(r2-r1));*/
            /*x1 = round_radius*2*cos(angle1);*/
            /*echo(angle1, x1);*/
            r__=z!=-1?r_[0]:r_[1];
            torus(radius=r__-round_radius/2, radial_width=round_radius/2, align=[0,0,z]);

            /*translate([0, 0, -round_radius])*/
            /*cubea([r__*2,r__*2,5], align=[0,0,-z]);*/
        }
    }
}

module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    if(end_angle > start_angle)
    {
        intersection() {
            circle(r);
            polygon([
                    [0,0],
                    [R * cos(a0), R * sin(a0)],
                    [R * cos(a1), R * sin(a1)],
                    [R * cos(a2), R * sin(a2)],
                    [R * cos(a3), R * sin(a3)],
                    [R * cos(a4), R * sin(a4)],
                    [0,0]
            ]);
        }
    }
}

module pie_slice(r, start_angle, end_angle, h)
{
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

module hollow_cylinder(d=10, thickness=1, h=10, taper=false, taper_h=undef, orient=[0,0,1], align=[0,0,0])
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    size_align(size=[outer_d, outer_d, h], orient=orient, align=align)
    difference()
    {
        /*hull()*/
        union()
        {
            cylindera(h=h-taper_h*2, d=outer_d, orient=[0,0,1], align=[0,0,0]);
            taper_h = taper_h == undef ? (outer_d-inner_d)/4 : taper_h;
            /*taper_h_ = pythag_leg(taper_h, outer_d-inner_d);*/
            /*echo(taper_h_);*/
            if(taper)
            {
                for(z=[-1,1])
                translate([0,0,z*(h/2-taper_h)])
                mirror([0,0,z==-1?1:0])
                difference()
                {
                    cylindera(d1=outer_d, d2=outer_d-inner_d/4, h=taper_h*2, align=[0,0,1]);
                    cylindera(d1=inner_d, d2=outer_d, h=taper_h*2+.1, align=[0,0,1]);
                }
            }
        }

        cylindera(h=h+.4, d=inner_d, orient=[0,0,1], align=[0,0,0]);
    }
}

/**
 * Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module triangle(o_len, a_len, depth, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[a_len, depth, o_len], align=align, orient=orient)
    rotate([90,0,0])
    translate([-a_len/2, -o_len/2, -depth/2])
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]);
    }
}

/*triangle_a(45, 5, 5);*/
/*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,1]);*/
/*triangle(10, 15, 5, align=[1,1,1], orient=[0,0,1]);*/
/*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,-1]);*/

/**
 * Standard right-angled triangle (tangent version)
 *
 * @param number angle of adjacent to hypotenuse (ie tangent)
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 */
module triangle_a(tan_angle, a_len, depth)
{
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]);
    }
}

// Tests:
module test_triangles()
{
    // Generate a bunch of triangles by sizes
    for (i = [1:10])
    {
        translate([i*7, -30, i*7])
        {
            triangle(i*5, sqrt(i*5+pow(i,2)), 5);
        }
    }

    // Generate a bunch of triangles by angle
    for (i = [1:85/5])
    {
        translate([i*7, 22, i*7])
        {
            triangle_a(i*5, 10, 5);
        }
    }
}

/*hollow_cylinder(thickness=5, h=10, taper=true, orient=[0,0,1], align=[0,0,1]);*/
/*cylindera(d=10, h=10, orient=[0,0,1], align=[0,0,1]);*/
/*translate([10,0,0])*/
/*{*/
    /*hollow_cylinder(d=10, thickness=4, h=10, taper=true, taper_h=.5, orient=[0,0,1], align=[0,0,1]);*/
    /*cylindera(d=8, h=10, orient=[0,0,1], align=[0,0,1]);*/
/*}*/

/*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

/*cubea([10,10,10],[1,0,0]);*/
/*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

/*%cubea([10,10,10],[-1,0,1]);*/
/*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
/*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
/*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

/*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/

/*hull_pairwise()*/
{
    /*sphere(30/2);*/

/*translate([30,0,0])*/
    /*rcubea(s=[35,35,35], rounding_radius=10);*/
    /*rcubea(s=[35,35,35], align=[0,-1,0]);*/

/*translate([60,0,0])*/
    /*sphere(30/2);*/
}


attach: cleanup and add support for show_conn and explode

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

// From Obiscad,
// modified to take roll parameter as param in module instead of attachment points
//-------------------------------------------------------------------------
// ATTACH OPERATOR
// This operator applies the necessary transformations to the
// child (attachable part) so that it is attached to the main part
// Parameters
//  a: Connector of the main part
//  b: Connector of the attachable part
//  explode: extra translation between parts (child moved away from parent)
//  roll:
//  rollaxis:
//-------------------------------------------------------------------------
module attach(a, b, roll=0, rollaxis)
{
    // Get the data from the connectors
    // Attachment point. Main part
    pos1 = a[0];
    // Attachment axis. Main part
    v    = a[1];

    // Attachment point. Attachable part
    pos2 = b[0];
    // Atachment axis. Attachable part
    vref = b[1];

    // Calculations for the "orientate operator"
    // Calculate the rotation axis
    raxis = v_cross(vref,v);

    // Calculate the angle between the vectors
    ang = v_anglev(vref,v);

    raxis_=ang==180&&raxis==N?X:raxis;

    // Apply the transformations to the child

    // Place the attachable part on the main part attachment point
    t(pos1)
    // Orientate operator. Apply the orientation so that
    // both attachment axis are paralell. Also apply the roll angle
    r(a=roll, v=rollaxis==U?v:rollaxis)
    r(a=ang, v=raxis_)
    // Attachable part to the origin
    t(-pos2)
    t(-$explode==U?0:$explode*vref)
    {
        children();

        if($show_conn)
        connector([b.x, -b.y]);
    }

    if($show_conn)
    connector(a);
}

if(false)
{
    s=[10,10,10];

    conn = [X*s.x/2,X];

    /*connector(conn);*/
    cubea(s);
    attach(conn, -conn, $explode=2)
    spherea(d=s.x);
}

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

// From Obiscad,
// modified to take roll parameter as param in module instead of attachment points
//-------------------------------------------------------------------------
//--  ATTACH OPERATOR
//--  This operator applies the necesary transformations to the
//--  child (attachable part) so that it is attached to the main part
//--
//--  Parameters
//--    a -> Connector of the main part
//--    b -> Connector of the attachable part
//-------------------------------------------------------------------------
module attach(a, b, roll=0, rollaxis)
{
    //-- Get the data from the connectors
    pos1 = a[0];  //-- Attachment point. Main part
    v    = a[1];  //-- Attachment axis. Main part

    pos2 = b[0];  //-- Attachment point. Attachable part
    vref = b[1];  //-- Atachment axis. Attachable part

    //-------- Calculations for the "orientate operator"------
    //-- Calculate the rotation axis
    raxis = v_cross(vref,v);

    //-- Calculate the angle between the vectors
    ang = v_anglev(vref,v);
    //--------------------------------------------------------.-

    raxis_=ang==180&&raxis==N?X:raxis;

    //-- Apply the transformations to the child ---------------------------

    //-- Place the attachable part on the main part attachment point
    translate(pos1)
        //-- Orientate operator. Apply the orientation so that
        //-- both attachment axis are paralell. Also apply the roll angle
        rotate(a=roll, v=rollaxis==U?v:rollaxis)  rotate(a=ang, v=raxis_)
        //-- Attachable part to the origin
        translate(-pos2)
        children();
}