broke out 6 tooth gear into seperate file from gear library

// Parametric Involute Bevel and Spur Gears by GregFrost
// It is licensed under the Creative Commons - GNU GPL license.
// © 2010 by GregFrost
// http://www.thingiverse.com/thing:3575

// Simple Test:
/*// orig
  gear (circular_pitch=700,
	gear_thickness = 12,
	rim_thickness = 15,
	hub_thickness = 17,
	circles=8);
*/

/*
translate([225 - 12, 0, 0])
difference(){
  cylinder(h=ACRYLIC_THICKNESS, r=12*inch);
  translate([0, 0, -.01])scale([1, 1, 1.1])gear (number_of_teeth=225,
	circular_pitch=PITCH,
	gear_thickness = ACRYLIC_THICKNESS,
	rim_thickness = ACRYLIC_THICKNESS,
	hub_thickness = ACRYLIC_THICKNESS,
	bore_diameter=0. * mm,
	circles=0);
}
*/

//Complex Spur Gear Test:
// test_gears ();

// Meshing Double Helix:
//meshing_double_helix ();

// Demonstrate the backlash option for Spur gears.
// test_backlash ();

// Demonstrate how to make meshing bevel gears.
// bevel_gear_pair ();

pi=3.1415926535897932384626433832795;

//==================================================
// Bevel Gears:
// Two gears with the same cone distance, circular pitch (measured at the cone distance)
// and pressure angle will mesh.

module bevel_gear_pair (
	gear1_teeth = 41,
	gear2_teeth = 7,
	axis_angle = 90,
	outside_circular_pitch=1000)
{
	outside_pitch_radius1 = gear1_teeth * outside_circular_pitch / 360;
	outside_pitch_radius2 = gear2_teeth * outside_circular_pitch / 360;
	pitch_apex1=outside_pitch_radius2 * sin (axis_angle) +
		(outside_pitch_radius2 * cos (axis_angle) + outside_pitch_radius1) / tan (axis_angle);
	cone_distance = sqrt (pow (pitch_apex1, 2) + pow (outside_pitch_radius1, 2));
	pitch_apex2 = sqrt (pow (cone_distance, 2) - pow (outside_pitch_radius2, 2));
	echo ("cone_distance", cone_distance);
	pitch_angle1 = asin (outside_pitch_radius1 / cone_distance);
	pitch_angle2 = asin (outside_pitch_radius2 / cone_distance);
	echo ("pitch_angle1, pitch_angle2", pitch_angle1, pitch_angle2);
	echo ("pitch_angle1 + pitch_angle2", pitch_angle1 + pitch_angle2);

	rotate([0,0,90])
	translate ([0,0,pitch_apex1+20])
	{
		translate([0,0,-pitch_apex1])
		bevel_gear (
			number_of_teeth=gear1_teeth,
			cone_distance=cone_distance,
			pressure_angle=30,
			outside_circular_pitch=outside_circular_pitch);

		rotate([0,-(pitch_angle1+pitch_angle2),0])
		translate([0,0,-pitch_apex2])
		bevel_gear (
			number_of_teeth=gear2_teeth,
			cone_distance=cone_distance,
			pressure_angle=30,
			outside_circular_pitch=outside_circular_pitch);
	}
}

//Bevel Gear Finishing Options:
bevel_gear_flat = 0;
bevel_gear_back_cone = 1;

module bevel_gear (
	number_of_teeth=11,
	cone_distance=100,
	face_width=20,
	outside_circular_pitch=1000,
	pressure_angle=30,
	clearance = 0.2,
	bore_diameter=5,
	gear_thickness = 15,
	backlash = 0,
	involute_facets=0,
	finish = -1)
{
	echo ("bevel_gear",
		"teeth", number_of_teeth,
		"cone distance", cone_distance,
		face_width,
		outside_circular_pitch,
		pressure_angle,
		clearance,
		bore_diameter,
		involute_facets,
		finish);

	// Pitch diameter: Diameter of pitch circle at the fat end of the gear.
	outside_pitch_diameter  =  number_of_teeth * outside_circular_pitch / 180;
	outside_pitch_radius = outside_pitch_diameter / 2;

	// The height of the pitch apex.
	pitch_apex = sqrt (pow (cone_distance, 2) - pow (outside_pitch_radius, 2));
	pitch_angle = asin (outside_pitch_radius/cone_distance);

	echo ("Num Teeth:", number_of_teeth, " Pitch Angle:", pitch_angle);

	finish = (finish != -1) ? finish : (pitch_angle < 45) ? bevel_gear_flat : bevel_gear_back_cone;

	apex_to_apex=cone_distance / cos (pitch_angle);
	back_cone_radius = apex_to_apex * sin (pitch_angle);

	// Calculate and display the pitch angle. This is needed to determine the angle to mount two meshing cone gears.

	// Base Circle for forming the involute teeth shape.
	base_radius = back_cone_radius * cos (pressure_angle);

	// Diametrial pitch: Number of teeth per unit length.
	pitch_diametrial = number_of_teeth / outside_pitch_diameter;

	// Addendum: Radial distance from pitch circle to outside circle.
	addendum = 1 / pitch_diametrial;
	// Outer Circle
	outer_radius = back_cone_radius + addendum;

	// Dedendum: Radial distance from pitch circle to root diameter
	dedendum = addendum + clearance;
	dedendum_angle = atan (dedendum / cone_distance);
	root_angle = pitch_angle - dedendum_angle;

	root_cone_full_radius = tan (root_angle)*apex_to_apex;
	back_cone_full_radius=apex_to_apex / tan (pitch_angle);

	back_cone_end_radius =
		outside_pitch_radius -
		dedendum * cos (pitch_angle) -
		gear_thickness / tan (pitch_angle);
	back_cone_descent = dedendum * sin (pitch_angle) + gear_thickness;

	// Root diameter: Diameter of bottom of tooth spaces.
	root_radius = back_cone_radius - dedendum;

	half_tooth_thickness = outside_pitch_radius * sin (360 / (4 * number_of_teeth)) - backlash / 4;
	half_thick_angle = asin (half_tooth_thickness / back_cone_radius);

	face_cone_height = apex_to_apex-face_width / cos (pitch_angle);
	face_cone_full_radius = face_cone_height / tan (pitch_angle);
	face_cone_descent = dedendum * sin (pitch_angle);
	face_cone_end_radius =
		outside_pitch_radius -
		face_width / sin (pitch_angle) -
		face_cone_descent / tan (pitch_angle);

	// For the bevel_gear_flat finish option, calculate the height of a cube to select the portion of the gear that includes the full pitch face.
	bevel_gear_flat_height = pitch_apex - (cone_distance - face_width) * cos (pitch_angle);

//	translate([0,0,-pitch_apex])
	difference ()
	{
		intersection ()
		{
			union()
			{
				rotate (half_thick_angle)
				translate ([0,0,pitch_apex-apex_to_apex])
				cylinder ($fn=number_of_teeth*2, r1=root_cone_full_radius,r2=0,h=apex_to_apex);
				for (i = [1:number_of_teeth])
//				for (i = [1:1])
				{
					rotate ([0,0,i*360/number_of_teeth])
					{
						involute_bevel_gear_tooth (
							back_cone_radius = back_cone_radius,
							root_radius = root_radius,
							base_radius = base_radius,
							outer_radius = outer_radius,
							pitch_apex = pitch_apex,
							cone_distance = cone_distance,
							half_thick_angle = half_thick_angle,
							involute_facets = involute_facets);
					}
				}
			}

			if (finish == bevel_gear_back_cone)
			{
				translate ([0,0,-back_cone_descent])
				cylinder (
					$fn=number_of_teeth*2,
					r1=back_cone_end_radius,
					r2=back_cone_full_radius*2,
					h=apex_to_apex + back_cone_descent);
			}
			else
			{
				translate ([-1.5*outside_pitch_radius,-1.5*outside_pitch_radius,0])
				cube ([3*outside_pitch_radius,
					3*outside_pitch_radius,
					bevel_gear_flat_height]);
			}
		}

		if (finish == bevel_gear_back_cone)
		{
			translate ([0,0,-face_cone_descent])
			cylinder (
				r1=face_cone_end_radius,
				r2=face_cone_full_radius * 2,
				h=face_cone_height + face_cone_descent+pitch_apex);
		}

		translate ([0,0,pitch_apex - apex_to_apex])
		cylinder (r=bore_diameter/2,h=apex_to_apex);
	}
}

module involute_bevel_gear_tooth (
	back_cone_radius,
	root_radius,
	base_radius,
	outer_radius,
	pitch_apex,
	cone_distance,
	half_thick_angle,
	involute_facets)
{
//	echo ("involute_bevel_gear_tooth",
//		back_cone_radius,
//		root_radius,
//		base_radius,
//		outer_radius,
//		pitch_apex,
//		cone_distance,
//		half_thick_angle);

	min_radius = max (base_radius*2,root_radius*2);

	pitch_point =
		involute (
			base_radius*2,
			involute_intersect_angle (base_radius*2, back_cone_radius*2));
	pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
	centre_angle = pitch_angle + half_thick_angle;

	start_angle = involute_intersect_angle (base_radius*2, min_radius);
	stop_angle = involute_intersect_angle (base_radius*2, outer_radius*2);

	res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;

	translate ([0,0,pitch_apex])
	rotate ([0,-atan(back_cone_radius/cone_distance),0])
	translate ([-back_cone_radius*2,0,-cone_distance*2])
	union ()
	{
		for (i=[1:res])
		{
			assign (
				point1=
					involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i-1)/res),
				point2=
					involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i)/res))
			{
				assign (
					side1_point1 = rotate_point (centre_angle, point1),
					side1_point2 = rotate_point (centre_angle, point2),
					side2_point1 = mirror_point (rotate_point (centre_angle, point1)),
					side2_point2 = mirror_point (rotate_point (centre_angle, point2)))
				{
					polyhedron (
						points=[
							[back_cone_radius*2+0.1,0,cone_distance*2],
							[side1_point1[0],side1_point1[1],0],
							[side1_point2[0],side1_point2[1],0],
							[side2_point2[0],side2_point2[1],0],
							[side2_point1[0],side2_point1[1],0],
							[0.1,0,0]],
						triangles=[[0,1,2],[0,2,3],[0,3,4],[0,5,1],[1,5,2],[2,5,3],[3,5,4],[0,4,5]]);
				}
			}
		}
	}
}

module gear (
	number_of_teeth=15,
	circular_pitch=false, diametral_pitch=false,
	pressure_angle=28,
	clearance = 0.2,
	gear_thickness=5,
	rim_thickness=8,
	rim_width=5,
	hub_thickness=10,
	hub_diameter=15,
	bore_diameter=5,
	circles=0,
	backlash=0,
	twist=0,
	involute_facets=0)
{
	if (circular_pitch==false && diametral_pitch==false)
		echo("MCAD ERROR: gear module needs either a diametral_pitch or circular_pitch");

	//Convert diametrial pitch to our native circular pitch
	circular_pitch = (circular_pitch!=false?circular_pitch:180/diametral_pitch);

	// Pitch diameter: Diameter of pitch circle.
	pitch_diameter  =  number_of_teeth * circular_pitch / 180;
	pitch_radius = pitch_diameter/2;
	echo ("Teeth:", number_of_teeth, " Pitch radius:", pitch_radius);

	// Base Circle
	base_radius = pitch_radius*cos(pressure_angle);

	// Diametrial pitch: Number of teeth per unit length.
	pitch_diametrial = number_of_teeth / pitch_diameter;

	// Addendum: Radial distance from pitch circle to outside circle.
	addendum = 1/pitch_diametrial;

	//Outer Circle
	outer_radius = pitch_radius+addendum;

	// Dedendum: Radial distance from pitch circle to root diameter
	dedendum = addendum + clearance;

	// Root diameter: Diameter of bottom of tooth spaces.
	root_radius = pitch_radius-dedendum;
	backlash_angle = backlash / pitch_radius * 180 / pi;
	half_thick_angle = (360 / number_of_teeth - backlash_angle) / 4;

	// Variables controlling the rim.
	rim_radius = root_radius - rim_width;

	// Variables controlling the circular holes in the gear.
	circle_orbit_diameter=hub_diameter/2+rim_radius;
	circle_orbit_curcumference=pi*circle_orbit_diameter;

	// Limit the circle size to 90% of the gear face.
	circle_diameter=
		min (
			0.70*circle_orbit_curcumference/circles,
			(rim_radius-hub_diameter/2)*0.9);

	difference ()
	{
		union ()
		{
			difference ()
			{
				linear_extrude (height=rim_thickness, convexity=10, twist=twist)
				gear_shape (
					number_of_teeth,
					pitch_radius = pitch_radius,
					root_radius = root_radius,
					base_radius = base_radius,
					outer_radius = outer_radius,
					half_thick_angle = half_thick_angle,
					involute_facets=involute_facets);

				if (gear_thickness < rim_thickness)
					translate ([0,0,gear_thickness])
					cylinder (r=rim_radius,h=rim_thickness-gear_thickness+1);
			}
			if (gear_thickness > rim_thickness)
				cylinder (r=rim_radius,h=gear_thickness);
			if (hub_thickness > gear_thickness)
				translate ([0,0,gear_thickness])
				cylinder (r=hub_diameter/2,h=hub_thickness-gear_thickness);
		}
		translate ([0,0,-1])
		cylinder (
			r=bore_diameter/2,
			h=2+max(rim_thickness,hub_thickness,gear_thickness));
		if (circles>0)
		{
			for(i=[0:circles-1])
				rotate([0,0,i*360/circles])
				translate([circle_orbit_diameter/2,0,-1])
				cylinder(r=circle_diameter/2,h=max(gear_thickness,rim_thickness)+3);
		}
	}
}

module gear_shape (
	number_of_teeth,
	pitch_radius,
	root_radius,
	base_radius,
	outer_radius,
	half_thick_angle,
	involute_facets)
{
	union()
	{
		rotate (half_thick_angle) circle ($fn=number_of_teeth*2, r=root_radius);

		for (i = [1:number_of_teeth])
		{
			rotate ([0,0,i*360/number_of_teeth])
			{
				involute_gear_tooth (
					pitch_radius = pitch_radius,
					root_radius = root_radius,
					base_radius = base_radius,
					outer_radius = outer_radius,
					half_thick_angle = half_thick_angle,
					involute_facets=involute_facets);
			}
		}
	}
}

module involute_gear_tooth (
	pitch_radius,
	root_radius,
	base_radius,
	outer_radius,
	half_thick_angle,
	involute_facets)
{
	min_radius = max (base_radius,root_radius);

	pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
	pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
	centre_angle = pitch_angle + half_thick_angle;

	start_angle = involute_intersect_angle (base_radius, min_radius);
	stop_angle = involute_intersect_angle (base_radius, outer_radius);

	res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;

	union ()
	{
		for (i=[1:res])
		assign (
			point1=involute (base_radius,start_angle+(stop_angle - start_angle)*(i-1)/res),
			point2=involute (base_radius,start_angle+(stop_angle - start_angle)*i/res))
		{
			assign (
				side1_point1=rotate_point (centre_angle, point1),
				side1_point2=rotate_point (centre_angle, point2),
				side2_point1=mirror_point (rotate_point (centre_angle, point1)),
				side2_point2=mirror_point (rotate_point (centre_angle, point2)))
			{
				polygon (
					points=[[0,0],side1_point1,side1_point2,side2_point2,side2_point1],
					paths=[[0,1,2,3,4,0]]);
			}
		}
	}
}

// Mathematical Functions
//===============

// Finds the angle of the involute about the base radius at the given distance (radius) from it's center.
//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html

function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / pi;

// Calculate the involute position for a given base radius and involute angle.

function rotated_involute (rotate, base_radius, involute_angle) =
[
	cos (rotate) * involute (base_radius, involute_angle)[0] + sin (rotate) * involute (base_radius, involute_angle)[1],
	cos (rotate) * involute (base_radius, involute_angle)[1] - sin (rotate) * involute (base_radius, involute_angle)[0]
];

function mirror_point (coord) =
[
	coord[0],
	-coord[1]
];

function rotate_point (rotate, coord) =
[
	cos (rotate) * coord[0] + sin (rotate) * coord[1],
	cos (rotate) * coord[1] - sin (rotate) * coord[0]
];

function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*pi/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*pi/180*cos (involute_angle)),
];

// Test Cases
//===============

module test_gears()
{
	translate([17,-15])
	{
		gear (number_of_teeth=17,
			circular_pitch=500,
			circles=8);

		rotate ([0,0,360*4/17])
		translate ([39.088888,0,0])
		{
			gear (number_of_teeth=11,
				circular_pitch=500,
				hub_diameter=0,
				rim_width=65);
			translate ([0,0,8])
			{
				gear (number_of_teeth=6,
					circular_pitch=300,
					hub_diameter=0,
					rim_width=5,
					rim_thickness=6,
					pressure_angle=31);
				rotate ([0,0,360*5/6])
				translate ([22.5,0,1])
				gear (number_of_teeth=21,
					circular_pitch=300,
					bore_diameter=2,
					hub_diameter=4,
					rim_width=1,
					hub_thickness=4,
					rim_thickness=4,
					gear_thickness=3,
					pressure_angle=31);
			}
		}

		translate ([-61.1111111,0,0])
		{
			gear (number_of_teeth=27,
				circular_pitch=500,
				circles=5,
				hub_diameter=2*8.88888889);

			translate ([0,0,10])
			{
				gear (
					number_of_teeth=14,
					circular_pitch=200,
					pressure_angle=5,
					clearance = 0.2,
					gear_thickness = 10,
					rim_thickness = 10,
					rim_width = 15,
					bore_diameter=5,
					circles=0);
				translate ([13.8888888,0,1])
				gear (
					number_of_teeth=11,
					circular_pitch=200,
					pressure_angle=5,
					clearance = 0.2,
					gear_thickness = 10,
					rim_thickness = 10,
					rim_width = 15,
					hub_thickness = 20,
					hub_diameter=2*7.222222,
					bore_diameter=5,
					circles=0);
			}
		}

		rotate ([0,0,360*-5/17])
		translate ([44.444444444,0,0])
		gear (number_of_teeth=15,
			circular_pitch=500,
			hub_diameter=10,
			rim_width=5,
			rim_thickness=5,
			gear_thickness=4,
			hub_thickness=6,
			circles=9);

		rotate ([0,0,360*-1/17])
		translate ([30.5555555,0,-1])
		gear (number_of_teeth=5,
			circular_pitch=500,
			hub_diameter=0,
			rim_width=5,
			rim_thickness=10);
	}
}

module meshing_double_helix ()
{
	test_double_helix_gear ();

	mirror ([0,1,0])
	translate ([58.33333333,0,0])
	test_double_helix_gear (teeth=13,circles=6);
}

module test_double_helix_gear (
	teeth=17,
	circles=8)
{
	//double helical gear
	{
		twist=200;
		height=20;
		pressure_angle=30;

		gear (number_of_teeth=teeth,
			circular_pitch=700,
			pressure_angle=pressure_angle,
			clearance = 0.2,
			gear_thickness = height/2*0.5,
			rim_thickness = height/2,
			rim_width = 5,
			hub_thickness = height/2*1.2,
			hub_diameter=15,
			bore_diameter=5,
			circles=circles,
			twist=twist/teeth);
		mirror([0,0,1])
		gear (number_of_teeth=teeth,
			circular_pitch=700,
			pressure_angle=pressure_angle,
			clearance = 0.2,
			gear_thickness = height/2,
			rim_thickness = height/2,
			rim_width = 5,
			hub_thickness = height/2,
			hub_diameter=15,
			bore_diameter=5,
			circles=circles,
			twist=twist/teeth);
	}
}

module test_backlash ()
{
	backlash = 2;
	teeth = 15;

	translate ([-29.166666,0,0])
	{
		translate ([58.3333333,0,0])
		rotate ([0,0,-360/teeth/4])
		gear (
			number_of_teeth = teeth,
			circular_pitch=700,
			gear_thickness = 12,
			rim_thickness = 15,
			rim_width = 5,
			hub_thickness = 17,
			hub_diameter=15,
			bore_diameter=5,
			backlash = 2,
			circles=8);

		rotate ([0,0,360/teeth/4])
		gear (
			number_of_teeth = teeth,
			circular_pitch=700,
			gear_thickness = 12,
			rim_thickness = 15,
			rim_width = 5,
			hub_thickness = 17,
			hub_diameter=15,
			bore_diameter=5,
			backlash = 2,
			circles=8);
	}

	color([0,0,128,0.5])
	translate([0,0,-5])
	cylinder ($fn=20,r=backlash / 4,h=25);
}

// Parametric Involute Bevel and Spur Gears by GregFrost
// It is licensed under the Creative Commons - GNU GPL license.
// © 2010 by GregFrost
// http://www.thingiverse.com/thing:3575

$fn=100;
mm = 1;
inch = 25.4 * mm;

// Simple Test:
/*// orig
  gear (circular_pitch=700,
	gear_thickness = 12,
	rim_thickness = 15,
	hub_thickness = 17,
	circles=8);
*/

ACRYLIC_THICKNESS = 6 * mm;
ACRYLIC_TOL = .5 * mm;
PITCH = 400. * 12 / 13.333333;
difference(){
  union(){
    gear (number_of_teeth=6,
	  circular_pitch = PITCH,
	  gear_thickness = ACRYLIC_THICKNESS + ACRYLIC_TOL,
	  rim_thickness = ACRYLIC_THICKNESS + ACRYLIC_TOL,
	  hub_thickness = ACRYLIC_THICKNESS + ACRYLIC_TOL,
	  bore_diameter=0. * mm,
	  circles=4,
	  pressure_angle=28
	  );
    translate([0, 0, -1*mm])cylinder(r=10.5 * mm, h=1*mm);
    translate([0, 0, 6.5*mm])cylinder(r=8.5 * mm, h=1*mm);
  }
  translate([0, 0, -1])cylinder(r=3mm, h=ACRYLIC_THICKNESS + ACRYLIC_TOL + 2);
}

/*
translate([225 - 12, 0, 0])
difference(){
  cylinder(h=ACRYLIC_THICKNESS, r=12*inch);
  translate([0, 0, -.01])scale([1, 1, 1.1])gear (number_of_teeth=225,
	circular_pitch=PITCH,
	gear_thickness = ACRYLIC_THICKNESS,
	rim_thickness = ACRYLIC_THICKNESS,
	hub_thickness = ACRYLIC_THICKNESS,
	bore_diameter=0. * mm,
	circles=0);
}
*/

//Complex Spur Gear Test:
// test_gears ();

// Meshing Double Helix:
//meshing_double_helix ();

// Demonstrate the backlash option for Spur gears.
// test_backlash ();

// Demonstrate how to make meshing bevel gears.
// bevel_gear_pair ();

pi=3.1415926535897932384626433832795;

//==================================================
// Bevel Gears:
// Two gears with the same cone distance, circular pitch (measured at the cone distance)
// and pressure angle will mesh.

module bevel_gear_pair (
	gear1_teeth = 41,
	gear2_teeth = 7,
	axis_angle = 90,
	outside_circular_pitch=1000)
{
	outside_pitch_radius1 = gear1_teeth * outside_circular_pitch / 360;
	outside_pitch_radius2 = gear2_teeth * outside_circular_pitch / 360;
	pitch_apex1=outside_pitch_radius2 * sin (axis_angle) +
		(outside_pitch_radius2 * cos (axis_angle) + outside_pitch_radius1) / tan (axis_angle);
	cone_distance = sqrt (pow (pitch_apex1, 2) + pow (outside_pitch_radius1, 2));
	pitch_apex2 = sqrt (pow (cone_distance, 2) - pow (outside_pitch_radius2, 2));
	echo ("cone_distance", cone_distance);
	pitch_angle1 = asin (outside_pitch_radius1 / cone_distance);
	pitch_angle2 = asin (outside_pitch_radius2 / cone_distance);
	echo ("pitch_angle1, pitch_angle2", pitch_angle1, pitch_angle2);
	echo ("pitch_angle1 + pitch_angle2", pitch_angle1 + pitch_angle2);

	rotate([0,0,90])
	translate ([0,0,pitch_apex1+20])
	{
		translate([0,0,-pitch_apex1])
		bevel_gear (
			number_of_teeth=gear1_teeth,
			cone_distance=cone_distance,
			pressure_angle=30,
			outside_circular_pitch=outside_circular_pitch);

		rotate([0,-(pitch_angle1+pitch_angle2),0])
		translate([0,0,-pitch_apex2])
		bevel_gear (
			number_of_teeth=gear2_teeth,
			cone_distance=cone_distance,
			pressure_angle=30,
			outside_circular_pitch=outside_circular_pitch);
	}
}

//Bevel Gear Finishing Options:
bevel_gear_flat = 0;
bevel_gear_back_cone = 1;

module bevel_gear (
	number_of_teeth=11,
	cone_distance=100,
	face_width=20,
	outside_circular_pitch=1000,
	pressure_angle=30,
	clearance = 0.2,
	bore_diameter=5,
	gear_thickness = 15,
	backlash = 0,
	involute_facets=0,
	finish = -1)
{
	echo ("bevel_gear",
		"teeth", number_of_teeth,
		"cone distance", cone_distance,
		face_width,
		outside_circular_pitch,
		pressure_angle,
		clearance,
		bore_diameter,
		involute_facets,
		finish);

	// Pitch diameter: Diameter of pitch circle at the fat end of the gear.
	outside_pitch_diameter  =  number_of_teeth * outside_circular_pitch / 180;
	outside_pitch_radius = outside_pitch_diameter / 2;

	// The height of the pitch apex.
	pitch_apex = sqrt (pow (cone_distance, 2) - pow (outside_pitch_radius, 2));
	pitch_angle = asin (outside_pitch_radius/cone_distance);

	echo ("Num Teeth:", number_of_teeth, " Pitch Angle:", pitch_angle);

	finish = (finish != -1) ? finish : (pitch_angle < 45) ? bevel_gear_flat : bevel_gear_back_cone;

	apex_to_apex=cone_distance / cos (pitch_angle);
	back_cone_radius = apex_to_apex * sin (pitch_angle);

	// Calculate and display the pitch angle. This is needed to determine the angle to mount two meshing cone gears.

	// Base Circle for forming the involute teeth shape.
	base_radius = back_cone_radius * cos (pressure_angle);

	// Diametrial pitch: Number of teeth per unit length.
	pitch_diametrial = number_of_teeth / outside_pitch_diameter;

	// Addendum: Radial distance from pitch circle to outside circle.
	addendum = 1 / pitch_diametrial;
	// Outer Circle
	outer_radius = back_cone_radius + addendum;

	// Dedendum: Radial distance from pitch circle to root diameter
	dedendum = addendum + clearance;
	dedendum_angle = atan (dedendum / cone_distance);
	root_angle = pitch_angle - dedendum_angle;

	root_cone_full_radius = tan (root_angle)*apex_to_apex;
	back_cone_full_radius=apex_to_apex / tan (pitch_angle);

	back_cone_end_radius =
		outside_pitch_radius -
		dedendum * cos (pitch_angle) -
		gear_thickness / tan (pitch_angle);
	back_cone_descent = dedendum * sin (pitch_angle) + gear_thickness;

	// Root diameter: Diameter of bottom of tooth spaces.
	root_radius = back_cone_radius - dedendum;

	half_tooth_thickness = outside_pitch_radius * sin (360 / (4 * number_of_teeth)) - backlash / 4;
	half_thick_angle = asin (half_tooth_thickness / back_cone_radius);

	face_cone_height = apex_to_apex-face_width / cos (pitch_angle);
	face_cone_full_radius = face_cone_height / tan (pitch_angle);
	face_cone_descent = dedendum * sin (pitch_angle);
	face_cone_end_radius =
		outside_pitch_radius -
		face_width / sin (pitch_angle) -
		face_cone_descent / tan (pitch_angle);

	// For the bevel_gear_flat finish option, calculate the height of a cube to select the portion of the gear that includes the full pitch face.
	bevel_gear_flat_height = pitch_apex - (cone_distance - face_width) * cos (pitch_angle);

//	translate([0,0,-pitch_apex])
	difference ()
	{
		intersection ()
		{
			union()
			{
				rotate (half_thick_angle)
				translate ([0,0,pitch_apex-apex_to_apex])
				cylinder ($fn=number_of_teeth*2, r1=root_cone_full_radius,r2=0,h=apex_to_apex);
				for (i = [1:number_of_teeth])
//				for (i = [1:1])
				{
					rotate ([0,0,i*360/number_of_teeth])
					{
						involute_bevel_gear_tooth (
							back_cone_radius = back_cone_radius,
							root_radius = root_radius,
							base_radius = base_radius,
							outer_radius = outer_radius,
							pitch_apex = pitch_apex,
							cone_distance = cone_distance,
							half_thick_angle = half_thick_angle,
							involute_facets = involute_facets);
					}
				}
			}

			if (finish == bevel_gear_back_cone)
			{
				translate ([0,0,-back_cone_descent])
				cylinder (
					$fn=number_of_teeth*2,
					r1=back_cone_end_radius,
					r2=back_cone_full_radius*2,
					h=apex_to_apex + back_cone_descent);
			}
			else
			{
				translate ([-1.5*outside_pitch_radius,-1.5*outside_pitch_radius,0])
				cube ([3*outside_pitch_radius,
					3*outside_pitch_radius,
					bevel_gear_flat_height]);
			}
		}

		if (finish == bevel_gear_back_cone)
		{
			translate ([0,0,-face_cone_descent])
			cylinder (
				r1=face_cone_end_radius,
				r2=face_cone_full_radius * 2,
				h=face_cone_height + face_cone_descent+pitch_apex);
		}

		translate ([0,0,pitch_apex - apex_to_apex])
		cylinder (r=bore_diameter/2,h=apex_to_apex);
	}
}

module involute_bevel_gear_tooth (
	back_cone_radius,
	root_radius,
	base_radius,
	outer_radius,
	pitch_apex,
	cone_distance,
	half_thick_angle,
	involute_facets)
{
//	echo ("involute_bevel_gear_tooth",
//		back_cone_radius,
//		root_radius,
//		base_radius,
//		outer_radius,
//		pitch_apex,
//		cone_distance,
//		half_thick_angle);

	min_radius = max (base_radius*2,root_radius*2);

	pitch_point =
		involute (
			base_radius*2,
			involute_intersect_angle (base_radius*2, back_cone_radius*2));
	pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
	centre_angle = pitch_angle + half_thick_angle;

	start_angle = involute_intersect_angle (base_radius*2, min_radius);
	stop_angle = involute_intersect_angle (base_radius*2, outer_radius*2);

	res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;

	translate ([0,0,pitch_apex])
	rotate ([0,-atan(back_cone_radius/cone_distance),0])
	translate ([-back_cone_radius*2,0,-cone_distance*2])
	union ()
	{
		for (i=[1:res])
		{
			assign (
				point1=
					involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i-1)/res),
				point2=
					involute (base_radius*2,start_angle+(stop_angle - start_angle)*(i)/res))
			{
				assign (
					side1_point1 = rotate_point (centre_angle, point1),
					side1_point2 = rotate_point (centre_angle, point2),
					side2_point1 = mirror_point (rotate_point (centre_angle, point1)),
					side2_point2 = mirror_point (rotate_point (centre_angle, point2)))
				{
					polyhedron (
						points=[
							[back_cone_radius*2+0.1,0,cone_distance*2],
							[side1_point1[0],side1_point1[1],0],
							[side1_point2[0],side1_point2[1],0],
							[side2_point2[0],side2_point2[1],0],
							[side2_point1[0],side2_point1[1],0],
							[0.1,0,0]],
						triangles=[[0,1,2],[0,2,3],[0,3,4],[0,5,1],[1,5,2],[2,5,3],[3,5,4],[0,4,5]]);
				}
			}
		}
	}
}

module gear (
	number_of_teeth=15,
	circular_pitch=false, diametral_pitch=false,
	pressure_angle=28,
	clearance = 0.2,
	gear_thickness=5,
	rim_thickness=8,
	rim_width=5,
	hub_thickness=10,
	hub_diameter=15,
	bore_diameter=5,
	circles=0,
	backlash=0,
	twist=0,
	involute_facets=0)
{
	if (circular_pitch==false && diametral_pitch==false)
		echo("MCAD ERROR: gear module needs either a diametral_pitch or circular_pitch");

	//Convert diametrial pitch to our native circular pitch
	circular_pitch = (circular_pitch!=false?circular_pitch:180/diametral_pitch);

	// Pitch diameter: Diameter of pitch circle.
	pitch_diameter  =  number_of_teeth * circular_pitch / 180;
	pitch_radius = pitch_diameter/2;
	echo ("Teeth:", number_of_teeth, " Pitch radius:", pitch_radius);

	// Base Circle
	base_radius = pitch_radius*cos(pressure_angle);

	// Diametrial pitch: Number of teeth per unit length.
	pitch_diametrial = number_of_teeth / pitch_diameter;

	// Addendum: Radial distance from pitch circle to outside circle.
	addendum = 1/pitch_diametrial;

	//Outer Circle
	outer_radius = pitch_radius+addendum;

	// Dedendum: Radial distance from pitch circle to root diameter
	dedendum = addendum + clearance;

	// Root diameter: Diameter of bottom of tooth spaces.
	root_radius = pitch_radius-dedendum;
	backlash_angle = backlash / pitch_radius * 180 / pi;
	half_thick_angle = (360 / number_of_teeth - backlash_angle) / 4;

	// Variables controlling the rim.
	rim_radius = root_radius - rim_width;

	// Variables controlling the circular holes in the gear.
	circle_orbit_diameter=hub_diameter/2+rim_radius;
	circle_orbit_curcumference=pi*circle_orbit_diameter;

	// Limit the circle size to 90% of the gear face.
	circle_diameter=
		min (
			0.70*circle_orbit_curcumference/circles,
			(rim_radius-hub_diameter/2)*0.9);

	difference ()
	{
		union ()
		{
			difference ()
			{
				linear_extrude (height=rim_thickness, convexity=10, twist=twist)
				gear_shape (
					number_of_teeth,
					pitch_radius = pitch_radius,
					root_radius = root_radius,
					base_radius = base_radius,
					outer_radius = outer_radius,
					half_thick_angle = half_thick_angle,
					involute_facets=involute_facets);

				if (gear_thickness < rim_thickness)
					translate ([0,0,gear_thickness])
					cylinder (r=rim_radius,h=rim_thickness-gear_thickness+1);
			}
			if (gear_thickness > rim_thickness)
				cylinder (r=rim_radius,h=gear_thickness);
			if (hub_thickness > gear_thickness)
				translate ([0,0,gear_thickness])
				cylinder (r=hub_diameter/2,h=hub_thickness-gear_thickness);
		}
		translate ([0,0,-1])
		cylinder (
			r=bore_diameter/2,
			h=2+max(rim_thickness,hub_thickness,gear_thickness));
		if (circles>0)
		{
			for(i=[0:circles-1])
				rotate([0,0,i*360/circles])
				translate([circle_orbit_diameter/2,0,-1])
				cylinder(r=circle_diameter/2,h=max(gear_thickness,rim_thickness)+3);
		}
	}
}

module gear_shape (
	number_of_teeth,
	pitch_radius,
	root_radius,
	base_radius,
	outer_radius,
	half_thick_angle,
	involute_facets)
{
	union()
	{
		rotate (half_thick_angle) circle ($fn=number_of_teeth*2, r=root_radius);

		for (i = [1:number_of_teeth])
		{
			rotate ([0,0,i*360/number_of_teeth])
			{
				involute_gear_tooth (
					pitch_radius = pitch_radius,
					root_radius = root_radius,
					base_radius = base_radius,
					outer_radius = outer_radius,
					half_thick_angle = half_thick_angle,
					involute_facets=involute_facets);
			}
		}
	}
}

module involute_gear_tooth (
	pitch_radius,
	root_radius,
	base_radius,
	outer_radius,
	half_thick_angle,
	involute_facets)
{
	min_radius = max (base_radius,root_radius);

	pitch_point = involute (base_radius, involute_intersect_angle (base_radius, pitch_radius));
	pitch_angle = atan2 (pitch_point[1], pitch_point[0]);
	centre_angle = pitch_angle + half_thick_angle;

	start_angle = involute_intersect_angle (base_radius, min_radius);
	stop_angle = involute_intersect_angle (base_radius, outer_radius);

	res=(involute_facets!=0)?involute_facets:($fn==0)?5:$fn/4;

	union ()
	{
		for (i=[1:res])
		assign (
			point1=involute (base_radius,start_angle+(stop_angle - start_angle)*(i-1)/res),
			point2=involute (base_radius,start_angle+(stop_angle - start_angle)*i/res))
		{
			assign (
				side1_point1=rotate_point (centre_angle, point1),
				side1_point2=rotate_point (centre_angle, point2),
				side2_point1=mirror_point (rotate_point (centre_angle, point1)),
				side2_point2=mirror_point (rotate_point (centre_angle, point2)))
			{
				polygon (
					points=[[0,0],side1_point1,side1_point2,side2_point2,side2_point1],
					paths=[[0,1,2,3,4,0]]);
			}
		}
	}
}

// Mathematical Functions
//===============

// Finds the angle of the involute about the base radius at the given distance (radius) from it's center.
//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html

function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base_radius, 2) - 1) * 180 / pi;

// Calculate the involute position for a given base radius and involute angle.

function rotated_involute (rotate, base_radius, involute_angle) =
[
	cos (rotate) * involute (base_radius, involute_angle)[0] + sin (rotate) * involute (base_radius, involute_angle)[1],
	cos (rotate) * involute (base_radius, involute_angle)[1] - sin (rotate) * involute (base_radius, involute_angle)[0]
];

function mirror_point (coord) =
[
	coord[0],
	-coord[1]
];

function rotate_point (rotate, coord) =
[
	cos (rotate) * coord[0] + sin (rotate) * coord[1],
	cos (rotate) * coord[1] - sin (rotate) * coord[0]
];

function involute (base_radius, involute_angle) =
[
	base_radius*(cos (involute_angle) + involute_angle*pi/180*sin (involute_angle)),
	base_radius*(sin (involute_angle) - involute_angle*pi/180*cos (involute_angle)),
];

// Test Cases
//===============

module test_gears()
{
	translate([17,-15])
	{
		gear (number_of_teeth=17,
			circular_pitch=500,
			circles=8);

		rotate ([0,0,360*4/17])
		translate ([39.088888,0,0])
		{
			gear (number_of_teeth=11,
				circular_pitch=500,
				hub_diameter=0,
				rim_width=65);
			translate ([0,0,8])
			{
				gear (number_of_teeth=6,
					circular_pitch=300,
					hub_diameter=0,
					rim_width=5,
					rim_thickness=6,
					pressure_angle=31);
				rotate ([0,0,360*5/6])
				translate ([22.5,0,1])
				gear (number_of_teeth=21,
					circular_pitch=300,
					bore_diameter=2,
					hub_diameter=4,
					rim_width=1,
					hub_thickness=4,
					rim_thickness=4,
					gear_thickness=3,
					pressure_angle=31);
			}
		}

		translate ([-61.1111111,0,0])
		{
			gear (number_of_teeth=27,
				circular_pitch=500,
				circles=5,
				hub_diameter=2*8.88888889);

			translate ([0,0,10])
			{
				gear (
					number_of_teeth=14,
					circular_pitch=200,
					pressure_angle=5,
					clearance = 0.2,
					gear_thickness = 10,
					rim_thickness = 10,
					rim_width = 15,
					bore_diameter=5,
					circles=0);
				translate ([13.8888888,0,1])
				gear (
					number_of_teeth=11,
					circular_pitch=200,
					pressure_angle=5,
					clearance = 0.2,
					gear_thickness = 10,
					rim_thickness = 10,
					rim_width = 15,
					hub_thickness = 20,
					hub_diameter=2*7.222222,
					bore_diameter=5,
					circles=0);
			}
		}

		rotate ([0,0,360*-5/17])
		translate ([44.444444444,0,0])
		gear (number_of_teeth=15,
			circular_pitch=500,
			hub_diameter=10,
			rim_width=5,
			rim_thickness=5,
			gear_thickness=4,
			hub_thickness=6,
			circles=9);

		rotate ([0,0,360*-1/17])
		translate ([30.5555555,0,-1])
		gear (number_of_teeth=5,
			circular_pitch=500,
			hub_diameter=0,
			rim_width=5,
			rim_thickness=10);
	}
}

module meshing_double_helix ()
{
	test_double_helix_gear ();

	mirror ([0,1,0])
	translate ([58.33333333,0,0])
	test_double_helix_gear (teeth=13,circles=6);
}

module test_double_helix_gear (
	teeth=17,
	circles=8)
{
	//double helical gear
	{
		twist=200;
		height=20;
		pressure_angle=30;

		gear (number_of_teeth=teeth,
			circular_pitch=700,
			pressure_angle=pressure_angle,
			clearance = 0.2,
			gear_thickness = height/2*0.5,
			rim_thickness = height/2,
			rim_width = 5,
			hub_thickness = height/2*1.2,
			hub_diameter=15,
			bore_diameter=5,
			circles=circles,
			twist=twist/teeth);
		mirror([0,0,1])
		gear (number_of_teeth=teeth,
			circular_pitch=700,
			pressure_angle=pressure_angle,
			clearance = 0.2,
			gear_thickness = height/2,
			rim_thickness = height/2,
			rim_width = 5,
			hub_thickness = height/2,
			hub_diameter=15,
			bore_diameter=5,
			circles=circles,
			twist=twist/teeth);
	}
}

module test_backlash ()
{
	backlash = 2;
	teeth = 15;

	translate ([-29.166666,0,0])
	{
		translate ([58.3333333,0,0])
		rotate ([0,0,-360/teeth/4])
		gear (
			number_of_teeth = teeth,
			circular_pitch=700,
			gear_thickness = 12,
			rim_thickness = 15,
			rim_width = 5,
			hub_thickness = 17,
			hub_diameter=15,
			bore_diameter=5,
			backlash = 2,
			circles=8);

		rotate ([0,0,360/teeth/4])
		gear (
			number_of_teeth = teeth,
			circular_pitch=700,
			gear_thickness = 12,
			rim_thickness = 15,
			rim_width = 5,
			hub_thickness = 17,
			hub_diameter=15,
			bore_diameter=5,
			backlash = 2,
			circles=8);
	}

	color([0,0,128,0.5])
	translate([0,0,-5])
	cylinder ($fn=20,r=backlash / 4,h=25);
}


encoders are in the lid cutout

encoders are in the lid cutout

$fn = 64;

// interference fit adjustment for 3D printer
iFitAdjust = .4;
iFitAdjust_d = .25;

// waveshare 5" knock off
displayScreenWidth = 118;
displayScreenHeight = 70;
displayScreenThickness = 3;
displayBoardWidth = 122;
displayBoardHeight = 78.5;
displayBoardThickness = 7;
displayDepth = 22;
displayScrewDiameter = 3;
module display() {
    // screen
    %translate([-displayScreenWidth / 2, -displayScreenHeight / 2, 0])
        cube([displayScreenWidth, displayScreenHeight, displayScreenThickness], center=false);
    // board
    %translate([-displayBoardWidth / 2, -displayBoardHeight / 2, -displayBoardThickness])
        cube([displayBoardWidth, displayBoardHeight, displayBoardThickness], center=false);
}

module display_mount() {
    // corner tabs
    #for (i = [-1,1])
        for (j = [-1,1]) {
            translate([i * displayBoardWidth/2, j * displayBoardHeight/2, -displayBoardThickness])
                difference() {
                    cube([displayMountTabWidth, displayMountTabHeight, displayMountTabThickness], center=true);
                    translate([i * 2, j * 2, -displayBoardThickness / 2])
                        cylinder(h=displayBoardThickness + 2, r = displayScrewDiameter + iFitAdjust_d);
                }
        }
}

displayMountTabThickness = 3;
displayMountTabWidth = 15;
displayMountTabHeight = 20;
module display_mount_tabs() {
    // corner tabs
    for (i = [-1,1])
        for (j = [-1,1]) {
            translate([i * displayBoardWidth/2, j * displayBoardHeight/2, -displayBoardThickness - displayMountTabThickness / 2])
                difference() {
                    cube([displayMountTabWidth, displayMountTabHeight, displayMountTabThickness], center=true);
                    translate([i * 2, j * 2, -displayBoardThickness / 2])
                        cylinder(h=displayBoardThickness + 2, r = displayScrewDiameter + iFitAdjust_d);
                }
        }
}

// encoders
encoderShaftDiameter = 7;
encoderShaftHeight = 18;
encoderWidth = 18;
encoderLength = 31;
encoderDepth = 8.2;
module encoder() {
    // encoder shaft
    cylinder(h = encoderShaftHeight, d = encoderShaftDiameter, center=false);
    // encoder base
    translate([-encoderWidth/2, -encoderLength/2, -encoderDepth/2])
        cube([encoderWidth, encoderLength, encoderDepth]);
}

// lid with screen and encoders
lidThickness = displayScreenThickness - .5;
module lid() {
  display_mount_tabs();
  display_mount();
  difference() {
    // face plate
    translate([-(displayBoardWidth * 1.5 + encoderWidth * 1.1)/2, -(displayBoardHeight * 1.25 + encoderLength)/2, 0])
        cube([displayBoardWidth * 1.5 + encoderWidth * 1.1, displayBoardHeight * 1.25 +            encoderLength, lidThickness]);
    // screen cutout
    display();
    // encoder cutout
    %for (i = [-1,1])
        for (j = [-1,1]) {
            translate([i * displayBoardWidth/2 + i * encoderWidth, j * displayBoardHeight/2, - encoderShaftHeight / 2 + 2])
                encoder();
        }
    // screw holes
  }
}

// box with pi mounts and holes
module box() {
    // bottom
    // pi mount holes
    // sides
    // pi usb / ethernet
    // hifi audio out
}

//display();
//encoder();
lid();

$fn = 64;

// interference fit adjustment for 3D printer
iFitAdjust = .4;
iFitAdjust_d = .25;

// waveshare 5" knock off
displayScreenWidth = 118;
displayScreenHeight = 70;
displayScreenThickness = 3;
displayBoardWidth = 122;
displayBoardHeight = 78.5;
displayBoardThickness = 7;
displayDepth = 22;
displayScrewDiameter = 3;
module display() {
    // screen
    %translate([-displayScreenWidth / 2, -displayScreenHeight / 2, 0])
        cube([displayScreenWidth, displayScreenHeight, displayScreenThickness], center=false);
    // board
    %translate([-displayBoardWidth / 2, -displayBoardHeight / 2, -displayBoardThickness])
        cube([displayBoardWidth, displayBoardHeight, displayBoardThickness], center=false);
    // corner tabs
    for (i = [-1,1])
        for (j = [-1,1]) {
            translate([i * displayBoardWidth/2, j * displayBoardHeight/2, -displayBoardThickness])
                difference() {
                    cube([20, 20, 3], center=true);
                    translate([i *2, j * 2, -displayBoardThickness / 2])
                        cylinder(h=displayBoardThickness + 2, r = displayScrewDiameter + iFitAdjust_d);
                }
        }
}

// encoders
encoderShaftDiameter = 7;
encoderShaftHeight = 18;
encoderWidth = 18;
encoderLength = 31;
encoderDepth = 8.2;
module encoder() {
    // encoder shaft
    cylinder(h = encoderShaftHeight, d = encoderShaftDiameter, center=false);
    // encoder base
    translate([-encoderWidth/2, -encoderLength/2, -encoderDepth/2])
        cube([encoderWidth, encoderLength, encoderDepth]);
}

// lid with screen and encoders
module lid() {
  difference() {
    // face plate
    translate([-(displayBoardWidth * 1.5 + encoderWidth * 1.1)/2, -(displayBoardHeight * 1.25 + encoderLength)/2, -displayBoardThickness / 2])
        cube([displayBoardWidth * 1.5 + encoderWidth * 1.1, displayBoardHeight * 1.25 +            encoderLength, displayScreenThickness / .5 ]);
    // screen cutout
 display()    ;
  }
    // encoder cutout
    // screw holes
}

// box with pi mounts and holes
module box() {
    // bottom
    // pi mount holes
    // sides
    // pi usb / ethernet
    // hifi audio out
}

//display();
//encoder();
lid();


Holder for brass nut

Holder for brass nut

For threaded-rod based linear motion.

// Brass Nut Mount for DIY Jack - see README.md for details.
// Author: Joseph M. Joy

function range(stop, start=0,  step=1) = [start: step: stop-1];
function range(start, stop, step) = [start: step: stop-1];

//module hexagon(base) = [[0,0], [0, base], [base, 0]];

base_thickness = 3;
base_width = 15;
base_corner_radius = 3; // For Minkowski corners
bolt_hole_dia = 4;
cylinder_dia = 10;
hex_bolt_dia = 5; // from corner to corner
hex_hole_dia = hex_bolt_dia + 1;
hex_bolt_height = 5;
EPSILON = 0.01;

// Create {n} bolt holes in a circle centered on ({x},{y}) and with radius r
// Bolt-hole radius is 2*bolt_hole_dia
module bolt_holes(x, y, r) {
    translate([x, y, -EPSILON ]) {
        for (a = range(45, 360, 90)) {
            rotate([0, 0, a]) translate([r, 0, 0])
                cylinder(base_thickness+2*EPSILON, r=bolt_hole_dia/2);

        }
    }
}

// base
module base() {
    reduced_width = base_width - 2*base_corner_radius;
    bolt_circle_radius = reduced_width/2;
    difference() {
        minkowski() {

                cube([reduced_width, reduced_width, base_thickness]);
                cylinder(EPSILON/2, r=base_corner_radius);
            }
        bolt_holes(reduced_width/2, reduced_width/2, bolt_circle_radius);
        }
}

module nut_mount() {
    base();
    //bolt_holes(0, 0, cylinder_dia, 4);
    //cylinder(base_thickness, r=bolt_hole_dia/2);
}

nut_mount();

error: pathspec 'models/jack/brass-nut-mount.scad' did not match any file(s) known to git


added fill sqare calibration

added fill sqare calibration

first_layer_hight = 0.15;   // first layer hight in mm
size = 40; //side length of the layer in mm

cube([size,size,first_layer_hight], center=true);

error: pathspec 'calibration/z_calibration/fill_square.scad' did not match any file(s) known to git


cleanup

cleanup

use <../che-thild.scad>

xyScale = 0.22;

childHeight = 2;

zTranslate = (childHeight / 2.0)  - 0.01;

union()
{
    translate([0, 0, zTranslate])
    scale([xyScale, xyScale, 1])
    theChild(height = childHeight);

    color("blue")
    cylinder(r=20, h=childHeight, center=true);
}

use <../che-thild.scad>

xyScale = 0.22;

childHeight = 2;

zTranslate = ( (childHeight / 2.0)  - 0.01 );

union()
{
    translate([0, 0, zTranslate])
    scale([xyScale, xyScale, 1])
    theChild(height = childHeight);

    color("blue")
    cylinder(r=20, h=childHeight, center=true);
}


Remove test.scad

Remove test.scad

surface("test.dat", convexity = 5);
translate([0,0,-2])
cube([20,10,2]);


Fix typo in annotation

Fix typo in annotation

/**
 * @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.
 *
 * Lines handling.
 *
 * @package core/line
 * @author jsconan
 */

/**
 * Computes the coordinates of a 2D arc by rotating a vector along the provided angle.
 *
 * @param Number|Vector r - The number or the vector that defines the radius of the arc (can be ellipse).
 * @param Number [a] - The angle to cover.
 * @param Vector [o] - The coordinates of the center of the arc.
 * @param Number [a1] - The start angle of the arc.
 * @param Number [a2] - The end angle of the arc.
 * @returns Vector[]
 */
function arc(r, a=DEGREES, o, a1, a2) =
    let(
        r = vector2D(r),
        o = vector2D(o),
        a1 = deg(a1),
        a2 = a2 != undef ? deg(a2) : a1 + deg(a)
    )
    !r[0] || !r[1] || (!a1 && !a2) ? []
   :let(
        start = min(a1, a2),
        end = max(a1, a2),
        range = end - start,
        step = astep(max(r), absdeg(range)),
        inc = sign(a2 - a1) * step
    )
    complete(
        // intermediate points
        range <= step ? []
       :[ for (a = [a1 + inc : inc : a2]) arcp(r, a) + o ],
        // the start point
        arcp(r, a1) + o,
        // the final point
        arcp(r, a2) + o
    )
;

/**
 * Computes a sinusoid wave.
 * Without angle, the line will be horizontal.
 *
 * @param Number l - The length of the curve.
 * @param Number w - The wave length.
 * @param Number h - The amplitude of the sinusoid.
 * @param Number p - The phase of the sinusoid (the start angle).
 * @param Number o - The offset of the sinusoid.
 * @param Number a - A rotation angle.
 * @returns Vector[]
 */
function sinusoid(l, w, h, p, o, a) =
    let(
        a = deg(a),
        l = float(l),
        w = divisor(w),
        h = divisor(h),
        step = l / (fragments(h) * l / w)
    )
    [
        for (x = [0 : step : l])
            let( p = sinp(x=x, w=w, h=h, p=p, o=o) )
            a ? rotp(p, a) : p
    ]
;

/**
 * Computes a cosinusoid wave.
 * Without angle, the line will be vertical.
 *
 * @param Number l - The length of the curve.
 * @param Number w - The wave length.
 * @param Number h - The amplitude of the cosinusoid.
 * @param Number p - The phase of the cosinusoid (the start angle).
 * @param Number o - The offset of the cosinusoid.
 * @param Number a - A rotation angle.
 * @returns Vector[]
 */
function cosinusoid(l, w, h, p, o, a) =
    let(
        a = deg(a),
        l = float(l),
        w = divisor(w),
        h = divisor(h),
        step = l / (fragments(h) * l / w)
    )
    [
        for (y = [0 : step : l])
            let( p = cosp(y=y, w=w, h=h, p=p, o=o) )
            a ? rotp(p, a) : p
    ]
;

/**
 * Computes a line from a path.
 *
 * A path is composed of commands, each one being a simple array starting by the
 * command name. Each command will produce points relative to the last command
 * or to the last existing point. When the line starts it will rely on the
 * existing points, if any. If no existing points is provided, the line will
 * start from the absolute origin ([0, 0]), unless the first command is a point.
 *
 * The following commands are recognized:
 * - P, Point: ["P", <x>, <y>] | ["P", <point>] - Adds a point at the given absolute coordinates.
 * - L, Line: ["L", <x>, <y>] | ["L", <point>] - Adds a line from the last point to the given relative coordinates.
 * - H, Horizontal line: ["H", <length>] - Adds an horizontal line from the last point with the given length. The sign of the length determines the direction.
 * - V, Vertical line: ["V", <length>] - Adds a vertical line from the last point with the given length. The sign of the length determines the direction.
 * - I, Intersection: ["I", <P1>, <P2>, <P3>] - Adds a line from the last point, that pass through P1 and intersects with the line defined by P2 and P3.
 * - T, Tangent: ["T", <x>, <y>, <radius>] | ["T", <point>, <radius>] - Adds a line from the last point, that ends at the tangent point with the defined circle. The sign of the radius determines the direction
 * - A, Angle: ["A", <angle>, <length>] - Adds a leaned line from the last point with the given angle and the given length. The sign of the length determines the direction.
 * - C, Circle: ["C", <radius>, <start angle>, <end angle>] - Adds a circle arc from the last point with the given radius and with the given angle.
 * - B, Bezier curve: ["B", <P1>, <P2>, <P3>] - Adds a cubic bezier curve from the last point with the given control points (up to 3, the first beeing the last existing point).
 *
 * @param Array p - The path from which build the line
 * @param Vector[] points - The existing points to start the line from.
 * @param Number i - The start index in the path (default: 0)
 * @returns Vector[]
 */
function path(p, points, i) =
    let(
        p = array(p),
        i = integer(i),
        points = array(points),
        length = len(points),
        point = vector2D(points[length - 1]),
        cur = p[i],
        cmd = cur[0],
        l = len(cur)
    )
    i >= len(p) ? points
   :let(
        values = (
            l <= 1 ? [point]
            :cmd == "P" || cmd == "p" ? [isVector(cur[1]) ? vector2D(cur[1]) : apply2D(x=cur[1], y=cur[2])]
            :cmd == "L" || cmd == "l" ? [point, point + (isVector(cur[1]) ? vector2D(cur[1]) : apply2D(x=cur[1], y=cur[2]))]
            :cmd == "H" || cmd == "h" ? [point, point + apply2D(x=cur[1])]
            :cmd == "V" || cmd == "v" ? [point, point + apply2D(y=cur[1])]
            :cmd == "I" || cmd == "i" ? [point, intersect2D(point, cur[1], cur[2], cur[3])]
            :cmd == "T" || cmd == "t" ? let(isv = isVector(cur[1])) [point, tangent2D(point, isv ? cur[1] : apply2D(x=cur[1], y=cur[2]), isv ? cur[2] : cur[3])]
            :cmd == "A" || cmd == "a" ? [point, point + arcPoint(a=cur[1], r=cur[2])]
            :cmd == "C" || cmd == "c" ? arc(r=cur[1], a1=cur[2], a2=cur[3], o=point + arcPoint(a=float(cur[2]) + STRAIGHT, r=cur[1]))
            :cmd == "B" || cmd == "b" ? (
                l >= 4 ? concat([point], cubicBezierCurve(point, point + vector2D(cur[1]), point + vector2D(cur[2]), point + vector2D(cur[3])))
               :l == 3 ? concat([point], quadraticBezierCurve(point, point + vector2D(cur[1]), point + vector2D(cur[2])))
               :[point, point + vector2D(cur[1])]
            )
            :[]
        )
    )
    path(p=p, points=concat(values[0] == point ? slice(points, 0, -1) : points, values), i=i + 1)
;

/**
 * Computes the outline of a polygon. The outline can be at a particular distance.
 *
 * @param Vector[] points - The points defining the polygon to outline.
 * @param Number distance - The distance from the polygon for the outline.
 *                          A positive distance will place the outline outside,
 *                          while a negative distance will place it inside.
 * @returns Vector[]
 */
function outline(points, distance) =
    let(
        points = array(points),
        l = len(points),
        prev = l - 1,
        next = 1
    )
    l >= 3 ? [
        for (i = [0 : 1 : l - 1])
            vertexOutline2D(
                a=points[(i + prev) % l],
                v=points[i],
                b=points[(i + next) % l],
                distance=distance
            )
    ] : points
;

/**
 * Adds a value to each point of a line.
 *
 * @param Vector[] points - The points defining the line.
 * @param Number|Vector value - The value to add to the line.
 * @returns Vector[]
 */
function lineAdd(points, value) =
    let(
        l = max(
            float(len(value)),
            float(len(points[0]))
        ),
        value = vector3D(value)
    )
    l > 2 ? [ for (p = points) vector3D(p) + value ]
          : [ for (p = points) vector2D(p) + value ]
;

/**
 * Builds a vector of faces to be used in a polyhedron. The function accepts the
 * number of points defining one main face of the polyhedron, then returns the
 * faces vector that contains the indices of each face enclosing the solid. This
 * only apply on simple polyhedron where two opposite faces share the same
 * number of points.
 *
 * @param Number length - The number of points for one main face of the polyhedron
 * @returns Vector[]
 */
function simplePolyhedronFaces(length) =
    let(
        length = integer(length)
    )
    length < 3 ? []
   :let(
       r1 = 0,
       r2 = length - 1,
       r3 = length,
       r4 = length * 2 - 1
   )
    concat([
        range(r1, r2),
        range(r3, r4)
    ], [
        for (i = [r1 : r2]) [
            r1 + i,
            (r1 + i + 1) % length,
            r3 + (i + 1) % length,
            r3 + i
        ]
    ])
;

/**
 * Composes a list of points to be used in a simple polyhedron.
 *
 * @param Vector[] [bottom] - The list of points for the bottom face.
 * @param Vector[] [top] - The list of points for the top face.
 * @param Vector[] [points] - The list of points for a main face.
 * @param Vector [distane] - The distance between two main faces.
 * @param Number [x] - The distance between two main faces on the X-axis.
 * @param Number [y] - The distance between two main faces on the Y-axis.
 * @param Number [z] - The distance between two main faces on the Z-axis.
 * @returns Vector[]
 */
function simplePolyhedronPoints(bottom, top, points, distance, x, y, z) =
    let(
       distance = apply3D(v=distance, x=x, y=y, z=z)
    )
    top && bottom ? concat(
        [ for (p = bottom) vector3D(p) ],
        [ for (p = top) vector3D(p) + distance ]
    )
   :let(
       points = [ for (p = (points ? points : (top ? top : bottom))) vector3D(p) ]
   )
   concat(
       points,
       [ for (p = points) p + distance ]
   )
;

/**
 * @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.
 *
 * Lines handling.
 *
 * @package core/line
 * @author jsconan
 */

/**
 * Computes the coordinates of a 2D arc by rotating a vector along the provided angle.
 *
 * @param Number|Vector r - The number or the vector that defines the radius of the arc (can be ellipse).
 * @param Number [a] - The angle to cover.
 * @param Vector [o] - The coordinates of the center of the arc.
 * @param Number [a1] - The start angle of the arc.
 * @param Number [a2] - The end angle of the arc.
 * @returns Vector[]
 */
function arc(r, a=DEGREES, o, a1, a2) =
    let(
        r = vector2D(r),
        o = vector2D(o),
        a1 = deg(a1),
        a2 = a2 != undef ? deg(a2) : a1 + deg(a)
    )
    !r[0] || !r[1] || (!a1 && !a2) ? []
   :let(
        start = min(a1, a2),
        end = max(a1, a2),
        range = end - start,
        step = astep(max(r), absdeg(range)),
        inc = sign(a2 - a1) * step
    )
    complete(
        // intermediate points
        range <= step ? []
       :[ for (a = [a1 + inc : inc : a2]) arcp(r, a) + o ],
        // the start point
        arcp(r, a1) + o,
        // the final point
        arcp(r, a2) + o
    )
;

/**
 * Computes a sinusoid wave.
 * Without angle, the line will be horizontal.
 *
 * @param Number l - The length of the curve.
 * @param Number w - The wave length.
 * @param Number h - The amplitude of the sinusoid.
 * @param Number p - The phase of the sinusoid (the start angle).
 * @param Number o - The offset of the sinusoid.
 * @param Number a - A rotation angle.
 * @returns Vector[]
 */
function sinusoid(l, w, h, p, o, a) =
    let(
        a = deg(a),
        l = float(l),
        w = divisor(w),
        h = divisor(h),
        step = l / (fragments(h) * l / w)
    )
    [
        for (x = [0 : step : l])
            let( p = sinp(x=x, w=w, h=h, p=p, o=o) )
            a ? rotp(p, a) : p
    ]
;

/**
 * Computes a cosinusoid wave.
 * Without angle, the line will be vertical.
 *
 * @param Number l - The length of the curve.
 * @param Number w - The wave length.
 * @param Number h - The amplitude of the cosinusoid.
 * @param Number p - The phase of the cosinusoid (the start angle).
 * @param Number o - The offset of the cosinusoid.
 * @param Number a - A rotation angle.
 * @returns Vector[]
 */
function cosinusoid(l, w, h, p, o, a) =
    let(
        a = deg(a),
        l = float(l),
        w = divisor(w),
        h = divisor(h),
        step = l / (fragments(h) * l / w)
    )
    [
        for (y = [0 : step : l])
            let( p = cosp(y=y, w=w, h=h, p=p, o=o) )
            a ? rotp(p, a) : p
    ]
;

/**
 * Computes a line from a path.
 *
 * A path is composed of commands, each one being a simple array starting by the
 * command name. Each command will produce points relative to the last command
 * or to the last existing point. When the line starts it will rely on the
 * existing points, if any. If no existing points is provided, the line will
 * start from the absolute origin ([0, 0]), unless the first command is a point.
 *
 * The following commands are recognized:
 * - P, Point: ["P", <x>, <y>] | ["P", <point>] - Adds a point at the given absolute coordinates.
 * - L, Line: ["L", <x>, <y>] | ["L", <point>] - Adds a line from the last point to the given relative coordinates.
 * - H, Horizontal line: ["H", <length>] - Adds an horizontal line from the last point with the given length. The sign of the length determines the direction.
 * - V, Vertical line: ["V", <length>] - Adds a vertical line from the last point with the given length. The sign of the length determines the direction.
 * - I, Intersection: ["I", <P1>, <P2>, <P3>] - Adds a line from the last point, that pass through P1 and intersects with the line defined by P2 and P3.
 * - T, Tangent: ["T", <x>, <y>, <radius>] | ["T", <point>, <radius>] - Adds a line from the last point, that ends at the tangent point with the defined circle. The sign of the radius determines the direction
 * - A, Angle: ["A", <angle>, <length>] - Adds a leaned line from the last point with the given angle and the given length. The sign of the length determines the direction.
 * - C, Circle: ["C", <radius>, <start angle>, <end angle>] - Adds a circle arc from the last point with the given radius and with the given angle.
 * - B, Bezier curve: ["B", <P1>, <P2>, <P3>] - Adds a cubic bezier curve from the last point with the given control points (up to 3, the first beeing the last existing point).
 *
 * @param Array p - The path from which build the line
 * @param Vector[] points - The existing points to start the line from.
 * @param Number i - The start index in the path (default: 0)
 * @returns Vector[]
 */
function path(p, points, i) =
    let(
        p = array(p),
        i = integer(i),
        points = array(points),
        length = len(points),
        point = vector2D(points[length - 1]),
        cur = p[i],
        cmd = cur[0],
        l = len(cur)
    )
    i >= len(p) ? points
   :let(
        values = (
            l <= 1 ? [point]
            :cmd == "P" || cmd == "p" ? [isVector(cur[1]) ? vector2D(cur[1]) : apply2D(x=cur[1], y=cur[2])]
            :cmd == "L" || cmd == "l" ? [point, point + (isVector(cur[1]) ? vector2D(cur[1]) : apply2D(x=cur[1], y=cur[2]))]
            :cmd == "H" || cmd == "h" ? [point, point + apply2D(x=cur[1])]
            :cmd == "V" || cmd == "v" ? [point, point + apply2D(y=cur[1])]
            :cmd == "I" || cmd == "i" ? [point, intersect2D(point, cur[1], cur[2], cur[3])]
            :cmd == "T" || cmd == "t" ? let(isv = isVector(cur[1])) [point, tangent2D(point, isv ? cur[1] : apply2D(x=cur[1], y=cur[2]), isv ? cur[2] : cur[3])]
            :cmd == "A" || cmd == "a" ? [point, point + arcPoint(a=cur[1], r=cur[2])]
            :cmd == "C" || cmd == "c" ? arc(r=cur[1], a1=cur[2], a2=cur[3], o=point + arcPoint(a=float(cur[2]) + STRAIGHT, r=cur[1]))
            :cmd == "B" || cmd == "b" ? (
                l >= 4 ? concat([point], cubicBezierCurve(point, point + vector2D(cur[1]), point + vector2D(cur[2]), point + vector2D(cur[3])))
               :l == 3 ? concat([point], quadraticBezierCurve(point, point + vector2D(cur[1]), point + vector2D(cur[2])))
               :[point, point + vector2D(cur[1])]
            )
            :[]
        )
    )
    path(p=p, points=concat(values[0] == point ? slice(points, 0, -1) : points, values), i=i + 1)
;

/**
 * Computes the outline of a polygon. The outline can be at a particular distance.
 *
 * @param Vector[] points - The points defining the polygon to outline.
 * @param Number distance - The distance from the polygon for the outline.
 *                          A positive distance will place the outline outside,
 *                          while a negative distance will place it inside.
 * @returns Vector[]
 */
function outline(points, distance) =
    let(
        points = array(points),
        l = len(points),
        prev = l - 1,
        next = 1
    )
    l >= 3 ? [
        for (i = [0 : 1 : l - 1])
            vertexOutline2D(
                a=points[(i + prev) % l],
                v=points[i],
                b=points[(i + next) % l],
                distance=distance
            )
    ] : points
;

/**
 * Adds a value to each point of a line.
 *
 * @param Vector[] points - The points defining the line.
 * @param Number|Vector value - The value to add to the line.
 * @returns Vector[]
 */
function lineAdd(points, value) =
    let(
        l = max(
            float(len(value)),
            float(len(points[0]))
        ),
        value = vector3D(value)
    )
    l > 2 ? [ for (p = points) vector3D(p) + value ]
          : [ for (p = points) vector2D(p) + value ]
;

/**
 * Builds a vector of faces to be used in a polyhedron. The function accepts the
 * number of points defining one main face of the polyhedron, then returns the
 * faces vector that contains the indices of each face enclosing the solid. This
 * only apply on simple polyhedron where two opposite faces share the same
 * number of points?.
 *
 * @param Number length - The number of points for one main face of the polyhedron
 * @returns Vector[]
 */
function simplePolyhedronFaces(length) =
    let(
        length = integer(length)
    )
    length < 3 ? []
   :let(
       r1 = 0,
       r2 = length - 1,
       r3 = length,
       r4 = length * 2 - 1
   )
    concat([
        range(r1, r2),
        range(r3, r4)
    ], [
        for (i = [r1 : r2]) [
            r1 + i,
            (r1 + i + 1) % length,
            r3 + (i + 1) % length,
            r3 + i
        ]
    ])
;

/**
 * Composes a list of points to be used in a simple polyhedron.
 *
 * @param Vector[] [bottom] - The list of points for the bottom face.
 * @param Vector[] [top] - The list of points for the top face.
 * @param Vector[] [points] - The list of points for a main face.
 * @param Vector [distane] - The distance between two main faces.
 * @param Number [x] - The distance between two main faces on the X-axis.
 * @param Number [y] - The distance between two main faces on the Y-axis.
 * @param Number [z] - The distance between two main faces on the Z-axis.
 * @returns Vector[]
 */
function simplePolyhedronPoints(bottom, top, points, distance, x, y, z) =
    let(
       distance = apply3D(v=distance, x=x, y=y, z=z)
    )
    top && bottom ? concat(
        [ for (p = bottom) vector3D(p) ],
        [ for (p = top) vector3D(p) + distance ]
    )
   :let(
       points = [ for (p = (points ? points : (top ? top : bottom))) vector3D(p) ]
   )
   concat(
       points,
       [ for (p = points) p + distance ]
   )
;


WIP on core element

WIP on core element

use <m3d/screw_head_hex.scad>

eps = 0.01;

// standard ball bearing: 8x22x7mm
module bearing()
{
  difference()
  {
    cylinder(d=22, h=7, $fn=100);
    translate(eps*[0,0,-1])
      cylinder(d=8, h=7+2*eps, $fn=40);
  }
}

module screw_head_slot(dh=0)
{
  screw_head_hex_m8(0.5, 2*0.2+dh);
}

module washer(dh=0)
{
  difference()
  {
    cylinder(d=15.5, h=1.4+dh);
    translate(eps*[0,0,-1])
      cylinder(d=8.5, h=1.4+dh+2*eps);
  }
}

// slot for ball bearing + 2 washers
module bearing_slot()
{
  d_spacing = 0.5;
  h_spacing = 0.2;
  cylinder(d=22+d_spacing, h=7+h_spacing, $fn=150);

  for(dh=[-1.4, 7+h_spacing])
    translate([0,0,dh])
      washer();
}

module side_block()
{
  difference()
  {
    // main element
    cylinder(d1=120, d2=30, h=20, $fn=360);
    // screw slot
    translate([60/2, 0, -eps])
    {
      screw_head_slot(0.5);
      // rod
      cylinder(d=8+0.55, h=100, $fn=50);
      translate([0, 0, 12])
        washer(dh=100);
    }
  }
}

side_block();

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


Fix top board

Fix top board

tol = 0.5;
screen_tol = 0.8;
pcb_x = 130;
pcb_y = 110;
pcb_z = 4;
bolt_d = 3.6;
shift_bolt = 5;
board_w = 1;
board_h = 1;

// box thickness
th = 2;

shift_x = 4;
shift_y = th + 1;

box_x = pcb_x + shift_x + 4;
box_y = pcb_y + shift_y + th;

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

socket_h = 15;
socket_w = 10;
socket_n = 5;
socket_int = 20;
start_socket_x = 20 + shift_x;
eps = 1e-1;

usb_type_b_w = 12;
usb_type_b_h = 11;
start_type_b_y = shift_y + 81.5;
//start_type_b_z = th + pcb_z + tol;

usb_type_a_w = 14.4;
usb_type_a_h = 7.8;
start_type_a_y = shift_y + 46;
//start_type_a_z = th + pcb_z + tol;

// programmator
micro_x = 10;
micro_y = 21.1;
micro_start_x = shift_x + 4.75;
micro_start_y = shift_y + pcb_y - 23.3 - micro_y;

contrast_start_x = shift_x + 38.4;
contrast_start_y = shift_y + 25.7;
volume_start_x = shift_x + pcb_x - 39.2;
volume_start_y = contrast_start_y;
pot_d = 7;
under_pcb = 13;
fn = 10;
gaika_h = 4;
gaika_w = 5.5;
stoiki_r = 4;
wide_stoiki_r = stoiki_r + 2;

translate([0,0,-50]) {

difference() {
  union() {
    difference() {
      union() {
        cube([box_x,box_y, box_z-board_h], false);
        translate([th - board_w, th - board_w, 0]) {
          cube([box_x - 2*(th - board_w), box_y - 2*(th -board_w), box_z], false);
        }
      }
      translate([th, th, th]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, box_z-th+eps], false);
      }
    }
    // under_pcb, stoiki
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
//        translate([dx,dy,pcb_up/2+th-eps]) {
//          cube(size=[under_pcb,under_pcb,pcb_up], center=true);
//        }
        translate([dx,dy,th-eps]) {
          cylinder($fn=6, r=stoiki_r, h=pcb_up);
          cylinder($fn=6, r=wide_stoiki_r, h=gaika_h);
        }
      }
    }
    translate([box_x/2, box_y/2, th-eps]) {
      cylinder($fn=6, r=stoiki_r, h=pcb_up);
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=th+pcb_up+2*eps);
        // gaika
        cylinder($fn=6, r=gaika_w / 2 / cos(30) + 0.05, h=gaika_h);
      }
    }
  }

//    // usb_in1 type b
//    translate([box_x-th-eps, start_type_b_y-tol, start_type_b_z]) {
//        cube(size=[th+2*eps, usb_type_b_w+2*tol, box_z]);
//    }

//    // usb_out1 type a
//    translate([-eps, start_type_a_y - tol, start_type_a_z]) {
//        cube(size=[th+2*eps, usb_type_a_w + 2*tol, box_z]);
//    }

    // programmator
    translate([micro_start_x-tol,micro_start_y-tol, -eps]) {
      cube(size=[micro_x+2*tol, micro_y+2*tol, th+2*eps]);
    }

    // contrast
    translate([contrast_start_x, contrast_start_y, -eps]) {
      cylinder($fn=fn, r=pot_d/2, h=th+2*eps);
    }

    // volume
//    translate([volume_start_x, volume_start_y, -eps]) {
//      cylinder($fn=20, r=pot_d/2, h=th+2*eps);
//    }
}
}

top_box_z = 15 + th;
stoiki_h = top_box_z - th;
wide_stoiki_h = 4;
pcb_room = 1;
screen_start_x = shift_x + 29;
screen_start_y = shift_y + 38.9;
screen_length_x = 71.2;
screen_length_y = 24.2;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 12.5;
screen_hold_y_shift = 2;
screen_hold_up_x = 15;
screen_hold_up_x_shift = 5;

master_button_y = shift_y + 10;
master_button_x = shift_x + 43;
master_button_int = 21.8;
master_button_r = 3;
top_bolt_h = 1.5;
top_bolt_r = 3.5;
speaker_shift = 18;
speaker_r = 15;
speaker_h = 15;
speaker_hole_d = 10;
speaker_hole_int = 3;
speaker_hole_w = 1.5;
speaker_shift = 18;

!difference() {
  union() {
    // board
    translate([0, 0, -board_h]) {
	difference() {
	    cube([box_x, box_y, board_h + eps], false);
	    translate([board_w, board_w, -eps]) {
		cube([box_x - 2*board_w, box_y - 2*board_w, board_h + 3*eps], false);
	    }
	}
    }
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room]) {
          cylinder($fn=6, r=stoiki_r, h=top_box_z-th+eps);
        }
        translate([dx,dy,top_box_z-th-wide_stoiki_h+eps]) {
          cylinder($fn=6, r=wide_stoiki_r, h=wide_stoiki_h+th-2*eps);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y - screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
    translate([screen_start_x + screen_length_x - screen_hold_up_x - screen_hold_up_x_shift, screen_start_y + screen_length_y + screen_hold_y_shift, screen_hold_start_z]) {
	cube([screen_hold_up_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker na stoikah
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // speaker_hole
  for (dy = [shift_y + speaker_shift - speaker_hole_int - speaker_hole_w*3/2,
             shift_y + speaker_shift - speaker_hole_w/2,
             shift_y + speaker_shift + speaker_hole_int + speaker_hole_w/2]) {
    translate([shift_x + pcb_x - speaker_shift - speaker_hole_d, dy, top_box_z-th-eps]) {
      cube(size=[speaker_hole_d, speaker_hole_w, th + 2*eps]);
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=top_box_z+2*eps);
      }
      translate([dx, dy, top_box_z - wide_stoiki_h]) {
        cylinder($fn=6, r=gaika_w / 2 / cos(30) + 0.05, h=wide_stoiki_h+eps);
        //cylinder($fn=6, r=top_bolt_r, h=top_bolt_h + eps);
      }
    }
  }

  // screen
  translate([screen_start_x - screen_tol, screen_start_y - screen_tol, top_box_z - th - eps]) {
      cube([screen_length_x + 2*screen_tol, screen_length_y + 2*screen_tol, th + 2*eps]);
  }
  // sockets
  for (i = [0:1:socket_n-1]) {
      translate([start_socket_x+i*socket_int - tol, box_y-th-eps, -eps - board_h]) {
        cube(size=[socket_w + 2*tol, th+2*eps, socket_h + board_h]);
      }
  }
  // type_b
  translate([box_x - th - eps, start_type_b_y - tol, -tol - board_h]) {
      cube([th + 2*eps, usb_type_b_w + 2*tol, usb_type_b_h + 2*tol + board_h]);
  }
  // type_a
  translate([-eps, start_type_a_y - tol, -eps - board_h]) {
      cube([th + 2*eps, usb_type_a_w + 2*tol, usb_type_a_h + 2*eps + board_h]);
  }
  // master buttons
  for (i = [0:1:2]) {
    translate([master_button_x + master_button_int*i, master_button_y, top_box_z - th - eps]) {
      cylinder($fn=fn, r=master_button_r + tol, h=th+2*eps);
    }
  }
}

//// bolts
//for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
//  for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
//    difference() {
//      translate([dx,dy,pcb_up/2+th]) {
//        cube(size=[a,a,pcb_up], center=true);
//      }
//      translate([dx,dy,-eps]) {
//        cylinder($fn=20, r=bolt_d/2, h=th+pcb_up+2*eps);
//      }
//    }
//  }
//}

//leg_r = t;
//shift = t/2+leg_r;
//for (dx = [shift, a-shift])
//    for (dy = [shift, b-shift]) {
//        translate([dx, dy, 0]) {
//            cylinder(h=c, r=leg_r, $fn=40);
//        }
//    }

tol = 0.5;
screen_tol = 0.8;
pcb_x = 130;
pcb_y = 110;
pcb_z = 4;
bolt_d = 3.6;
shift_bolt = 5;
board_w = 1;
board_h = 1;

// box thickness
th = 2;

shift_x = 4;
shift_y = th + 1;

box_x = pcb_x + shift_x + 4;
box_y = pcb_y + shift_y + th;

pcb_width = 2;
pcb_up = 9;

box_z = th + pcb_up + pcb_width - 1;

socket_h = 15;
socket_w = 10;
socket_n = 5;
socket_int = 20;
start_socket_x = 20 + shift_x;
eps = 1e-1;

usb_type_b_w = 12;
usb_type_b_h = 11;
start_type_b_y = shift_y + 81.5;
//start_type_b_z = th + pcb_z + tol;

usb_type_a_w = 14.4;
usb_type_a_h = 7.8;
start_type_a_y = shift_y + 46;
//start_type_a_z = th + pcb_z + tol;

// programmator
micro_x = 10;
micro_y = 21.1;
micro_start_x = shift_x + 4.75;
micro_start_y = shift_y + pcb_y - 23.3 - micro_y;

contrast_start_x = shift_x + 38.4;
contrast_start_y = shift_y + 25.7;
volume_start_x = shift_x + pcb_x - 39.2;
volume_start_y = contrast_start_y;
pot_d = 7;
under_pcb = 13;
fn = 10;
gaika_h = 4;
gaika_w = 5.5;
stoiki_r = 4;
wide_stoiki_r = stoiki_r + 2;

translate([0,0,-50]) {

difference() {
  union() {
    difference() {
      union() {
        cube([box_x,box_y, box_z-board_h], false);
        translate([th - board_w, th - board_w, 0]) {
          cube([box_x - 2*(th - board_w), box_y - 2*(th -board_w), box_z], false);
        }
      }
      translate([th, th, th]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, box_z-th+eps], false);
      }
    }
    // under_pcb, stoiki
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
//        translate([dx,dy,pcb_up/2+th-eps]) {
//          cube(size=[under_pcb,under_pcb,pcb_up], center=true);
//        }
        translate([dx,dy,th-eps]) {
          cylinder($fn=6, r=stoiki_r, h=pcb_up);
          cylinder($fn=6, r=wide_stoiki_r, h=gaika_h);
        }
      }
    }
    translate([box_x/2, box_y/2, th-eps]) {
      cylinder($fn=6, r=stoiki_r, h=pcb_up);
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=th+pcb_up+2*eps);
        // gaika
        cylinder($fn=6, r=gaika_w / 2 / cos(30) + 0.05, h=gaika_h);
      }
    }
  }

//    // usb_in1 type b
//    translate([box_x-th-eps, start_type_b_y-tol, start_type_b_z]) {
//        cube(size=[th+2*eps, usb_type_b_w+2*tol, box_z]);
//    }

//    // usb_out1 type a
//    translate([-eps, start_type_a_y - tol, start_type_a_z]) {
//        cube(size=[th+2*eps, usb_type_a_w + 2*tol, box_z]);
//    }

    // programmator
    translate([micro_start_x-tol,micro_start_y-tol, -eps]) {
      cube(size=[micro_x+2*tol, micro_y+2*tol, th+2*eps]);
    }

    // contrast
    translate([contrast_start_x, contrast_start_y, -eps]) {
      cylinder($fn=fn, r=pot_d/2, h=th+2*eps);
    }

    // volume
//    translate([volume_start_x, volume_start_y, -eps]) {
//      cylinder($fn=20, r=pot_d/2, h=th+2*eps);
//    }
}
}

top_box_z = 15 + th;
stoiki_h = top_box_z - th;
wide_stoiki_h = 4;
pcb_room = 1;
screen_start_x = shift_x + 29;
screen_start_y = shift_y + 38.9;
screen_length_x = 71.2;
screen_length_y = 24.2;
screen_hold_x = 40;
screen_hold_y = 4;
screen_hold_start_z = 12.5;
screen_hold_y_shift = 2;
screen_hold_up_x = 15;
screen_hold_up_x_shift = 5;

master_button_y = shift_y + 10;
master_button_x = shift_x + 43;
master_button_int = 21.8;
master_button_r = 3;
top_bolt_h = 1.5;
top_bolt_r = 3.5;
speaker_shift = 18;
speaker_r = 15;
speaker_h = 15;
speaker_hole_d = 10;
speaker_hole_int = 3;
speaker_hole_w = 1.5;
speaker_shift = 18;

difference() {
  union() {
    // board
    translate([0, 0, -board_h + eps]) {
	difference() {
	    cube([box_x, box_y, board_h], false);
	    translate([board_w, board_w, -eps]) {
		cube([box_x - 2*board_w, box_y - 2*board_w, board_h + 2*eps], false);
	    }
	}
    }
    difference() {
      cube([box_x,box_y,top_box_z], false);
      translate([th, th, -eps]) {
        cube([box_x-2*th+eps, box_y-2*th+eps, top_box_z-th+eps], false);
      }
    }
    // stoiki
    for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
      for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
        translate([dx,dy,pcb_room]) {
          cylinder($fn=6, r=stoiki_r, h=top_box_z-th+eps);
        }
        translate([dx,dy,top_box_z-th-wide_stoiki_h+eps]) {
          cylinder($fn=6, r=wide_stoiki_r, h=wide_stoiki_h+th-2*eps);
        }
      }
    }
    // screen_hold
    translate([screen_start_x + (screen_length_x - screen_hold_x)/2, screen_start_y - screen_hold_y_shift - screen_hold_y, screen_hold_start_z]) {
	cube([screen_hold_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
    translate([screen_start_x + screen_length_x - screen_hold_up_x - screen_hold_up_x_shift, screen_start_y + screen_length_y + screen_hold_y_shift, screen_hold_start_z]) {
	cube([screen_hold_up_x, screen_hold_y, top_box_z - screen_hold_start_z - th + eps]);
    }
  }
  // - speaker na stoikah
  translate([shift_x + pcb_x - 18, shift_y + 18, 0]) {
    cylinder(r=speaker_r, h = 15, $fn=20);
  }
  // speaker_hole
  for (dy = [shift_y + speaker_shift - speaker_hole_int - speaker_hole_w*3/2,
             shift_y + speaker_shift - speaker_hole_w/2,
             shift_y + speaker_shift + speaker_hole_int + speaker_hole_w/2]) {
    translate([shift_x + pcb_x - speaker_shift - speaker_hole_d, dy, top_box_z-th-eps]) {
      cube(size=[speaker_hole_d, speaker_hole_w, th + 2*eps]);
    }
  }

  // bolts
  for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
    for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
      translate([dx,dy,-eps]) {
        cylinder($fn=fn, r=bolt_d/2, h=top_box_z+2*eps);
      }
      translate([dx, dy, top_box_z - wide_stoiki_h]) {
        cylinder($fn=6, r=gaika_w / 2 / cos(30) + 0.05, h=wide_stoiki_h+eps);
        //cylinder($fn=6, r=top_bolt_r, h=top_bolt_h + eps);
      }
    }
  }

  // screen
  translate([screen_start_x - screen_tol, screen_start_y - screen_tol, top_box_z - th - eps]) {
      cube([screen_length_x + 2*screen_tol, screen_length_y + 2*screen_tol, th + 2*eps]);
  }
  // sockets
  for (i = [0:1:socket_n-1]) {
      translate([start_socket_x+i*socket_int - tol, box_y-th-eps, -eps - board_h]) {
        cube(size=[socket_w + 2*tol, th+2*eps, socket_h + board_h]);
      }
  }
  // type_b
  translate([box_x - th - eps, start_type_b_y - tol, -tol - board_h]) {
      cube([th + 2*eps, usb_type_b_w + 2*tol, usb_type_b_h + 2*tol + board_h]);
  }
  // type_a
  translate([-eps, start_type_a_y - tol, -eps - board_h]) {
      cube([th + 2*eps, usb_type_a_w + 2*tol, usb_type_a_h + 2*eps + board_h]);
  }
  // master buttons
  for (i = [0:1:2]) {
    translate([master_button_x + master_button_int*i, master_button_y, top_box_z - th - eps]) {
      cylinder($fn=fn, r=master_button_r + tol, h=th+2*eps);
    }
  }
}

//// bolts
//for (dx = [shift_x+shift_bolt, shift_x+pcb_x-shift_bolt]) {
//  for (dy = [shift_y+shift_bolt, shift_y+pcb_y-shift_bolt]) {
//    difference() {
//      translate([dx,dy,pcb_up/2+th]) {
//        cube(size=[a,a,pcb_up], center=true);
//      }
//      translate([dx,dy,-eps]) {
//        cylinder($fn=20, r=bolt_d/2, h=th+pcb_up+2*eps);
//      }
//    }
//  }
//}

//leg_r = t;
//shift = t/2+leg_r;
//for (dx = [shift, a-shift])
//    for (dy = [shift, b-shift]) {
//        translate([dx, dy, 0]) {
//            cylinder(h=c, r=leg_r, $fn=40);
//        }
//    }