diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..979f64bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*~ +*.pyc +.pytest_cache/ +__pycache__/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 64771f3d..00000000 --- a/.gitmodules +++ /dev/null @@ -1,6 +0,0 @@ -[submodule "SolidPython"] - path = SolidPython - url = git://github.com/SolidCode/SolidPython.git -[submodule "ThingDoc"] - path = ThingDoc - url = git://github.com/SolidCode/ThingDoc.git diff --git a/2Dshapes.scad b/2Dshapes.scad index 2d105779..1b21050c 100644 --- a/2Dshapes.scad +++ b/2Dshapes.scad @@ -3,137 +3,168 @@ * Copyright (C) 2012 Peter Uithoven * * License: LGPL 2.1 or later + + * 2D Shapes + * ngon(sides, radius, center=false); + * complexRoundSquare(size,rads1=[0,0], rads2=[0,0], rads3=[0,0], rads4=[0,0], center=true) + * roundedSquare(pos=[10,10],r=2) + * ellipsePart(width,height,numQuarters) + * donutSlice(innerSize,outerSize, start_angle, end_angle) + * pieSlice(size, start_angle, end_angle) //size in radius(es) + * ellipse(width, height) { */ -// 2D Shapes -//ngon(sides, radius, center=false); -//complexRoundSquare(size,rads1=[0,0], rads2=[0,0], rads3=[0,0], rads4=[0,0], center=true) -//roundedSquare(pos=[10,10],r=2) -//ellipsePart(width,height,numQuarters) -//donutSlice(innerSize,outerSize, start_angle, end_angle) -//pieSlice(size, start_angle, end_angle) //size in radius(es) -//ellipse(width, height) { - -// Examples -/*use ; -grid(105,105,true,4) -{ - // ellipse - ellipse(50,75); - - // part of ellipse (a number of quarters) - ellipsePart(50,75,3); - ellipsePart(50,75,2); - ellipsePart(50,75,1); - - // complexRoundSquare examples - complexRoundSquare([75,100],[20,10],[20,10],[20,10],[20,10]); - complexRoundSquare([75,100],[0,0],[0,0],[30,50],[20,10]); - complexRoundSquare([50,50],[10,20],[10,20],[10,20],[10,20],false); - complexRoundSquare([100,100]); - complexRoundSquare([100,100],rads1=[20,20],rads3=[20,20]); - - // pie slice - pieSlice(50,0,10); - pieSlice(50,45,190); - pieSlice([50,20],180,270); - - // donut slice - donutSlice(20,50,0,350); - donutSlice(30,50,190,270); - donutSlice([40,22],[50,30],180,270); - donutSlice([50,20],50,180,270); - donutSlice([20,30],[50,40],0,270); -}*/ -//---------------------- - -// size, top left radius, top right radius, bottom right radius, bottom left radius, center -module complexRoundSquare(size,rads1=[0,0], rads2=[0,0], rads3=[0,0], rads4=[0,0], center=true) -{ - width = size[0]; - height = size[1]; - //%square(size=[width, height],center=true); - x1 = 0-width/2+rads1[0]; - y1 = 0-height/2+rads1[1]; - x2 = width/2-rads2[0]; - y2 = 0-height/2+rads2[1]; - x3 = width/2-rads3[0]; - y3 = height/2-rads3[1]; - x4 = 0-width/2+rads4[0]; - y4 = height/2-rads4[1]; - - scs = 0.1; //straight corner size - - x = (center)? 0: width/2; - y = (center)? 0: height/2; - - translate([x,y,0]) - { - hull() { - // top left - if(rads1[0] > 0 && rads1[1] > 0) - translate([x1,y1]) mirror([1,0]) ellipsePart(rads1[0]*2,rads1[1]*2,1); - else - translate([x1,y1]) square(size=[scs, scs]); - - // top right - if(rads2[0] > 0 && rads2[1] > 0) - translate([x2,y2]) ellipsePart(rads2[0]*2,rads2[1]*2,1); - else - translate([width/2-scs,0-height/2]) square(size=[scs, scs]); - - // bottom right - if(rads3[0] > 0 && rads3[1] > 0) - translate([x3,y3]) mirror([0,1]) ellipsePart(rads3[0]*2,rads3[1]*2,1); - else - translate([width/2-scs,height/2-scs]) square(size=[scs, scs]); - - // bottom left - if(rads4[0] > 0 && rads4[1] > 0) - translate([x4,y4]) rotate([0,0,-180]) ellipsePart(rads4[0]*2,rads4[1]*2,1); - else - #translate([x4,height/2-scs]) square(size=[scs, scs]); - } - } +// Examples - (layouts.scad is required for examples) +// example2DShapes(); use ; + +module example2DShapes() { + grid(105,105,true,4) + { + // ellipse + ellipse(50,75); + + // part of ellipse (a number of quarters) + ellipsePart(50,75,3); + ellipsePart(50,75,2); + ellipsePart(50,75,1); + + // complexRoundSquare examples + complexRoundSquare([75,100],[20,10],[20,10],[20,10],[20,10]); + complexRoundSquare([75,100],[0,0],[0,0],[30,50],[20,10]); + complexRoundSquare([50,50],[10,20],[10,20],[10,20],[10,20],false); + complexRoundSquare([100,100]); + complexRoundSquare([100,100],rads1=[20,20],rads3=[20,20]); + + // pie slice + pieSlice(50,0,10); + pieSlice(50,45,190); + pieSlice([50,20],180,270); + + // donut slice + donutSlice(20,50,0,350); + donutSlice(30,50,190,270); + donutSlice([40,22],[50,30],180,270); + donutSlice([50,20],50,180,270); + donutSlice([20,30],[50,40],0,270); + } +} +// end examples ---------------------- + +module complexRoundSquare( + size, // Size + rads1=[0,0], // Top left radius + rads2=[0,0], // Top right radius + rads3=[0,0], // Bottom right radius + rads4=[0,0], // Bottom left radius + center=true // center +) { + width = size[0]; + height = size[1]; + // %square(size=[width, height],center=true); + x1 = 0-width/2+rads1[0]; + y1 = 0-height/2+rads1[1]; + x2 = width/2-rads2[0]; + y2 = 0-height/2+rads2[1]; + x3 = width/2-rads3[0]; + y3 = height/2-rads3[1]; + x4 = 0-width/2+rads4[0]; + y4 = height/2-rads4[1]; + + scs = 0.1; // straight corner size + + x = (center)? 0: width/2; + y = (center)? 0: height/2; + + translate([x,y,0]) + hull() + { + // top left + if(rads1[0] > 0 && rads1[1] > 0) + translate([x1,y1]) + mirror([1,0]) + ellipsePart(rads1[0]*2,rads1[1]*2,1); + else + translate([x1,y1]) + square(size=[scs, scs]); + + // top right + if(rads2[0] > 0 && rads2[1] > 0) + translate([x2,y2]) + ellipsePart(rads2[0]*2,rads2[1]*2,1); + else + translate([width/2-scs,0-height/2]) + square(size=[scs, scs]); + + // bottom right + if(rads3[0] > 0 && rads3[1] > 0) + translate([x3,y3]) + mirror([0,1]) + ellipsePart(rads3[0]*2,rads3[1]*2,1); + else + translate([width/2-scs,height/2-scs]) + square(size=[scs, scs]); + + // bottom left + if(rads4[0] > 0 && rads4[1] > 0) + translate([x4,y4]) + rotate([0,0,-180]) + ellipsePart(rads4[0]*2,rads4[1]*2,1); + else + #translate([x4,height/2-scs]) + square(size=[scs, scs]); + } } + module roundedSquare(pos=[10,10],r=2) { - minkowski() { - square([pos[0]-r*2,pos[1]-r*2],center=true); - circle(r=r); - } + minkowski() + { + square([pos[0]-r*2,pos[1]-r*2],center=true); + + + circle(r=r); + } } + // round shapes // The orientation might change with the implementation of circle... -module ngon(sides, radius, center=false){ - rotate([0, 0, 360/sides/2]) circle(r=radius, $fn=sides, center=center); +module ngon(sides, radius, center=false) { + rotate([0, 0, 360/sides/2]) + circle(r=radius, $fn=sides, center=center); } -module ellipsePart(width,height,numQuarters) -{ + +module ellipsePart(width,height,numQuarters) { o = 1; //slight overlap to fix a bug - difference() - { - ellipse(width,height); - if(numQuarters <= 3) - translate([0-width/2-o,0-height/2-o,0]) square([width/2+o,height/2+o]); - if(numQuarters <= 2) - translate([0-width/2-o,-o,0]) square([width/2+o,height/2+o*2]); - if(numQuarters < 2) - translate([-o,0,0]) square([width/2+o*2,height/2+o]); - } + difference() + { + ellipse(width,height); + + if(numQuarters <= 3) + translate([0-width/2-o,0-height/2-o,0]) + square([width/2+o,height/2+o]); + if(numQuarters <= 2) + translate([0-width/2-o,-o,0]) + square([width/2+o,height/2+o*2]); + if(numQuarters < 2) + translate([-o,0,0]) + square([width/2+o*2,height/2+o]); + } } -module donutSlice(innerSize,outerSize, start_angle, end_angle) -{ + +module donutSlice(innerSize,outerSize, start_angle, end_angle) { difference() { pieSlice(outerSize, start_angle, end_angle); - if(len(innerSize) > 1) ellipse(innerSize[0]*2,innerSize[1]*2); - else circle(innerSize); + + if(is_list(innerSize) && len(innerSize) > 1) + ellipse(innerSize[0]*2,innerSize[1]*2); + else + circle(innerSize); } } -module pieSlice(size, start_angle, end_angle) //size in radius(es) -{ - rx = ((len(size) > 1)? size[0] : size); - ry = ((len(size) > 1)? size[1] : size); + +module pieSlice(size, start_angle, end_angle) { //size in radius(es) + rx = (is_list(size) && len(size) > 1)? size[0] : size; + ry = (is_list(size) && len(size) > 1)? size[1] : size; trx = rx* sqrt(2) + 1; try = ry* sqrt(2) + 1; a0 = (4 * start_angle + 0 * end_angle) / 4; @@ -141,12 +172,13 @@ module pieSlice(size, start_angle, end_angle) //size in radius(es) 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() { - if(len(size) > 1) - ellipse(rx*2,ry*2); - else - circle(rx); + if(is_list(size) && len(size) > 1) + ellipse(rx*2,ry*2); + else + circle(rx); polygon([ [0,0], [trx * cos(a0), try * sin(a0)], @@ -155,9 +187,11 @@ module pieSlice(size, start_angle, end_angle) //size in radius(es) [trx * cos(a3), try * sin(a3)], [trx * cos(a4), try * sin(a4)], [0,0] - ]); + ]); } } + module ellipse(width, height) { - scale([1, height/width, 1]) circle(r=width/2); -} \ No newline at end of file + scale([1, height/width, 1]) + circle(r=width/2); +} diff --git a/3d_triangle.scad b/3d_triangle.scad index f313433a..f3514985 100644 --- a/3d_triangle.scad +++ b/3d_triangle.scad @@ -205,7 +205,7 @@ function 3dtri_centerOfIn_circle (Acord,Bcord,Ccord,r) = // Acord : [x,y,z] Coordinates of vertex A // Bcord : [x,y,z] Coordinates of vertex B // Ccord : [x,y,z] Coordinates of vertex C -// h : real Hight of the triangle +// h : real Height of the triangle // RETURNS: // none // @@ -238,7 +238,7 @@ polyhedron (points=[Acord,Bcord,Ccord, // Acord : [x,y,z] Coordinates of vertex A // Bcord : [x,y,z] Coordinates of vertex B // Ccord : [x,y,z] Coordinates of vertex C -// h : real Hight of the triangle +// h : real Height of the triangle // r : real Radius from vertices coordinates // RETURNS: // none diff --git a/README.markdown b/README.markdown index 97dde74f..3175ead4 100644 --- a/README.markdown +++ b/README.markdown @@ -1,12 +1,15 @@ -OpenSCAD MCAD Library [![](http://stillmaintained.com/elmom/MCAD.png)](http://stillmaintained.com/elmom/MCAD) +OpenSCAD MCAD Library ===================== -This library contains components commonly used in designing and moching up +This library contains components commonly used in designing and mocking up mechanical designs. It is currently unfinished and you can expect some API changes, however many things are already working. -This library is licensed under the LGPL 2.1 -See http://creativecommons.org/licenses/LGPL/2.1/ or the included file, lgpl-2.1.txt. +This library was created by various authors as named in the individual +files' comments. All the files are licensed under the LGPL 2.1 (see +http://creativecommons.org/licenses/LGPL/2.1/ or the included file +lgpl-2.1.txt), some of them allow distribution under more permissive +terms (as described in the files' comments). ## Usage ## @@ -24,7 +27,6 @@ If you host your project in git, you can do `git submodule add URL PATH` in your repo to import this library as a git submodule for easy usage. Then you need to do a `git submodule update --init` after cloning. When you want to update the submodule, do `cd PATH; git checkout master; git pull`. See `git help submodule` for more info. -"./get_submodules.py" is shortcut that initializes and updates submodules. Currently Provided Tools: @@ -43,7 +45,7 @@ Currently Provided Tools: * motors.scad: - stepper_motor_mount(nema_standard, slide_distance OPTIONAL, mochup OPTIONAL) -Other tools (alpha and beta quality): +Tools (alpha and beta quality): * nuts_and_bolts.scad: for creating metric and imperial bolt/nut holes * bearing.scad: standard/custom bearings @@ -66,11 +68,30 @@ Very generally useful functions and constants: * shapes.scad: DEPRECATED simple shapes by Catarina Mota * polyholes.scad: holes that should come out well when printed -External utils that generate and and process openscad code: +Other: + +* alphabet_block.scad +* bitmap.scad +* letter_necklace.scad +* name_tag.scad +* height_map.scad +* trochoids.scad +* libtriangles.scad +* layouts.scad +* transformations.scad +* 2Dshapes.scad +* gridbeam.scad +* fonts.scad +* unregular_shapes.scad +* metric_fastners.scad +* lego_compatibility.scad +* multiply.scad +* hardware.scad + +External utils that generate and process openscad code: * openscad_testing.py: testing code, see below * openscad_utils.py: code for scraping function names etc. -* SolidPython: An external Python library for solid cad ## Development ## diff --git a/SolidPython b/SolidPython deleted file mode 160000 index ecf1c088..00000000 --- a/SolidPython +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ecf1c0888ad323e2be5b2ec1578773be46b72435 diff --git a/ThingDoc b/ThingDoc deleted file mode 160000 index 54c83e5a..00000000 --- a/ThingDoc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 54c83e5a41131156cad0ce7e3271433b1035aab1 diff --git a/array.scad b/array.scad new file mode 100644 index 00000000..3ab8a3e3 --- /dev/null +++ b/array.scad @@ -0,0 +1,114 @@ +// array functions +// by david powell +// licence LGPL V2 or later +// +// this lib provides 2 functions +// Cubic_Array() , and Radial_Array() +// +//Cubic_Array(sx,sy,sz,nx,ny,nz,center){childobject} +// produces a cubic grid of child objects +// sx,sy,sz = spacing for each axis +// nx,ny,nz and number of objects on each axis +// center = true/false on if geometery is centered or not +// +// +//Radial_Array(a,n,r){child object} +// produces a clockwise radial array of child objects rotated around the local z axis +// a= interval angle +// n= number of objects +// r= radius distance +// +// remove // from following line to run test +//Cubic_and_Radial_Array_Test(); + +module Cubic_and_Radial_Array_Test() + { +//center referance point + translate([0,0,0]) + #cube([5,5,5],center=true); + +//cubic array of 5*5*5 objects spaced 10*10*10 center relative + Cubic_Array(10,10,10,5,5,5,center=true) + { + sphere(2.5,$fn=60); + cylinder(h=10,r=.5,center=true); + rotate([90,0,0]) + cylinder(h=10,r=.5,center=true); + rotate([0,90,0]) + cylinder(h=10,r=.5,center=true); + } + +//a linear array allong x can be derived from the cubic array simply + translate([60,0,0]) + Cubic_Array(10,0,0,5,1,1,center=false) + { + cube([5,5,5],center=true); + } +//a linear array allong y can be derived from the cubic array simply + translate([0,60,0]) + Cubic_Array(0,10,0,1,5,1,center=false) + { + cube([5,5,5],center=true); + } + +//a linear array allong z can be derived from the cubic array simply + translate([0,0,60]) + Cubic_Array(0,0,10,1,1,5,center=false) + { + cube([5,5,5],center=true); + } + +//a grid array allong x,y can be derived from the cubic array simply + translate([0,0,-60]) + Cubic_Array(10,10,0,5,5,1,center=true) + { + cube([5,5,5],center=true); + } + +//radial array of 32 objects rotated though 10 degrees + translate([0,0,0]) + Radial_Array(10,32,40) + { + cube([2,4,6],center=true); + } + +// a radial array of linear arrays + + rotate([45,45,45]) + Radial_Array(10,36,40) + { + translate([0,10,0]) + Cubic_Array(0,10,0,1,5,1,center=false) + { + cube([2,3,4],center=true); + cylinder(h=10,r=.5,center=true); + rotate([90,0,0]) + cylinder(h=10,r=.5,center=true); + } + } + +} + + +// main lib modules +module Cubic_Array(sx,sy,sz,nx,ny,nz,center) { + offset = center ? [-(((nx+1)*sx)/2),-(((ny+1)*sy)/2),-(((nz+1)*sz)/2)] : [0,0,0]; + translate(offset) + for(x=[1:nx], y=[1:ny], z=[1:nz]) + translate([x*sx,y*sy,z*sz]) + children(); +} + +// +//Radial_Array(a,n,r){child object} +// produces a clockwise radial array of child objects rotated around the local z axis +// a= interval angle +// n= number of objects +// r= radius distance +// +module Radial_Array(a,n,r){ + for (k=[0:n-1]) + rotate([0,0,-(a*k)]) + translate([0,r,0]) + children(); +} diff --git a/bearing.scad b/bearing.scad index 2efea7ec..5db8c717 100644 --- a/bearing.scad +++ b/bearing.scad @@ -5,6 +5,11 @@ * Dual licenced under Creative Commons Attribution-Share Alike 3.0 and LGPL2 or later */ +/* +change list 13/6/2013 + added ,604,606,607,628,629,6200,6201,6202,6203,6205,6206 bearing sizes +*/ + include include @@ -20,8 +25,8 @@ module test_bearing(){ module test_bearing_hole(){ difference(){ - translate([0, 0, 3.5]) cube(size=[30, 30, 7-10*epsilon], center=true); - bearing(outline=true); + cube(size=[30, 30, 7-10*epsilon], center=true); + bearing(outline=true, center=true); } } @@ -34,13 +39,136 @@ SkateBearing = 608; // Bearing dimensions // model == XXX ? [inner dia, outer dia, width]: +// http://www.gizmology.net/bearings.htm has some valuable information on that +// https://www.bearingworks.com/bearing-sizes has a very exhaustive table of dimensions function bearingDimensions(model) = - model == 608 ? [8*mm, 22*mm, 7*mm]: - model == 623 ? [3*mm, 10*mm, 4*mm]: - model == 624 ? [4*mm, 13*mm, 5*mm]: - model == 627 ? [7*mm, 22*mm, 7*mm]: - model == 688 ? [8*mm, 16*mm, 4*mm]: - model == 698 ? [8*mm, 19*mm, 6*mm]: + model == 603 ? [3*mm, 9*mm, 5*mm]: + model == 604 ? [4*mm, 12*mm, 4*mm]: + model == 605 ? [5*mm, 14*mm, 5*mm]: + model == 606 ? [6*mm, 17*mm, 6*mm]: + model == 607 ? [7*mm, 19*mm, 6*mm]: + model == 608 ? [8*mm, 22*mm, 7*mm]: + model == 609 ? [9*mm, 24*mm, 7*mm]: + + model == 623 ? [3*mm, 10*mm, 4*mm]: + model == 624 ? [4*mm, 13*mm, 5*mm]: + model == 625 ? [5*mm, 16*mm, 5*mm]: + model == 626 ? [6*mm, 19*mm, 6*mm]: + model == 627 ? [7*mm, 22*mm, 7*mm]: + model == 628 ? [8*mm, 24*mm, 8*mm]: + model == 629 ? [9*mm, 26*mm, 8*mm]: + + model == 633 ? [3*mm, 13*mm, 5*mm]: + model == 634 ? [4*mm, 16*mm, 5*mm]: + model == 635 ? [5*mm, 19*mm, 6*mm]: + model == 636 ? [6*mm, 22*mm, 7*mm]: + model == 637 ? [7*mm, 26*mm, 9*mm]: + model == 638 ? [8*mm, 28*mm, 9*mm]: + model == 639 ? [9*mm, 30*mm, 10*mm]: + + model == 673 ? [3*mm, 6*mm, 2.5*mm]: + model == 674 ? [4*mm, 7*mm, 2.5*mm]: + model == 675 ? [5*mm, 8*mm, 2.5*mm]: + model == 676 ? [6*mm, 10*mm, 3*mm]: + model == 677 ? [7*mm, 11*mm, 3*mm]: + model == 678 ? [8*mm, 12*mm, 3.5*mm]: + + model == 683 ? [3*mm, 7*mm, 3*mm]: + model == 684 ? [4*mm, 9*mm, 4*mm]: + model == 685 ? [5*mm, 11*mm, 5*mm]: + model == 686 ? [6*mm, 13*mm, 5*mm]: + model == 687 ? [7*mm, 14*mm, 5*mm]: + model == 688 ? [8*mm, 16*mm, 5*mm]: + model == 689 ? [9*mm, 17*mm, 5*mm]: + + model == 692 ? [2*mm, 6*mm, 3*mm]: + model == 693 ? [3*mm, 8*mm, 4*mm]: + model == 694 ? [4*mm, 11*mm, 4*mm]: + model == 695 ? [5*mm, 13*mm, 4*mm]: + model == 696 ? [6*mm, 15*mm, 5*mm]: + model == 697 ? [7*mm, 17*mm, 5*mm]: + model == 698 ? [8*mm, 19*mm, 6*mm]: + model == 699 ? [9*mm, 20*mm, 6*mm]: + + model == 6000 ? [10*mm, 26*mm, 8*mm]: + model == 6001 ? [12*mm, 28*mm, 8*mm]: + model == 6002 ? [15*mm, 32*mm, 9*mm]: + model == 6003 ? [17*mm, 35*mm, 10*mm]: + model == 6004 ? [20*mm, 42*mm, 12*mm]: + model == 6005 ? [25*mm, 47*mm, 12*mm]: + model == 6006 ? [30*mm, 55*mm, 13*mm]: + model == 6007 ? [35*mm, 62*mm, 14*mm]: + model == 6008 ? [40*mm, 68*mm, 15*mm]: + model == 6009 ? [45*mm, 75*mm, 16*mm]: + model == 6010 ? [50*mm, 80*mm, 16*mm]: + model == 6011 ? [55*mm, 90*mm, 18*mm]: + model == 6012 ? [60*mm, 95*mm, 18*mm]: + model == 6013 ? [65*mm, 100*mm, 18*mm]: + model == 6014 ? [70*mm, 110*mm, 20*mm]: + model == 6015 ? [75*mm, 115*mm, 20*mm]: + + model == 6200 ? [10*mm, 30*mm, 9*mm]: + model == 6201 ? [12*mm, 32*mm, 10*mm]: + model == 6202 ? [15*mm, 35*mm, 11*mm]: + model == 6203 ? [17*mm, 40*mm, 12*mm]: + model == 6204 ? [20*mm, 47*mm, 14*mm]: + model == 6205 ? [25*mm, 52*mm, 15*mm]: + model == 6206 ? [30*mm, 62*mm, 16*mm]: + model == 6207 ? [35*mm, 72*mm, 17*mm]: + model == 6208 ? [40*mm, 80*mm, 18*mm]: + model == 6209 ? [45*mm, 85*mm, 19*mm]: + + model == 6300 ? [10*mm, 35*mm, 11*mm]: + model == 6301 ? [12*mm, 37*mm, 12*mm]: + model == 6302 ? [15*mm, 42*mm, 13*mm]: + model == 6303 ? [17*mm, 47*mm, 14*mm]: + model == 6304 ? [20*mm, 52*mm, 15*mm]: + model == 6305 ? [25*mm, 62*mm, 17*mm]: + model == 6306 ? [30*mm, 72*mm, 19*mm]: + model == 6307 ? [35*mm, 80*mm, 21*mm]: + model == 6308 ? [40*mm, 90*mm, 23*mm]: + model == 6309 ? [45*mm, 100*mm, 25*mm]: + model == 6310 ? [50*mm, 110*mm, 27*mm]: + model == 6311 ? [55*mm, 120*mm, 29*mm]: + model == 6312 ? [60*mm, 130*mm, 31*mm]: + model == 6313 ? [65*mm, 140*mm, 33*mm]: + model == 6314 ? [70*mm, 150*mm, 35*mm]: + model == 6315 ? [75*mm, 160*mm, 37*mm]: + + model == 6700 ? [10*mm, 15*mm, 4*mm]: + model == 6701 ? [12*mm, 18*mm, 4*mm]: + + model == 6808 ? [40*mm, 52*mm, 7*mm]: + + model == 6900 ? [10*mm, 22*mm, 6*mm]: + model == 6901 ? [12*mm, 24*mm, 6*mm]: + model == 6902 ? [15*mm, 28*mm, 7*mm]: + model == 6903 ? [17*mm, 30*mm, 7*mm]: + model == 6904 ? [20*mm, 37*mm, 9*mm]: + model == 6905 ? [25*mm, 42*mm, 9*mm]: + + model == "LM12" ? [12*mm, 21*mm, 30*mm]: + + model == "MR52" ? [2*mm, 5*mm, 2.5*mm]: + model == "MR62" ? [2*mm, 6*mm, 2.5*mm]: + model == "MR63" ? [3*mm, 6*mm, 2.5*mm]: + model == "MR72" ? [2*mm, 7*mm, 3*mm]: + model == "MR74" ? [4*mm, 7*mm, 2.5*mm]: + model == "MR83" ? [3*mm, 8*mm, 3*mm]: + model == "MR84" ? [4*mm, 8*mm, 3*mm]: + model == "MR85" ? [5*mm, 8*mm, 2.5*mm]: + model == "MR93" ? [3*mm, 9*mm, 4*mm]: + model == "MR95" ? [5*mm, 9*mm, 3*mm]: + model == "MR104" ? [4*mm, 10*mm, 4*mm]: + model == "MR105" ? [5*mm, 10*mm, 4*mm]: + model == "MR106" ? [6*mm, 10*mm, 3*mm]: + model == "MR115" ? [5*mm, 11*mm, 4*mm]: + model == "MR117" ? [7*mm, 11*mm, 3*mm]: + model == "MR126" ? [6*mm, 12*mm, 4*mm]: + model == "MR128" ? [8*mm, 12*mm, 3.5*mm]: + model == "MR137" ? [7*mm, 13*mm, 4*mm]: + model == "MR148" ? [8*mm, 14*mm, 4*mm]: + model == "MR149" ? [9*mm, 14*mm, 4.5*mm]: [8*mm, 22*mm, 7*mm]; // this is the default @@ -49,7 +177,7 @@ function bearingInnerDiameter(model) = bearingDimensions(model)[BEARING_INNER_DI function bearingOuterDiameter(model) = bearingDimensions(model)[BEARING_OUTER_DIAMETER]; module bearing(pos=[0,0,0], angle=[0,0,0], model=SkateBearing, outline=false, - material=Steel, sideMaterial=Brass) { + material=Steel, sideMaterial=Brass, center=false) { // Common bearing names model = model == "Skate" ? 608 : @@ -62,8 +190,9 @@ module bearing(pos=[0,0,0], angle=[0,0,0], model=SkateBearing, outline=false, innerRim = innerD + (outerD - innerD) * 0.2; outerRim = outerD - (outerD - innerD) * 0.2; midSink = w * 0.1; + newpos = [pos[0], pos[1], center ? pos[2]-(w/2) : pos[2]]; - translate(pos) rotate(angle) union() { + translate(newpos) rotate(angle) union() { color(material) difference() { // Basic ring diff --git a/bitmap/name_tag.scad b/bitmap/name_tag.scad index 7687c546..4b392bb3 100644 --- a/bitmap/name_tag.scad +++ b/bitmap/name_tag.scad @@ -7,33 +7,30 @@ http://creativecommons.org/licenses/by/3.0/ use -// change chars array and char_count -// OpenSCAD has no string or length methods :( -chars = ["R", "E", "P", "R", "A", "P"]; -char_count = 6; - - -// block size 1 will result in 8mm per letter -block_size = 2; -// height is the Z height of each letter -height = 3; -// Append a hole fo a keyring, necklace etc. ? -key_ring_hole = true; - -union() { - translate(v = [0,-block_size*8*char_count/2+block_size*8/2,3]) { - 8bit_str(chars, char_count, block_size, height); - } - translate(v = [0,0,3/2]) { - color([0,0,1,1]) { - cube(size = [block_size * 8, block_size * 8 * char_count, 3], center = true); - } - } - if (key_ring_hole == true){ - translate([0, block_size * 8 * (char_count+1)/2, 3/2]) - difference(){ - cube(size = [block_size * 8, block_size * 8 , 3], center = true); - cube(size = [block_size * 4, block_size * 4 , 5], center = true); - } - } +/* + chars = chars array + block_size = letter size (block size 1 will result in 8mm per letter) + height = the Z height of each letter in mm + key_ring_hole = (boolean) Append a hole to a keyring, necklace etc. ? +*/ +module name_tag(chars = ["R", "E", "P", "R", "A", "P"], + block_size = 2, height = 3, key_ring_hole = true) { + char_count = len(chars); + union() { + translate(v = [0,-block_size*8*char_count/2+block_size*8/2,3]) { + 8bit_str(chars, char_count, block_size, height); + } + translate(v = [0,0,3/2]) { + color([0,0,1,1]) { + cube(size = [block_size * 8, block_size * 8 * char_count, 3], center = true); + } + } + if (key_ring_hole == true){ + translate([0, block_size * 8 * (char_count+1)/2, 3/2]) + difference(){ + cube(size = [block_size * 8, block_size * 8 , 3], center = true); + cube(size = [block_size * 4, block_size * 4 , 5], center = true); + } + } + } } diff --git a/bitmap/test_name_tag.scad b/bitmap/test_name_tag.scad new file mode 100644 index 00000000..a3bcf405 --- /dev/null +++ b/bitmap/test_name_tag.scad @@ -0,0 +1,19 @@ +include <../bitmap/name_tag.scad>; + +translate([0,0,0]) +name_tag("name_tag"); + +translate([20,0,0]) // 0 + 16/2 + 16/2 + 4 +name_tag("NAME_TAG"); + +translate([52,0,0]) // 20 + 16/2 + 40/2 + 4 +name_tag("name_tag", block_size=5); + +translate([96,0,0]) // 52 + 40/2 + 40/2 + 4 +name_tag("NAME_TAG", block_size=5); + +translate([130,0,0]) // 92 + 40/2 + 16/2 + 4 +name_tag("name_tag", height=30); + +translate([150,0,0]) // 130 + 16/2 + 16/2 + 4 +name_tag("NAME_TAG", height=30); diff --git a/boxes.scad b/boxes.scad index d9cb1eeb..8867477e 100644 --- a/boxes.scad +++ b/boxes.scad @@ -2,42 +2,45 @@ // Version: 1.0 // Author: Marius Kintel // Copyright: 2010 -// License: BSD +// License: 2-clause BSD License (http://opensource.org/licenses/BSD-2-Clause) -// roundedBox([width, height, depth], float radius, bool sidesonly); +// +// roundedCube([x, y, z], r, sidesonly=true/false, center=true/false); +// roundedCube(x, r, sidesonly=true/false, center=true/false); // EXAMPLE USAGE: -// roundedBox([20, 30, 40], 5, true); +// roundedCube([20, 30, 40], 5, true, true); -// size is a vector [w, h, d] +// Only for backwards compatibility with existing scripts, (always centered, radius instead of consistent "r" naming. module roundedBox(size, radius, sidesonly) { - rot = [ [0,0,0], [90,0,90], [90,90,0] ]; - if (sidesonly) { - cube(size - [2*radius,0,0], true); - cube(size - [0,2*radius,0], true); - for (x = [radius-size[0]/2, -radius+size[0]/2], - y = [radius-size[1]/2, -radius+size[1]/2]) { - translate([x,y,0]) cylinder(r=radius, h=size[2], center=true); - } - } - else { - cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true); - cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true); - cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true); + echo("WARNING: roundedBox(size, radius, sidesonly) is deprecated, use roundedCube(size, r, sidesonly, center)"); + roundedCube(size, radius, sidesonly, true); +} - for (axis = [0:2]) { - for (x = [radius-size[axis]/2, -radius+size[axis]/2], - y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) { - rotate(rot[axis]) - translate([x,y,0]) - cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true); +// New implementation +module roundedCube(size, r, sidesonly, center) { + s = is_list(size) ? size : [size,size,size]; + translate(center ? -s/2 : [0,0,0]) { + if (sidesonly) { + hull() { + translate([ r, r]) cylinder(r=r, h=s[2]); + translate([ r,s[1]-r]) cylinder(r=r, h=s[2]); + translate([s[0]-r, r]) cylinder(r=r, h=s[2]); + translate([s[0]-r,s[1]-r]) cylinder(r=r, h=s[2]); } } - for (x = [radius-size[0]/2, -radius+size[0]/2], - y = [radius-size[1]/2, -radius+size[1]/2], - z = [radius-size[2]/2, -radius+size[2]/2]) { - translate([x,y,z]) sphere(radius); + else { + hull() { + translate([ r, r, r]) sphere(r=r); + translate([ r, r,s[2]-r]) sphere(r=r); + translate([ r,s[1]-r, r]) sphere(r=r); + translate([ r,s[1]-r,s[2]-r]) sphere(r=r); + translate([s[0]-r, r, r]) sphere(r=r); + translate([s[0]-r, r,s[2]-r]) sphere(r=r); + translate([s[0]-r,s[1]-r, r]) sphere(r=r); + translate([s[0]-r,s[1]-r,s[2]-r]) sphere(r=r); + } } } } diff --git a/constants.scad b/constants.scad index 141c0c3e..fe1120b0 100644 --- a/constants.scad +++ b/constants.scad @@ -1,5 +1,5 @@ // MIT license - +// Author: Elmo Mäntynen TAU = 6.2831853071; //2*PI, see http://tauday.com/ PI = TAU/2; diff --git a/fonts.scad b/fonts.scad index 0ce6a771..770bc216 100644 --- a/fonts.scad +++ b/fonts.scad @@ -1,5 +1,7 @@ // Font Functions // Encoding from http://en.wikipedia.org/wiki/ASCII +// Author: Andrew Plumb +// License: LGPL 2.1 module outline_2d(outline,points,paths,width=0.1,resolution=8) { if(outline && resolution > 4) { @@ -22,16 +24,53 @@ module bold_2d(bold,width=0.2,resolution=8) { for(j=[0:$children-1]) { if(bold) { union() { - child(j); - for(i=[0:resolution-1]) assign(dx=width*cos(360*i/resolution),dy=width*sin(360*i/resolution)) - translate([dx,dy]) child(j); + children(j); + for(i=[0:resolution-1]) { + dx=width*cos(360*i/resolution); + dy=width*sin(360*i/resolution); + translate([dx,dy]) children(j); + } } } else { - child(j); + children(j); } } } +module polytext(charstring,size,font,line=0,justify=1,align=-1 + ,bold=false,bold_width=0.2,bold_resolution=8 + ,underline=false,underline_start=[0,0],underline_width=1.0 + ,outline=false,outline_width=0.2,outline_resolution=8 + ,strike=false,strike_start=[-0.5,0],strike_width=1.0 + ) { + line_length=len(charstring)*font[0][0]; + line_shift_x=-line_length/2+justify*line_length/2; + char_width=font[0][0]; + char_height=font[0][1]; + char_shift_height=-char_height/2-align*char_height/2; + char_thickness=font[0][2]; + char_index_map=search(charstring,font[2],1,1); + for(i=[0:len(char_index_map)-1]) { + thisCharIndex=char_index_map[i]; + x_pos=i*size+line_shift_x*size/char_width; + translate([x_pos,line*size+char_shift_height*size/char_height]) scale([size/char_width,size/char_height]) { + if(char_thickness==0) + bold_2d(bold,width=bold_width,resolution=bold_resolution) + outline_2d(outline,points=font[2][thisCharIndex][6][0],paths=font[2][thisCharIndex][6][1] + ,width=outline_width,resolution=outline_resolution); + if( charstring[i] != " " ) { + if(underline) translate(underline_start) + square(size=[char_width-2*underline_start[0],underline_width],center=false); + if(strike) translate([strike_start[0],char_height/2+strike_start[1]]) + square(size=[char_width-2*strike_start[0],strike_width],center=false); + } + if(char_thickness>0) + polyhedron(points=font[2][thisCharIndex][6][0],triangles=font[2][thisCharIndex][6][1]); + } + } +} + + function 8bit_polyfont(dx=0.1,dy=0.1) = [ [8,8,0,"fixed"],["Decimal Byte","Caret Notation","Character Escape Code","Abbreviation","Name","Bound Box","[points,paths]"] ,[ @@ -514,3 +553,191 @@ function 8bit_polyfont(dx=0.1,dy=0.1) = [ ,[127,"^?","", "DEL","Delete",[[0,0],[8,8]],[]] ] ]; +// From http://www.brailleauthority.org/sizespacingofbraille/ +// +// Section 3.2 of Specification 800 (Braille Books and Pamphlets) February 2008 reads as follows: +// Size and Spacing +// 3.2.1 The nominal height of braille dots shall be 0.019 inches [0.48 mm] and shall be uniform within any given transcription. +// 3.2.2 The nominal base diameter of braille dots shall be 0.057 inches [1.44 mm]. +// 3.2.3 Cell spacing of dots shall conform to the following: +// 3.2.3.1 The nominal distance from center to center of adjacent dots (horizontally or vertically, but not diagonally) +// in the same cell shall be 0.092 inches [2.340 mm]. +// 3.2.3.2 The nominal distance from center to center of corresponding dots in adjacent cells shall be 0.245 inches [6.2 mm]. +// 3.2.4 The nominal line spacing of braille cells from center to center of nearest corresponding dots in adjacent lines shall +// be 0.400 inches [1.000 cm]. +// +// Additional References: +// http://www.loc.gov/nls/specs/800.pdf +// http://www.tiresias.org/research/reports/braille_cell.htm +module braille_ascii_spec800(inString,dot_backing=true,cell_backing=false,justify=1,align=-1,dot_h=0.48,dot_d=1.44,dot_spacing=2.340,cell_d2d_spacing=6.2, line_d2d_spacing=10.0, echo_translate=true) { + // justify: + // -1 : left side + // 0 : center + // 1 : right side (default) + // align: + // -1 : bottom braille cell edge - shift up (default) + // 0 : center braille cell + // 1 : top braille cell edge - shift down + thisFont=braille_ascii_font(dot_h=dot_h,dot_d=dot_d,dot_spacing=dot_spacing + ,cell_d2d_spacing=cell_d2d_spacing,line_d2d_spacing=line_d2d_spacing); + x_shift=thisFont[0][0]; + y_shift=thisFont[0][1]; + theseIndicies=search(inString,thisFont[2],1,1); + for( i=[0:len(theseIndicies)-1]) translate([i*x_shift-(1-justify)*x_shift*len(theseIndicies)/2,-y_shift*(align+1)/2]) { + dotPattern=thisFont[2][theseIndicies[i]][6]; + if(dot_backing) translate([cell_d2d_spacing/2-dot_spacing/2-dot_d/2,line_d2d_spacing/2-dot_spacing-dot_d/2,-dot_h]) + cube(size=[dot_spacing+dot_d,2*dot_spacing+dot_d,dot_h],center=false); + if(cell_backing) translate([0,0,-dot_h]) + cube(size=[x_shift,y_shift,dot_h],center=false); + if(echo_translate) echo(str(inString[i]," maps to '",thisFont[2][theseIndicies[i]][4],"'")); + for(dotIndex=dotPattern) { + translate([cell_d2d_spacing/2-dot_spacing/2+floor((dotIndex-1)/3)*dot_spacing + , line_d2d_spacing/2-dot_spacing+(2-(dotIndex-1)%3)*dot_spacing]) + scale([dot_d,dot_d,2*dot_h]) sphere($fn=8,r=0.5); + } + } +} + +// Encoding from http://en.wikipedia.org/wiki/Braille_ASCII +// Dot Pattern: +// 1 4 +// 2 5 +// 3 6 +function braille_ascii_font(dot_h=0.48,dot_d=1.44,dot_spacing=2.340,cell_d2d_spacing=6.2,line_d2d_spacing=10.0) = [ + [cell_d2d_spacing,line_d2d_spacing,0,"bump"],["Decimal Byte","Caret Notation","Character Escape Code","Abbreviation","Name","Bound Box","[bump_list]"] + ,[ + [ 0,"^@","\0","NUL","Null character",[[0,0],[2,3]],[]] + ,[ 1,"^A","", "SOH","Start of Header",[[0,0],[2,3]],[]] + ,[ 2,"^B","", "STX","Start of Text",[[0,0],[2,3]],[]] + ,[ 3,"^C","", "ETX","End of Text",[[0,0],[2,3]],[]] + ,[ 4,"^D","", "EOT","End of Transmission",[[0,0],[2,3]],[]] + ,[ 5,"^E","", "ENQ","Enquiry",[[0,0],[2,3]],[]] + ,[ 6,"^F","", "ACK","Acknowledgment",[[0,0],[2,3]],[]] + ,[ 7,"^G","\a","BEL","Bell",[[0,0],[2,3]],[]] + ,[ 8,"^H","\b","BS", "Backspace",[[0,0],[2,3]],[]] + ,[ 9,"^I","\t","HT", "Horizontal Tab",[[0,0],[2,3]],[]] + ,[ 10,"^J","\n","LF", "Line Feed",[[0,0],[2,3]],[]] + ,[ 11,"^K","\v","VT", "Vertical Tab",[[0,0],[2,3]],[]] + ,[ 12,"^L","\f","FF", "Form feed",[[0,0],[2,3]],[]] + ,[ 13,"^M","\r","CR", "Carriage return",[[0,0],[2,3]],[]] + ,[ 14,"^N","", "SO", "Shift Out",[[0,0],[2,3]],[]] + ,[ 15,"^O","", "SI", "Shift In",[[0,0],[2,3]],[]] + ,[ 16,"^P","", "DLE","Data Link Escape",[[0,0],[2,3]],[]] + ,[ 17,"^Q","", "DC1","Device Control 1",[[0,0],[2,3]],[]] + ,[ 18,"^R","", "DC2","Device Control 2",[[0,0],[2,3]],[]] + ,[ 19,"^S","", "DC3","Device Control 3",[[0,0],[2,3]],[]] + ,[ 20,"^T","", "DC4","Device Control 4",[[0,0],[2,3]],[]] + ,[ 21,"^U","", "NAK","Negative Acknowledgement",[[0,0],[2,3]],[]] + ,[ 22,"^V","", "SYN","Synchronous Idle",[[0,0],[2,3]],[]] + ,[ 23,"^W","", "ETB","End of Transmission Block",[[0,0],[2,3]],[]] + ,[ 24,"^X","", "CAN","Cancel",[[0,0],[2,3]],[]] + ,[ 25,"^Y","", "EM", "End of Medium",[[0,0],[2,3]],[]] + ,[ 26,"^Z","", "SUB","Substitute",[[0,0],[2,3]],[]] + ,[ 27,"^[","\e","ESC","Escape",[[0,0],[2,3]],[]] + ,[ 28,"^\\","", "FS", "File Separator",[[0,0],[2,3]],[]] + ,[ 29,"^]","", "GS", "Group Separator",[[0,0],[2,3]],[]] + ,[ 30,"^^","", "RS", "Record Separator",[[0,0],[2,3]],[]] + ,[ 31,"^_","", "US", "Unit Separator",[[0,0],[2,3]],[]] + ,[ 32," "," ", "", "Space",[[0,0],[2,3]],[]] + ,[ 33,"!","!", "", "the",[[0,0],[2,3]],[ 2,3,4,6 ]] + ,[ 34,"\"","\"","", "(contraction)",[[0,0],[2,3]],[ 5 ]] + ,[ 35,"#","#", "", "(number prefix)",[[0,0],[2,3]],[ 3,4,5,6 ]] + ,[ 36,"$","$", "", "ed",[[0,0],[2,3]],[ 1,2,4,6 ]] + ,[ 37,"%","%", "", "sh",[[0,0],[2,3]],[ 1,4,6 ]] + ,[ 38,"&","&", "", "and",[[0,0],[2,3]],[ 1,2,3,4,6 ]] + ,[ 39,"'","'", "", "",[[0,0],[2,3]],[ 3 ]] + ,[ 40,"(","(", "", "of",[[0,0],[2,3]],[ 1,2,3,5,6 ]] + ,[ 41,")",")", "", "with",[[0,0],[2,3]],[ 2,3,4,5,6 ]] + ,[ 42,"*","*", "", "ch",[[0,0],[2,3]],[ 1,6 ]] + ,[ 43,"+","+", "", "ing",[[0,0],[2,3]],[ 3,4,6 ]] + ,[ 44,",",",", "", "(uppercase prefix)",[[0,0],[2,3]],[ 6 ]] + ,[ 45,"-","-", "", "",[[0,0],[2,3]],[ 3,6 ]] + ,[ 46,".",".", "", "(italic prefix)",[[0,0],[2,3]],[ 4,6 ]] + ,[ 47,"/","/", "", "st",[[0,0],[2,3]],[ 3,4 ]] + ,[ 48,"0","0", "", "\"",[[0,0],[2,3]],[ 3,5,6 ]] + ,[ 49,"1","1", "", ",",[[0,0],[2,3]],[ 2 ]] + ,[ 50,"2","2", "", ";",[[0,0],[2,3]],[ 2,3 ]] + ,[ 51,"3","3", "", ":",[[0,0],[2,3]],[ 2,5 ]] + ,[ 52,"4","4", "", ".",[[0,0],[2,3]],[ 2,5,6 ]] + ,[ 53,"5","5", "", "en",[[0,0],[2,3]],[ 2,6 ]] + ,[ 54,"6","6", "", "!",[[0,0],[2,3]],[ 2,3,5 ]] + ,[ 55,"7","7", "", "( or )",[[0,0],[2,3]],[ 2,3,5,6 ]] + ,[ 56,"8","8", "", "\" or ?",[[0,0],[2,3]],[ 2,3,6 ]] + ,[ 57,"9","9", "", "in",[[0,0],[2,3]],[ 3,5 ]] + ,[ 58,":",":", "", "wh",[[0,0],[2,3]],[ 1,5,6 ]] + ,[ 59,";",";", "", "(letter prefix)",[[0,0],[2,3]],[ 5,6 ]] + ,[ 60,"<","<", "", "gh",[[0,0],[2,3]],[ 1,2,6 ]] + ,[ 61,"=","=", "", "for",[[0,0],[2,3]],[ 1,2,3,4,5,6 ]] + ,[ 62,">",">", "", "ar",[[0,0],[2,3]],[ 3,4,5 ]] + ,[ 63,"?","?", "", "th",[[0,0],[2,3]],[ 1,4,5,6 ]] + ,[ 64,"@","@", "", "(accent prefix)",[[0,0],[2,3]],[ 4 ]] + ,[ 65,"A","A", "", "a",[[0,0],[2,3]],[ 1 ]] + ,[ 66,"B","B", "", "b",[[0,0],[2,3]],[ 1,2 ]] + ,[ 67,"C","C", "", "c",[[0,0],[2,3]],[ 1,4 ]] + ,[ 68,"D","D", "", "d",[[0,0],[2,3]],[ 1,4,5 ]] + ,[ 69,"E","E", "", "e",[[0,0],[2,3]],[ 1,5 ]] + ,[ 70,"F","F", "", "f",[[0,0],[2,3]],[ 1,2,4 ]] + ,[ 71,"G","G", "", "g",[[0,0],[2,3]],[ 1,2,4,5 ]] + ,[ 72,"H","H", "", "h",[[0,0],[2,3]],[ 1,2,5 ]] + ,[ 73,"I","I", "", "i",[[0,0],[2,3]],[ 2,4 ]] + ,[ 74,"J","J", "", "j",[[0,0],[2,3]],[ 2,4,5 ]] + ,[ 75,"K","K", "", "k",[[0,0],[2,3]],[ 1,3 ]] + ,[ 76,"L","L", "", "l",[[0,0],[2,3]],[ 1,2,3 ]] + ,[ 77,"M","M", "", "m",[[0,0],[2,3]],[ 1,3,4 ]] + ,[ 78,"N","N", "", "n",[[0,0],[2,3]],[ 1,3,4,5 ]] + ,[ 79,"O","O", "", "o",[[0,0],[2,3]],[ 1,3,5 ]] + ,[ 80,"P","P", "", "p",[[0,0],[2,3]],[ 1,2,3,4 ]] + ,[ 81,"Q","Q", "", "q",[[0,0],[2,3]],[ 1,2,3,4,5 ]] + ,[ 82,"R","R", "", "r",[[0,0],[2,3]],[ 1,2,3,5 ]] + ,[ 83,"S","S", "", "s",[[0,0],[2,3]],[ 2,3,4 ]] + ,[ 84,"T","T", "", "t",[[0,0],[2,3]],[ 2,3,4,5 ]] + ,[ 85,"U","U", "", "u",[[0,0],[2,3]],[ 1,3,6 ]] + ,[ 86,"V","V", "", "v",[[0,0],[2,3]],[ 1,2,3,6 ]] + ,[ 87,"W","W", "", "w",[[0,0],[2,3]],[ 2,4,5,6 ]] + ,[ 88,"X","X", "", "x",[[0,0],[2,3]],[ 1,3,4,6 ]] + ,[ 89,"Y","Y", "", "y",[[0,0],[2,3]],[ 1,3,4,5,6 ]] + ,[ 90,"Z","Z", "", "z",[[0,0],[2,3]],[ 1,3,5,6 ]] + ,[ 91,"[","[", "", "ow",[[0,0],[2,3]],[ 2,4,6 ]] // ]] + ,[ 92,"\\","\\","", "ou",[[0,0],[2,3]],[ 1,2,5,6 ]] // [[ + ,[ 93,"]","]", "", "er",[[0,0],[2,3]],[ 1,2,4,5,6 ]] + ,[ 94,"^","^", "", "(contraction)",[[0,0],[2,3]],[ 4,5 ]] + ,[ 95,"_","_", "", "(contraction)",[[0,0],[2,3]],[ 4,5,6 ]] + ,[ 96,"`","`", "", "",[[0,0],[2,3]],[ + ]] +// Repeating upper-case patterns for lower-case letters. + ,[ 97,"a","a", "", "a",[[0,0],[2,3]],[ 1 ]] + ,[ 98,"b","b", "", "b",[[0,0],[2,3]],[ 1,2 ]] + ,[ 99,"c","c", "", "c",[[0,0],[2,3]],[ 1,4 ]] + ,[100,"d","d", "", "d",[[0,0],[2,3]],[ 1,4,5 ]] + ,[101,"e","e", "", "e",[[0,0],[2,3]],[ 1,5 ]] + ,[102,"f","f", "", "f",[[0,0],[2,3]],[ 1,2,4 ]] + ,[103,"g","g", "", "g",[[0,0],[2,3]],[ 1,2,4,5 ]] + ,[104,"h","h", "", "h",[[0,0],[2,3]],[ 1,2,5 ]] + ,[105,"i","i", "", "i",[[0,0],[2,3]],[ 2,4 ]] + ,[106,"j","j", "", "j",[[0,0],[2,3]],[ 2,4,5 ]] + ,[107,"k","k", "", "k",[[0,0],[2,3]],[ 1,3 ]] + ,[108,"l","l", "", "l",[[0,0],[2,3]],[ 1,2,3 ]] + ,[109,"m","m", "", "m",[[0,0],[2,3]],[ 1,3,4 ]] + ,[110,"n","n", "", "n",[[0,0],[2,3]],[ 1,3,4,5 ]] + ,[111,"o","o", "", "o",[[0,0],[2,3]],[ 1,3,5 ]] + ,[112,"p","p", "", "p",[[0,0],[2,3]],[ 1,2,3,4 ]] + ,[113,"q","q", "", "q",[[0,0],[2,3]],[ 1,2,3,4,5 ]] + ,[114,"r","r", "", "r",[[0,0],[2,3]],[ 1,2,3,5 ]] + ,[115,"s","s", "", "s",[[0,0],[2,3]],[ 2,3,4 ]] + ,[116,"t","t", "", "t",[[0,0],[2,3]],[ 2,3,4,5 ]] + ,[117,"u","u", "", "u",[[0,0],[2,3]],[ 1,3,6 ]] + ,[118,"v","v", "", "v",[[0,0],[2,3]],[ 1,2,3,6 ]] + ,[119,"w","w", "", "w",[[0,0],[2,3]],[ 2,4,5,6 ]] + ,[120,"x","x", "", "x",[[0,0],[2,3]],[ 1,3,4,6 ]] + ,[121,"y","y", "", "y",[[0,0],[2,3]],[ 1,3,4,5,6 ]] + ,[122,"z","z", "", "z",[[0,0],[2,3]],[ 1,3,5,6 ]] + ,[123,"{","{", "", "",[[0,0],[2,3]],[ + ]] + ,[124,"|","|", "", "",[[0,0],[2,3]],[ + ]] + ,[125,"}","}", "", "",[[0,0],[2,3]],[ + ]] + ,[126,"~","~", "", "",[[0,0],[2,3]],[ + ]] + ,[127,"^?","", "DEL","Delete",[[0,0],[2,3]],[]] + ] ]; diff --git a/gears.scad b/gears.scad index 2bc5e021..29ca9a22 100644 --- a/gears.scad +++ b/gears.scad @@ -14,41 +14,62 @@ // Circular pitch: Length of the arc from one tooth to the next // Clearance: Radial distance between top of tooth on one gear to bottom of gap on another. +function pitch_circular2diameter(number_of_teeth,circular_pitch) = number_of_teeth * circular_pitch / 180; +function pitch_diametral2diameter(number_of_teeth,diametral_pitch) = number_of_teeth / diametral_pitch; + module gear(number_of_teeth, circular_pitch=false, diametral_pitch=false, - pressure_angle=20, clearance = 0) + pressure_angle=20, clearance = 0, + verbose=false) { + if(verbose) { + echo("gear arguments:"); + echo(str(" number_of_teeth: ", number_of_teeth)); + echo(str(" circular_pitch: ", circular_pitch)); + echo(str(" diametral_pitch: ", diametral_pitch)); + echo(str(" pressure_angle: ", pressure_angle)); + echo(str(" clearance: ", clearance)); + } if (circular_pitch==false && diametral_pitch==false) echo("MCAD ERROR: gear module needs either a diametral_pitch or circular_pitch"); + if(verbose) echo("gear calculations:"); //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_diameter = pitch_circular2diameter(number_of_teeth,circular_pitch); + if(verbose) echo (str(" pitch_diameter: ", pitch_diameter)); pitch_radius = pitch_diameter/2; // Base Circle base_diameter = pitch_diameter*cos(pressure_angle); + if(verbose) echo (str(" base_diameter: ", base_diameter)); base_radius = base_diameter/2; // Diametrial pitch: Number of teeth per unit length. pitch_diametrial = number_of_teeth / pitch_diameter; + if(verbose) echo (str(" pitch_diametrial: ", pitch_diametrial)); // Addendum: Radial distance from pitch circle to outside circle. addendum = 1/pitch_diametrial; + if(verbose) echo (str(" addendum: ", addendum)); //Outer Circle outer_radius = pitch_radius+addendum; outer_diameter = outer_radius*2; + if(verbose) echo (str(" outer_diameter: ", outer_diameter)); // Dedendum: Radial distance from pitch circle to root diameter dedendum = addendum + clearance; + if(verbose) echo (str(" dedendum: ", dedendum)); // Root diameter: Diameter of bottom of tooth spaces. root_radius = pitch_radius-dedendum; root_diameter = root_radius * 2; + if(verbose) echo (str(" root_diameter: ", root_diameter)); half_thick_angle = 360 / (4 * number_of_teeth); + if(verbose) echo (str(" half_thick_angle: ", half_thick_angle)); union() { @@ -153,12 +174,13 @@ module test_gears() module demo_3d_gears() { //double helical gear - // (helics don't line up perfectly - for display purposes only ;) translate([50,0]) { linear_extrude(height = 10, center = true, convexity = 10, twist = -45) gear(number_of_teeth=17,diametral_pitch=1); - translate([0,0,10]) linear_extrude(height = 10, center = true, convexity = 10, twist = 45) + translate([0,0,10]) + rotate([0,180,180/17]) + linear_extrude(height = 10, center = true, convexity = 10, twist = 45) gear(number_of_teeth=17,diametral_pitch=1); } diff --git a/get_submodules.py b/get_submodules.py deleted file mode 100755 index e1d78bed..00000000 --- a/get_submodules.py +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/python - -import os - -os.system("git submodule update --init") diff --git a/gridbeam.scad b/gridbeam.scad index 33b7f6bf..b7fd0b37 100644 --- a/gridbeam.scad +++ b/gridbeam.scad @@ -113,11 +113,7 @@ if (mode == "dxf") { } } -module translateBeam(v) { - for (i = [0 : $children - 1]) { - translate(v * beam_width) child(i); - } -} +module translateBeam(v) translate(v * beam_width) children([0 : $children - 1]); module topShelf(width, depth, corners) { if (mode == "model") { diff --git a/involute_gears.scad b/involute_gears.scad index fd80efed..39b24aa3 100644 --- a/involute_gears.scad +++ b/involute_gears.scad @@ -5,10 +5,10 @@ // Simple Test: //gear (circular_pitch=700, -// gear_thickness = 12, -// rim_thickness = 15, -// hub_thickness = 17, -// circles=8); +// gear_thickness = 12, +// rim_thickness = 15, +// hub_thickness = 17, +// circles=8); //Complex Spur Gear Test: //test_gears (); @@ -42,41 +42,41 @@ pi=3.1415926535897932384626433832795; // and pressure angle will mesh. module bevel_gear_pair ( - gear1_teeth = 41, - gear2_teeth = 7, - axis_angle = 90, - outside_circular_pitch=1000) + 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); - } + 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: @@ -84,398 +84,524 @@ 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) + 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); - } + 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) + 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,2,1],[0,3,2],[0,4,3],[0,1,5],[1,2,5],[2,3,5],[3,4,5],[0,5,4]]); - } - } - } - } +// 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]) + { + let ( + 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)) + { + let ( + 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,2,1],[0,3,2],[0,4,3],[0,1,5],[1,2,5],[2,3,5],[3,4,5],[0,5,4]]); + } + } + } + } } 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, - flat=false) + number_of_teeth=15, + circular_pitch=undef, diametral_pitch=undef, + pressure_angle=28, + clearance = undef, + gear_thickness=5, + rim_thickness=undef, + rim_width=undef, + hub_thickness=undef, + hub_diameter=undef, + spokes=0, + spoke_width=undef, + spoke_thickness=undef, + spoke_square=false, + centered_gear=false, + centered_hub=false, + bore_diameter=undef, + circles=0, + circle_diameter=undef, + backlash=0, + twist=0, + involute_facets=0, + flat=false) { - 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_exturde_flat_option(flat=flat, 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) - linear_exturde_flat_option(flat=flat, height=gear_thickness) - circle (r=rim_radius); - if (flat == false && hub_thickness > gear_thickness) - translate ([0,0,gear_thickness]) - linear_exturde_flat_option(flat=flat, height=hub_thickness-gear_thickness) - circle (r=hub_diameter/2); - } - translate ([0,0,-1]) - linear_exturde_flat_option(flat =flat, height=2+max(rim_thickness,hub_thickness,gear_thickness)) - circle (r=bore_diameter/2); - if (circles>0) - { - for(i=[0:circles-1]) - rotate([0,0,i*360/circles]) - translate([circle_orbit_diameter/2,0,-1]) - linear_exturde_flat_option(flat =flat, height=max(gear_thickness,rim_thickness)+3) - circle(r=circle_diameter/2); - } - } + // Check for undefined circular pitch (happens when neither circular_pitch or diametral_pitch are specified) + if (circular_pitch==undef) + 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!=undef?circular_pitch:pi/diametral_pitch); + + // Calculate default clearance if not specified + clearance = (clearance!=undef?clearance:0.25 * circular_pitch / pi); + + // Pitch diameter: Diameter of pitch circle. + pitch_diameter = number_of_teeth * circular_pitch / pi; + pitch_radius = pitch_diameter/2; + echo (str("Teeth: ", number_of_teeth, ", Pitch Radius: ", pitch_radius, ", Clearance: ", clearance)); + + // 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_thickness = (rim_thickness!=undef?(rim_thickness!=0?rim_thickness:gear_thickness):gear_thickness * 1.5); + rim_width = (rim_width!=undef?rim_width:root_radius * .1); + rim_radius = root_radius - rim_width; + + // Variables controlling the hub + hub_thickness = (hub_thickness!=undef?(hub_thickness!=0?hub_thickness:gear_thickness):gear_thickness * 2); + hub_diameter = (hub_diameter!=undef?hub_diameter:root_radius * .3); + hub_base = (centered_hub == false)? 0 : rim_thickness/2 - hub_thickness/2; + + // Variables controlling the spokes + spokes = spokes == undef? 0 : spokes; + spoke_thickness = (spoke_thickness == undef)? rim_thickness : spoke_thickness; + spoke_width = (spokes==0)? 1 : (spoke_width == undef)? 0.75 * pi * hub_diameter / spokes : spoke_width; + //spoke_depth is depth spoke must penetrate into hub to ensure complete penetration + spoke_depth = ((hub_diameter/2)^2-(spoke_width/2)^2)^0.5 +.01; + //spoke length is length of spoke including the depth sunk into the hub + spoke_length = spoke_depth+rim_radius-(hub_diameter/2.0); + //spoke raius is the distance from gear center to base of the spoke(inside the hub) + spoke_radius = (hub_diameter/2.0)-spoke_depth; + //echo (str("spoke_width: ",spoke_width,", hub_diameter: ",hub_diameter, ", spoke_depth: ",spoke_depth)); + + // Variables controlling the bore + bore_diameter = bore_diameter!=undef?bore_diameter:root_radius * .1; + + // 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_default_diameter = min ( + 0.70*circle_orbit_curcumference/circles, + (rim_radius+hub_diameter/2)*0.9); + circle_diameter=(circle_diameter != undef)? circle_diameter : circle_default_diameter; + echo(str("cir_orb_dia: ", circle_orbit_diameter, ", cir_orb_circumf: ", circle_orbit_curcumference, ", default cir dia: ",circle_default_diameter, ", cir_dia:",circle_diameter)); + difference() + { + union () + { + difference () + { + //start with a plane toothed disk gear + linear_extrude_flat_option(flat=flat, 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 we have a 0 hub thickness, then hub must be removed + if (hub_thickness == 0) + translate ([0,0,-1]) + cylinder (r=rim_radius,h=rim_thickness+2); + //if the rim is thicker than the gear, carve out gear body + else if (rim_thickness>gear_thickness){ + //if not centered, carve out only the top + if (centered_gear == false){ + translate ([0,0,gear_thickness]) + cylinder (r=rim_radius,h=rim_thickness); + } + else + //carve out half from top and half from bottom + union () + { + translate ([0,0,(gear_thickness + rim_thickness)/2]) + cylinder (r=rim_radius,h=rim_thickness+1); + translate ([0,0,-1 -(gear_thickness + rim_thickness)/2]) + cylinder (r=rim_radius,h=rim_thickness+1); + } + + } + } + + //extend the gear body if gear_thickness > rim_thickness unless spoked, + if (gear_thickness > rim_thickness) + { + if (centered_gear == false) + { + linear_extrude_flat_option(flat=flat, height=gear_thickness) + circle (r=rim_radius); + } + else + { + translate ([0,0,-(gear_thickness - rim_thickness)/2]) + linear_extrude_flat_option(flat=flat, height=gear_thickness) + circle (r=rim_radius); + } + //if rim is thicker than body, body protrudes into rim + } + //add the hub + translate ([0,0,hub_base]) + linear_extrude_flat_option(flat=flat, height=hub_thickness) + circle (r=hub_diameter/2); + + //add in spokes + if (spokes>0) + { + for(i=[0:spokes-1]) + translate([0,0,rim_thickness/2]) + rotate([90,0,i*360/spokes]) + translate([0,0,spoke_radius]) + { + if (spoke_square==true){ + resize([spoke_width,spoke_thickness,spoke_length]) + translate([0,0,.5]) + cube(1,center=true); + } + if (spoke_square==false){ + resize([spoke_width,spoke_thickness,spoke_length]) + cylinder(h=10,d=10); + } + } + } + } + + //remove the center bore + translate ([0,0,-1]) + linear_extrude_flat_option(flat =flat, height=2+max(rim_thickness,hub_thickness,gear_thickness)) + circle (r=bore_diameter/2); + + //remove circles from gear body + if (circles>0) + { + for(i=[0:circles-1]) + rotate([0,0,i*360/circles]) + translate([circle_orbit_diameter/2,0,-1]) + linear_extrude_flat_option(flat =flat, height=max(gear_thickness,rim_thickness)+3) + circle(r=circle_diameter/2); + } + } } -module linear_exturde_flat_option(flat =false, height = 10, center = false, convexity = 2, twist = 0) +module rack( + number_of_teeth=15, + circular_pitch=false, diametral_pitch=false, + pressure_angle=28, + clearance=0.2, + rim_thickness=8, + rim_width=5, + flat=false) { - if(flat==false) - { - linear_extrude(height = height, center = center, convexity = convexity, twist= twist) child(0); - } - else - { - child(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:pi/diametral_pitch); + pitch = circular_pitch; + + addendum = circular_pitch / pi; + dedendum = addendum + clearance; + pitch_slope = tan(pressure_angle); + + linear_extrude_flat_option(flat=flat, height=rim_thickness) + union() + { + translate([0,-dedendum-rim_width/2]) + square([number_of_teeth*pitch, rim_width],center=true); + + p1 = pitch / 4 + pitch_slope * dedendum; + p2 = pitch / 4 - pitch_slope * addendum; + for(i=[1:number_of_teeth]) + translate([pitch*(i-number_of_teeth/2-0.5),0]) + polygon(points=[ + [-p1,-dedendum], + [p1,-dedendum], + [p2,addendum], + [-p2,addendum] + ]); + } +} + +module linear_extrude_flat_option(flat =false, height = 10, center = false, convexity = 2, twist = 0) +{ + if(flat==false) + { + linear_extrude(height = height, center = center, convexity = convexity, twist= twist) children(0); + } + else + { + children(0); + } } module gear_shape ( - number_of_teeth, - pitch_radius, - root_radius, - base_radius, - outer_radius, - half_thick_angle, - involute_facets) + 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); - } - } - } + 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) + 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]]); - } - } - } + 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]) { + 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); + 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 @@ -490,26 +616,26 @@ function involute_intersect_angle (base_radius, radius) = sqrt (pow (radius/base 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] + 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] + 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] + 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)) + base_radius*(cos (involute_angle) + involute_angle*pi/180*sin (involute_angle)), + base_radius*(sin (involute_angle) - involute_angle*pi/180*cos (involute_angle)) ]; @@ -518,181 +644,204 @@ function involute (base_radius, involute_angle) = 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); - } + $fs = 0.2; + $fa =1; + translate([17,-15]) + { + gear (number_of_teeth=17, + circular_pitch=500*pi/180, + spokes=6, + spoke_thickness=4, + gear_thickness=0, + rim_thickness=5, + hub_thickness=5, + hub_diameter=10, + circles=0); + + rotate ([0,0,360*4/17]) + translate ([39.088888,0,0]) + { + gear (number_of_teeth=11, + circular_pitch=500*pi/180, + hub_diameter=0, + rim_width=65); + translate ([0,0,8]) + { + gear (number_of_teeth=6, + circular_pitch=300*pi/180, + 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*pi/180, + 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*pi/180, + circles=6, + circle_diameter=12, + spokes=6, + gear_thickness=2, + hub_thickness=10, + centered_gear=true, + spoke_thickness=3, + hub_diameter=2*8.88888889); + + translate ([-37.5,0,0]) + rotate ([0,0,-90]) + rack ( + circular_pitch=500*pi/180 + ); + + translate ([0,0,10]) + { + gear ( + number_of_teeth=14, + circular_pitch=200*pi/180, + pressure_angle=5, + twist=30, + 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=10, + circular_pitch=200*pi/180, + pressure_angle=5, + clearance = 0.2, + gear_thickness = 10, + rim_thickness = 8, + twist=-30*8/10, + rim_width = 15, + hub_thickness = 10, + centered_hub=true, + hub_diameter=7, + bore_diameter=4, + circles=0); + } + } + + rotate ([0,0,360*-5/17]) + translate ([44.444444444,0,0]) + gear (number_of_teeth=15, + circular_pitch=500*pi/180, + 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*pi/180, + hub_diameter=0, + rim_width=5, + rim_thickness=10); + } } module meshing_double_helix () { - test_double_helix_gear (); + test_double_helix_gear (); - mirror ([0,1,0]) - translate ([58.33333333,0,0]) - test_double_helix_gear (teeth=13,circles=6); + 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) + 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); - } + //double helical gear + { + twist=200; + height=20; + pressure_angle=30; + + gear (number_of_teeth=teeth, + circular_pitch=700*pi/180, + 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*pi/180, + 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); + 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*pi/180, + 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*pi/180, + 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,1,0.5]) + translate([0,0,-5]) + cylinder ($fn=20,r=backlash / 4,h=25); } diff --git a/layouts.scad b/layouts.scad index bec8de71..99496aa6 100644 --- a/layouts.scad +++ b/layouts.scad @@ -31,7 +31,7 @@ module list(iHeight) { for (i = [0 : $children-1]) - translate([0,i*iHeight]) child(i); + translate([0,i*iHeight]) children(i); } module grid(iWidth,iHeight,inYDir = true,limit=3) { @@ -39,6 +39,6 @@ module grid(iWidth,iHeight,inYDir = true,limit=3) { translate([(inYDir)? (iWidth)*(i%limit) : (iWidth)*floor(i/limit), (inYDir)? (iHeight)*floor(i/limit) : (iHeight)*(i%limit)]) - child(i); + children(i); } } \ No newline at end of file diff --git a/lego_compatibility.scad b/lego_compatibility.scad index d47b5670..4e402d9b 100644 --- a/lego_compatibility.scad +++ b/lego_compatibility.scad @@ -1,9 +1,9 @@ // This file is placed under the public domain // from: http://www.thingiverse.com/thing:9512 +// Author: nefercheprure - -// EXAMPLES: +// Examples: // standard LEGO 2x1 tile has no pin // block(1,2,1/3,reinforcement=false,flat_top=true); // standard LEGO 2x1 flat has pin diff --git a/linear_bearing.scad b/linear_bearing.scad new file mode 100644 index 00000000..8f98bf81 --- /dev/null +++ b/linear_bearing.scad @@ -0,0 +1,98 @@ +//By Glen Chung, 2013. +//Dual licenced under Creative Commons Attribution-Share Alike 3.0 and LGPL2 or later + +include +include + +LINEAR_BEARING_dr = 0; //Inscribed circle +LINEAR_BEARING_D = 1; //Outer diameter +LINEAR_BEARING_L = 2; //Length +LINEAR_BEARING_B = 3; //Outer locking groove B +LINEAR_BEARING_D1 = 4; //Outer locking groove D1 +LINEAR_BEARING_W = 5; //W + + +// Common bearing names +LinearBearing = "LM8UU"; + +// Linear Bearing dimensions +// model == "XXXXX" ? [ dr, D, L, B, D1, W]: +function linearBearingDimensions(model) = + model == "LM3UU" ? [ 3*mm, 7*mm, 10*mm, 0.0*mm, 0.0*mm, 0.00*mm]: + model == "LM4UU" ? [ 4*mm, 8*mm, 12*mm, 0.0*mm, 0.0*mm, 0.00*mm]: + model == "LM5UU" ? [ 5*mm, 10*mm, 15*mm, 10.2*mm, 9.6*mm, 1.10*mm]: + model == "LM6UU" ? [ 6*mm, 12*mm, 19*mm, 13.5*mm, 11.5*mm, 1.10*mm]: + model == "LM8SUU" ? [ 8*mm, 15*mm, 17*mm, 11.5*mm, 14.3*mm, 1.10*mm]: + model == "LM10UU" ? [ 10*mm, 19*mm, 29*mm, 22.0*mm, 18.0*mm, 1.30*mm]: + model == "LM12UU" ? [ 12*mm, 21*mm, 30*mm, 23.0*mm, 20.0*mm, 1.30*mm]: + model == "LM13UU" ? [ 13*mm, 23*mm, 32*mm, 23.0*mm, 22.0*mm, 1.30*mm]: + model == "LM16UU" ? [ 16*mm, 28*mm, 37*mm, 26.5*mm, 27.0*mm, 1.60*mm]: + model == "LM20UU" ? [ 20*mm, 32*mm, 42*mm, 30.5*mm, 30.5*mm, 1.60*mm]: + model == "LM25UU" ? [ 25*mm, 40*mm, 59*mm, 41.0*mm, 38.0*mm, 1.85*mm]: + model == "LM30UU" ? [ 30*mm, 45*mm, 64*mm, 44.5*mm, 43.0*mm, 1.85*mm]: + model == "LM35UU" ? [ 35*mm, 52*mm, 70*mm, 49.5*mm, 49.0*mm, 2.10*mm]: + model == "LM40UU" ? [ 40*mm, 60*mm, 80*mm, 60.5*mm, 57.0*mm, 2.10*mm]: + model == "LM50UU" ? [ 50*mm, 80*mm, 100*mm, 74.0*mm, 76.5*mm, 2.60*mm]: + model == "LM60UU" ? [ 60*mm, 90*mm, 110*mm, 85.0*mm, 86.5*mm, 3.15*mm]: + model == "LM80UU" ? [ 80*mm, 120*mm, 140*mm, 105.5*mm, 116.0*mm, 4.15*mm]: + model == "LM100UU" ? [100*mm, 150*mm, 150*mm, 125.5*mm, 145.0*mm, 4.15*mm]: + /*model == "LM8UU" ?*/ [ 8*mm, 15*mm, 24*mm, 17.5*mm, 14.3*mm, 1.10*mm]; + + +function linearBearing_dr(model) = linearBearingDimensions(model)[LINEAR_BEARING_dr]; +function linearBearing_D(model) = linearBearingDimensions(model)[LINEAR_BEARING_D]; +function linearBearing_L(model) = linearBearingDimensions(model)[LINEAR_BEARING_L]; +function linearBearing_B(model) = linearBearingDimensions(model)[LINEAR_BEARING_B]; +function linearBearing_D1(model) = linearBearingDimensions(model)[LINEAR_BEARING_D1]; +function linearBearing_W(model) = linearBearingDimensions(model)[LINEAR_BEARING_W]; + +module linearBearing(pos=[0,0,0], angle=[0,0,0], model=LinearBearing, + material=Steel, sideMaterial=BlackPaint) { + dr = linearBearing_dr(model); + D = linearBearing_D(model); + L = linearBearing_L(model); + B = linearBearing_B(model); + D1 = linearBearing_D1(model); + W = linearBearing_W(model); + + innerRim = dr + (D - dr) * 0.2; + outerRim = D - (D - dr) * 0.2; + midSink = W/4; + + translate(pos) rotate(angle) union() { + color(material) + difference() { + // Basic ring + Ring([0,0,0], D, dr, L, material, material); + + if(W) { + // Side shields + Ring([0,0,-epsilon], outerRim, innerRim, L*epsilon+midSink, sideMaterial, material); + Ring([0,0,L-midSink-epsilon], outerRim, innerRim, L*epsilon+midSink, sideMaterial, material); + //Outer locking groove + Ring([0,0,(L-B)/2], D+epsilon, outerRim+W/2, W, material, material); + Ring([0,0,L-(L-B)/2], D+epsilon, outerRim+W/2, W, material, material); + } + } + if(W) + Ring([0,0,midSink], D-L*epsilon, dr+L*epsilon, L-midSink*2, sideMaterial, sideMaterial); + } + + module Ring(pos, od, id, h, material, holeMaterial) { + color(material) { + translate(pos) + difference() { + cylinder(r=od/2, h=h, $fn = 100); + color(holeMaterial) + translate([0,0,-10*epsilon]) + cylinder(r=id/2, h=h+20*epsilon, $fn = 100); + } + } + } + +} + + +//examples +//linearBearing(model="LM8UU"); +//linearBearing(model="LM10UU"); diff --git a/metric_fastners.scad b/metric_fastners.scad index 2849fea3..08b371dd 100644 --- a/metric_fastners.scad +++ b/metric_fastners.scad @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ diff --git a/multiply.scad b/multiply.scad index bca12c36..63e54cb1 100644 --- a/multiply.scad +++ b/multiply.scad @@ -9,21 +9,22 @@ include use -// TODO check that the axis parameter works as intended -// Duplicate everything $no of times around an $axis, for $angle/360 rounds -module spin(no, angle=360, axis=Z){ - for (i = [1:no]){ - rotate(normalized_axis(axis)*angle*no/i) union(){ - for (i = [0 : $children-1]) child(i); - } - } +// Copy everything $no of times around an $axis, spread over $angle +// If $strict==true or $angle==360, then spacing will leave an empty at $angle, +// otherwise, $no will be distributed so first is at 0deg, last copy at $angle degrees +// NOTE: $axis works (rotates around that axis), but pass parameter as lower case string +// eg: "x", "y", or "z". Alternatively, use units.scad vector definitions: X, Y, Z +module spin(no, angle=360, axis=Z, strict=false){ + divisor = (strict || angle==360) ? no : no-1; + for (i = [0:no-1]) + rotate(normalized_axis(axis)*angle*i/divisor) + children(); } -//Doesn't work currently -module duplicate(axis=Z) spin(no=2, axis=axis) child(0); +// Make a copy of children by rotating around $axis by 180 degrees +module duplicate(axis=Z) spin(no=2, axis=axis) children(); -module linear_multiply(no, separation, axis=Z){ - for (i = [0:no-1]){ - translate(i*separation*axis) child(0); - } -} +// Make $no copies along the $axis, separated by $separation +module linear_multiply(no, separation, axis=Z) + for (i = [0:no-1]) + translate(i*separation*normalized_axis(axis)) children(); diff --git a/nuts_and_bolts.scad b/nuts_and_bolts.scad index 8cb2a87e..95c275ab 100644 --- a/nuts_and_bolts.scad +++ b/nuts_and_bolts.scad @@ -19,7 +19,7 @@ METRIC_NUT_AC_WIDTHS = [ -1, //0 index is not used but reduces computation -1, - -1, + 4.38,//m2 6.40,//m3 8.10,//m4 9.20,//m5 @@ -59,7 +59,7 @@ METRIC_NUT_THICKNESS = [ -1, //0 index is not used but reduces computation -1, - -1, + 1.6,//m2 2.40,//m3 3.20,//m4 4.00,//m5 @@ -96,11 +96,11 @@ METRIC_NUT_THICKNESS = 29.00//m36 ]; -COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS = +COARSE_THREAD_METRIC_BOLT_MAJOR_DIAMETERS = [//based on max values -1, //0 index is not used but reduces computation -1, - -1, + 1.6,//m2 2.98,//m3 3.978,//m4 4.976,//m5 @@ -137,6 +137,51 @@ COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS = 35.940//m36 ]; +// Deprecated, but kept around for people who use the wrong spelling. +COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS = COARSE_THREAD_METRIC_BOLT_MAJOR_DIAMETERS; + +//Based on: http://www.roymech.co.uk/Useful_Tables/Screws/cap_screws.htm +METRIC_BOLT_CAP_DIAMETERS = +[ + -1, //0 index is not used but reduces computation + -1, + 3.8, + 5.50,//m3 + 7.00,//m4 + 8.50,//m5 + 10.00,//m6 + -1, + 13.00,//m8 + -1, + 16.00,//m10 + -1, + 18.00,//m12 + -1, + -1, + -1, + 24.00,//m16 + -1, + -1, + -1, + 30.00//m20 + -1, + -1, + -1, + 36.00,//m24 + -1, + -1, + -1, + -1, + -1, + 45.00,//m30 + -1, + -1, + -1, + -1, + -1, + 54.00//m36 +]; + module nutHole(size, units=MM, tolerance = +0.0001, proj = -1) { //takes a metric screw/nut size and looksup nut dimensions @@ -159,10 +204,9 @@ module nutHole(size, units=MM, tolerance = +0.0001, proj = -1) module boltHole(size, units=MM, length, tolerance = +0.0001, proj = -1) { - radius = COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS[size]/2+tolerance; -//TODO: proper screw cap values - capHeight = METRIC_NUT_THICKNESS[size]+tolerance; //METRIC_BOLT_CAP_HEIGHTS[size]+tolerance; - capRadius = METRIC_NUT_AC_WIDTHS[size]/2+tolerance; //METRIC_BOLT_CAP_RADIUS[size]+tolerance; + radius = COARSE_THREAD_METRIC_BOLT_MAJOR_DIAMETERS[size]/2+tolerance; + capHeight = size+tolerance; + capRadius = METRIC_BOLT_CAP_DIAMETERS[size]/2+tolerance; if (proj == -1) { diff --git a/openscad_testing.py b/openscad_testing.py index cadbc2f3..05f30e7e 100644 --- a/openscad_testing.py +++ b/openscad_testing.py @@ -7,16 +7,20 @@ def pytest_generate_tests(metafunc): if "modpath" in metafunc.funcargnames: + args1 = [] + args2 = [] for fpath, modnames in collect_test_modules().items(): basename = os.path.splitext(os.path.split(str(fpath))[1])[0] - #os.system("cp %s %s/" % (fpath, temppath)) if "modname" in metafunc.funcargnames: for modname in modnames: - print modname - metafunc.addcall(id=basename+"/"+modname, funcargs=dict(modname=modname, modpath=fpath)) + args2.append([fpath, modname]) else: - metafunc.addcall(id=os.path.split(str(fpath))[1], funcargs=dict(modpath=fpath)) + args1.append(fpath) + if "modname" in metafunc.funcargnames: + metafunc.parametrize(["modpath", "modname"], args2) + else: + metafunc.parametrize("modpath", args1) def test_module_compile(modname, modpath): tempname = modpath.basename + '-' + modname + '.scad' @@ -29,23 +33,21 @@ def test_module_compile(modname, modpath): %s(); """ % (modpath, modname) - print code + print(code) f.write(code) f.flush() - output = call_openscad(path=fpath, stlpath=stlpath, timeout=15) - print output + output = call_openscad(path=fpath, stlpath=stlpath, timeout=60) + print(output) assert output[0] is 0 for s in ("warning", "error"): - assert s not in output[2].strip().lower() + assert s not in output[2].strip().lower().decode("utf-8") assert len(stlpath.readlines()) > 2 def test_file_compile(modpath): stlpath = temppath.join(modpath.basename + "-test.stl") output = call_openscad(path=modpath, stlpath=stlpath) - print output + print(output) assert output[0] is 0 for s in ("warning", "error"): - assert s not in output[2].strip().lower() + assert s not in output[2].strip().lower().decode("utf-8") assert len(stlpath.readlines()) == 2 - - diff --git a/openscad_utils.py b/openscad_utils.py index 00d8dd9d..c4a0880b 100644 --- a/openscad_utils.py +++ b/openscad_utils.py @@ -1,4 +1,4 @@ -import py, re, os, signal, time, commands, sys +import py, re, os, signal, time, subprocess, sys from subprocess import Popen, PIPE mod_re = (r"\bmodule\s+(", r")\s*\(\s*") @@ -17,11 +17,11 @@ def extract_func_names(fpath, name_re=r"\w+"): def collect_test_modules(dirpath=None): dirpath = dirpath or py.path.local("./") - print "Collecting openscad test module names" + print("Collecting openscad test module names") test_files = {} for fpath in dirpath.visit('*.scad'): - #print fpath + #print(fpath) modules = extract_mod_names(fpath, r"test\w*") #functions = extract_func_names(fpath, r"test\w*") test_files[fpath] = modules @@ -32,20 +32,20 @@ class Timeout(Exception): pass def call_openscad(path, stlpath, timeout=5): if sys.platform == 'darwin': exe = 'OpenSCAD.app/Contents/MacOS/OpenSCAD' else: exe = 'openscad' - command = [exe, '-s', str(stlpath), str(path)] - print command + command = [exe, '-o', str(stlpath), str(path)] + print(command) if timeout: try: proc = Popen(command, stdout=PIPE, stderr=PIPE, close_fds=True) calltime = time.time() time.sleep(0.05) - #print calltime + #print(calltime) while True: if proc.poll() is not None: break time.sleep(0.5) - #print time.time() + #print(time.time()) if time.time() > calltime + timeout: raise Timeout() finally: @@ -57,7 +57,7 @@ def call_openscad(path, stlpath, timeout=5): return (proc.returncode,) + proc.communicate() else: - output = commands.getstatusoutput(" ".join(command)) + output = subprocess.getstatusoutput(" ".join(command)).decode("utf-8") return output + ('', '') def parse_output(text): diff --git a/polyholes.scad b/polyholes.scad index 82edb5f7..266b0cee 100644 --- a/polyholes.scad +++ b/polyholes.scad @@ -1,26 +1,29 @@ -// Copyright 2011 Nophead (of RepRap fame) -// This file is licensed under the terms of Creative Commons Attribution 3.0 Unported. - -// Using this holes should come out approximately right when printed -module polyhole(h, d) { - n = max(round(2 * d),3); - rotate([0,0,180]) - cylinder(h = h, r = (d / 2) / cos (180 / n), $fn = n); -} - -module test_polyhole(){ -difference() { - cube(size = [100,27,3]); - union() { - for(i = [1:10]) { - translate([(i * i + i)/2 + 3 * i , 8,-1]) - polyhole(h = 5, d = i); - - assign(d = i + 0.5) - translate([(d * d + d)/2 + 3 * d, 19,-1]) - polyhole(h = 5, d = d); - } - } -} -} - +// Copyright 2011 Nophead (of RepRap fame) +// This file is licensed under the terms of Creative Commons Attribution 3.0 Unported. + +// Using this holes should come out approximately right when printed +module polyhole(h, d=0, r=0, center=false) { + _r = (r == 0 ? d / 2 : r); + _d = (d == 0 ? r * 2 : d); + + n = max(round(2 * _d),3); + + rotate([0,0,180]) + cylinder(h = h, r = (_d / 2) / cos (180 / n), $fn = n, center=center); +} + +module test_polyhole(){ +difference() { + cube(size = [100,27,3]); + union() { + for(i = [1:10]) { + translate([(i * i + i)/2 + 3 * i , 8,-1]) + polyhole(h = 5, d = i); + + let(d = i + 0.5) + translate([(d * d + d)/2 + 3 * d, 19,-1]) + polyhole(h = 5, d = d); + } + } +} +} diff --git a/profiles.scad b/profiles.scad new file mode 100644 index 00000000..bd77e1c7 --- /dev/null +++ b/profiles.scad @@ -0,0 +1,89 @@ +// ============================================== +// Miscellaneous profiles (aluminum etc) +// By Vitaly Mankevich / contraptor.org, (c) 2012 +// LGPL 2.1 +// ============================================== +// +// PROFILES (DIMENSIONLESS UNLESS SPECIFIED) +// ----------------------------------------- +// profile_angle_equal(1, 1/8); +// profile_angle_unequal(1, 1/2, 1/16); +// profile_square_tube(1.5, 1/8); +// profile_rect_tube(1.5, 2, 1/8); +// profile_channel(1.5, 1, 1/8); +// +// profile_8020_fractional_1010(); // inches +// profile_misumi_metric_2020(); // millimeters +// profile_makerbeam(); // millimeters +// +// EXTRUDED PROFILES +// ----------------- +// linear_extrude (height = 3.5) profile_square_tube(1.5, 1/8); +// + +$fn = 24; + +module profile_angle_equal(side, wall) { + difference () { + square (side); + translate([wall, wall, 0]) square (side - wall); + } +} + +module profile_angle_unequal(side_x, side_y, wall) { + difference () { + square ([side_x, side_y]); + translate ([wall, wall, 0]) square ([side_x - wall, side_y - wall]); + } +} + +module profile_square_tube(side, wall) { + difference () { + square (side, center = true); + square (side-wall*2, center = true); + } +} + +module profile_rect_tube(side_x, side_y, wall) { + difference () { + square ([side_x, side_y], center = true); + square ([side_x - wall*2, side_y - wall*2], center = true); + } +} + +module profile_channel(base, side, wall) { + translate ([0, side/2, 0]) difference () { + square ([base, side], center = true); + translate ([0, wall/2, 0]) square ([base - wall*2, side - wall], center = true); + } +} + +module profile_tslot_generic (pitch, slot, lip, web, core, hole) { + // pitch = side width, slot = slot width, lip = thickness of the lip, web = thickness of the web, core = side of the center square, hole = center hole diameter + difference () { + union() { + difference () { + square (pitch, center=true); + square (pitch - lip*2, center=true); + square ([pitch, slot], center=true); + square ([slot, pitch], center=true); + } + rotate ([0, 0, 45]) square ([pitch*1.15, web], center=true); + rotate ([0, 0, -45]) square ([pitch*1.15, web], center=true); + square (core, center=true); + } + circle (hole/2); + } +} + +module profile_8020_fractional_1010 () { + profile_tslot_generic (pitch = 1, slot = 0.26, lip = 0.1, web = 0.13, core = 0.45, hole = 0.28); +} + +module profile_misumi_metric_2020 () { + profile_tslot_generic (pitch = 20, slot = 5.2, lip = 2, web = 2.6, core = 9, hole = 5.6); +} + +module profile_makerbeam () { + profile_tslot_generic (pitch = 10, slot = 2.5, lip = 1, web = 2, core = 1, hole = 0); +} diff --git a/regular_shapes.scad b/regular_shapes.scad index acba0bc0..c3acbcbf 100644 --- a/regular_shapes.scad +++ b/regular_shapes.scad @@ -14,7 +14,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ @@ -27,53 +27,66 @@ module triangle(radius) polygon(points=[[-a,-o],[0,radius],[a,-o]],paths=[[0,1,2]]); } -module reg_polygon(sides,radius) +module reg_polygon(sides, radius) { + echo(" + DEPRECATED: function 'reg_polygon' is now deprecated + please use 'regular_polygon' instead"); + + regular_polygon(sides, radius); +} + +module regular_polygon(sides, radius) { function dia(r) = sqrt(pow(r*2,2)/2); //sqrt((r*2^2)/2) if only we had an exponention op if(sides<2) square([radius,0]); if(sides==3) triangle(radius); if(sides==4) square([dia(radius),dia(radius)],center=true); - if(sides>4) circle(r=radius,$fn=sides); + if(sides>4) { + angles=[ for (i = [0:sides-1]) i*(360/sides) ]; + coords=[ for (th=angles) [radius*cos(th), radius*sin(th)] ]; + polygon(coords); + } } module pentagon(radius) { - reg_polygon(5,radius); + regular_polygon(5,radius); } -module hexagon(radius) +module hexagon(radius, diameter, across_flats) { - reg_polygon(6,radius); + r = across_flats ? across_flats/2/cos(30) : diameter ? diameter/2 : radius; + regular_polygon(6,r); } module heptagon(radius) { - reg_polygon(7,radius); + regular_polygon(7,radius); } module octagon(radius) { - reg_polygon(8,radius); + regular_polygon(8,radius); } module nonagon(radius) { - reg_polygon(9,radius); + regular_polygon(9,radius); } module decagon(radius) { - reg_polygon(10,radius); + regular_polygon(10,radius); } module hendecagon(radius) { - reg_polygon(11,radius); + regular_polygon(11,radius); } module dodecagon(radius) { - reg_polygon(12,radius); + regular_polygon(12,radius); } module ring(inside_diameter, thickness){ @@ -87,7 +100,7 @@ module ellipse(width, height) { scale([1, height/width, 1]) circle(r=width/2); } -// The ratio of lenght and width is about 1.39 for a real egg +// The ratio of length and width is about 1.39 for a real egg module egg_outline(width, length){ translate([0, width/2, 0]) union(){ rotate([0, 0, 180]) difference(){ @@ -129,8 +142,8 @@ module tubify(radius,wall) { difference() { - child(0); - translate([0, 0, -0.1]) scale([(radius-wall)/radius, (radius-wall)/radius, 2]) child(0); + children(0); + translate([0, 0, -0.1]) scale([(radius-wall)/radius, (radius-wall)/radius, 2]) children(0); } } @@ -154,9 +167,10 @@ module pentagon_tube(height,radius,wall) tubify(radius,wall) pentagon_prism(height,radius); } -module hexagon_prism(height,radius) +module hexagon_prism(height, radius, across_flats) { - linear_extrude(height=height) hexagon(radius); + linear_extrude(height=height) + hexagon(radius=radius, across_flats=across_flats); } module hexagon_tube(height,radius,wall) @@ -235,11 +249,11 @@ module square_pyramid(base_x, base_y,height) polyhedron(points=[[-w,-h,0],[-w,h,0],[w,h,0],[w,-h,0],[0,0,height]],triangles=[[0,3,2,1], [0,1,4], [1,2,4], [2,3,4], [3,0,4]]); } -module egg(width, lenght){ +module egg(width, length){ rotate_extrude() difference(){ - egg_outline(width, lenght); - translate([-lenght, 0, 0]) cube(2*lenght, center=true); + egg_outline(width, length); + translate([-length, 0, 0]) cube(2*length, center=true); } } diff --git a/screw.scad b/screw.scad index eb444ec0..2cea0b57 100644 --- a/screw.scad +++ b/screw.scad @@ -20,7 +20,7 @@ inner_diameter: thickness of the shaft module helix(pitch, length, slices=500){ rotations = length/pitch; linear_extrude(height=length, center=false, convexity=10, twist=360*rotations, slices=slices, $fn=100) - child(0); + children(); } module auger(pitch, length, outside_radius, inner_radius, taper_ratio = 0.25) { @@ -48,7 +48,7 @@ module ball_groove2(pitch, length, diameter, ball_radius, slices=200){ offset = length/slices; union(){ for (i = [0:slices]) { - assign (z = i*offset){ + let (z = i*offset){ translate(helix_curve(pitch, radius, z)) sphere(ball_radius, $fa=5, $fs=1); } } diff --git a/servos.scad b/servos.scad index b751835e..4970e764 100644 --- a/servos.scad +++ b/servos.scad @@ -9,6 +9,50 @@ use +/** + * TowerPro SG90 servo + * + * @param vector position The position vector + * @param vector rotation The rotation vector + * @param boolean screws If defined then "screws" will be added and when the module is differenced() from something if will have holes for the screws + * @param boolean cables If defined then "cables" output will be added and when the module is differenced() from something if will have holes for the cables output + * @param number axle_length If defined this will draw a red indicator for the main axle + */ +module towerprosg90(position=undef, rotation=undef, screws = 0, axle_length = 0, cables=0) +{ + translate(position) rotate(rotation) { + difference(){ + union() + { + translate([-5.9,-11.8/2,0]) cube([22.5,11.8,22.7]); + translate([0,0,22.7-0.1]){ + cylinder(d=11.8,h=4+0.1); + hull(){ + translate([8.8-5/2,0,0]) cylinder(d=5,h=4+0.1); + cylinder(d=5,h=4+0.1); + } + translate([0,0,4]) cylinder(d=4.6,h=3.2); + } + translate([-4.7-5.9,-11.8/2,15.9]) cube([22.5+4.7*2, 11.8, 2.5]); + } + //screw holes + translate([-2.3-5.9,0,15.9+1.25]) cylinder(d=2,h=5, center=true); + translate([-2.3-5.9-2,0,15.9+1.25]) cube([3,1.3,5], center=true); + translate([2.3+22.5-5.9,0,15.9+1.25]) cylinder(d=2,h=5, center=true); + translate([2.3+22.5-5.9+2,0,15.9+1.25]) cube([3,1.3,5], center=true); + } + if (axle_length > 0) { + color("red", 0.3) translate([0,0,29.9/2]) cylinder(r=1, h=29.9+axle_length, center=true); + } + if (cables > 0) color("red", 0.3) translate([-12.4,-1.8,4.5]) cube([10,3.6,1.2]); + if(screws > 0) color("red", 0.3) { + translate([-2.3-5.9,0,15.9+1.25]) cylinder(d=2,h=10, center=true); + translate([2.3+22.5-5.9,0,15.9+1.25]) cylinder(d=2,h=10, center=true); + } + } + +} + /** * Align DS420 digital servo * @@ -104,5 +148,53 @@ module alignds420(position, rotation, screws = 0, axle_lenght = 0) } } +/** + * Futaba S3003 servo + * + * @param vector position The position vector + * @param vector rotation The rotation vector + */ +module futabas3003(position, rotation) +{ + translate(position) + { + rotate(rotation) + { + union() + { + // Box and ears + translate([0,0,0]) + { + cube([20.1, 39.9, 36.1], false); + translate([1.1, -7.6, 26.6]) + { + difference() { + cube([18, 7.6, 2.5]); + translate([4, 3.5, 0]) cylinder(100, 2); + translate([14, 3.5, 0]) cylinder(100, 2); + } + } + + translate([1.1, 39.9, 26.6]) + { + difference() { + cube([18, 7.6, 2.5]); + translate([4, 4.5, 0]) cylinder(100, 2); + translate([14, 4.5, 0]) cylinder(100, 2); + } + } + } + + // Main axle + translate([10, 30, 36.1]) + { + cylinder(r=6, h=0.4, $fn=30); + cylinder(r=2.5, h=4.9, $fn=20); + } + } + } + } +} + // Tests: module test_alignds420(){alignds420(screws=1);} diff --git a/shapes.scad b/shapes.scad index 84b1810c..a769a39b 100644 --- a/shapes.scad +++ b/shapes.scad @@ -6,35 +6,50 @@ * License: LGPL 2.1 or later */ -// 2D Shapes -//ngon(sides, radius, center=false); - -// 3D Shapes -//box(width, height, depth); -//roundedBox(width, height, depth, factor); -//cone(height, radius); -//ellipticalCylinder(width, height, depth); -//ellipsoid(width, height); -//tube(height, radius, wall, center = false); -//tube2(height, ID, OD, center = false); -//ovalTube(width, height, depth, wall, center = false); -//hexagon(height, depth); -//octagon(height, depth); -//dodecagon(height, depth); -//hexagram(height, depth); -//rightTriangle(adjacent, opposite, depth); -//equiTriangle(side, depth); -//12ptStar(height, depth); +include + +/* +2D Shapes +ngon(sides, radius, center=false); + +3D Shapes +box(width, height, depth); +roundedBox(width, height, depth, radius); +cone(height, radius); +ellipticalCylinder(width, height, depth); +ellipsoid(width, height); +tube(height, radius, wall, center = false); +tube2(height, ID, OD, center = false); +ovalTube(width, height, depth, wall, center = false); +hexagon(height, depth); +octagon(height, depth); +dodecagon(height, depth); +hexagram(height, depth); + +rightTriangle(adjacent, opposite, depth); +equiTriangle(side, depth); +12ptStar(height, depth); +*/ //---------------------- +echo_deprecated_shapes_library(); + +module echo_deprecated_shapes_library() { + echo(" + DEPRECATED: 'shapes' library is now deprecated + please use 'regular_shapes' instead"); +} + // size is a vector [w, h, d] module box(width, height, depth) { + echo_deprecated_shapes_library(); cube([width, height, depth], true); } // size is a vector [w, h, d] module roundedBox(width, height, depth, radius) { + echo_deprecated_shapes_library(); size=[width, height, depth]; cube(size - [2*radius,0,0], true); cube(size - [0,2*radius,0], true); @@ -45,35 +60,43 @@ module roundedBox(width, height, depth, radius) { } module cone(height, radius, center = false) { + echo_deprecated_shapes_library(); cylinder(height, radius, 0, center); } module ellipticalCylinder(w,h, height, center = false) { + echo_deprecated_shapes_library(); scale([1, h/w, 1]) cylinder(h=height, r=w, center=center); } module ellipsoid(w, h, center = false) { + echo_deprecated_shapes_library(); scale([1, h/w, 1]) sphere(r=w/2, center=center); } // wall is wall thickness module tube(height, radius, wall, center = false) { + echo_deprecated_shapes_library(); + linear_extrude (height = height, center = center) { + difference() { + circle(r = radius); + circle(r = radius - wall); + } + } difference() { cylinder(h=height, r=radius, center=center); - cylinder(h=height, r=radius-wall, center=center); + translate([0,0,-epsilon]) + cylinder(h=height+2*epsilon, r=radius-wall, center=center); } } -// wall is wall thickness module tube2(height, ID, OD, center = false) { - difference() { - cylinder(h=height, r=OD/2, center=center); - cylinder(h=height, r=ID/2, center=center); - } + tube(height = height, center = center, radius = OD / 2, wall = (OD - ID)/2); } // wall is wall thickness module ovalTube(height, rx, ry, wall, center = false) { + echo_deprecated_shapes_library(); difference() { scale([1, ry/rx, 1]) cylinder(h=height, r=rx, center=center); scale([(rx-wall)/rx, (ry-wall)/rx, 1]) cylinder(h=height, r=rx, center=center); @@ -82,20 +105,26 @@ module ovalTube(height, rx, ry, wall, center = false) { // size is the XY plane size, height in Z module hexagon(size, height) { + echo_deprecated_shapes_library(); boxWidth = size/1.75; - for (r = [-60, 0, 60]) rotate([0,0,r]) cube([boxWidth, size, height], true); + for (r = [-60, 0, 60]) + rotate([0,0,r]) + cube([boxWidth, size, height], true); } // size is the XY plane size, height in Z module octagon(size, height) { + echo_deprecated_shapes_library(); intersection() { cube([size, size, height], true); - rotate([0,0,45]) cube([size, size, height], true); + rotate([0,0,45]) + cube([size, size, height], true); } } // size is the XY plane size, height in Z module dodecagon(size, height) { + echo_deprecated_shapes_library(); intersection() { hexagon(size, height); rotate([0,0,90]) hexagon(size, height); @@ -104,6 +133,7 @@ module dodecagon(size, height) { // size is the XY plane size, height in Z module hexagram(size, height) { + echo_deprecated_shapes_library(); boxWidth=size/1.75; for (v = [[0,1],[0,-1],[1,-1]]) { intersection() { @@ -114,15 +144,19 @@ module hexagram(size, height) { } module rightTriangle(adjacent, opposite, height) { + echo_deprecated_shapes_library(); difference() { - translate([-adjacent/2,opposite/2,0]) cube([adjacent, opposite, height], true); + translate([-adjacent/2,opposite/2,0]) + cube([adjacent, opposite, height], true); translate([-adjacent,0,0]) { - rotate([0,0,atan(opposite/adjacent)]) dislocateBox(adjacent*2, opposite, height+2); + rotate([0,0,atan(opposite/adjacent)]) + dislocateBox(adjacent*2, opposite, height+2); } } } module equiTriangle(side, height) { + echo_deprecated_shapes_library(); difference() { translate([-side/2,side/2,0]) cube([side, side, height], true); rotate([0,0,30]) dislocateBox(side*2, side, height); @@ -133,8 +167,9 @@ module equiTriangle(side, height) { } module 12ptStar(size, height) { + echo_deprecated_shapes_library(); starNum = 3; - starAngle = 360/starNum; + starAngle = 90/starNum; for (s = [1:starNum]) { rotate([0, 0, s*starAngle]) cube([size, size, height], true); } @@ -145,10 +180,3 @@ module 12ptStar(size, height) { module dislocateBox(w, h, d) { translate([0,0,-d/2]) cube([w,h,d]); } - -//----------------------- -// Tests -//module test2D_ellipse(){ellipse(10, 5);} -module test_ellipsoid(){ellipsoid(10, 5);} - -//module test2D_egg_outline(){egg_outline();} diff --git a/stepper.scad b/stepper.scad index c19d4afc..d1f2c660 100644 --- a/stepper.scad +++ b/stepper.scad @@ -259,20 +259,20 @@ module motor(model=Nema23, size=NemaMedium, dualAxis=false, pos=[0,0,0], orienta // Bolt holes color(stepperAluminum, $fs=holeRadius/8) { - translate([mid+holeDist,mid+holeDist,-1*mm]) cylinder(h=holeDepth+1*mm, r=holeRadius); - translate([mid-holeDist,mid+holeDist,-1*mm]) cylinder(h=holeDepth+1*mm, r=holeRadius); - translate([mid+holeDist,mid-holeDist,-1*mm]) cylinder(h=holeDepth+1*mm, r=holeRadius); - translate([mid-holeDist,mid-holeDist,-1*mm]) cylinder(h=holeDepth+1*mm, r=holeRadius); + translate([mid+holeDist,mid+holeDist,-1*mm]) cylinder(h=holeDepth+1*mm+extrSize, r=holeRadius); + translate([mid-holeDist,mid+holeDist,-1*mm]) cylinder(h=holeDepth+1*mm+extrSize, r=holeRadius); + translate([mid+holeDist,mid-holeDist,-1*mm]) cylinder(h=holeDepth+1*mm+extrSize, r=holeRadius); + translate([mid-holeDist,mid-holeDist,-1*mm]) cylinder(h=holeDepth+1*mm+extrSize, r=holeRadius); } // Grinded flat color(stepperAluminum) { difference() { - translate([-1*mm, -1*mm, -extrSize]) + translate([-1*mm, -1*mm, -1*mm]) cube(size=[side+2*mm, side+2*mm, extrSize + 1*mm]); - translate([side/2, side/2, -extrSize - 1*mm]) - cylinder(h=4*mm, r=extrRad); + translate([side/2, side/2, -1*mm]) + cylinder(h=extrSize + 1*mm, r=extrRad); } } diff --git a/teardrop.scad b/teardrop.scad index 274c162e..16b16cd4 100644 --- a/teardrop.scad +++ b/teardrop.scad @@ -23,7 +23,7 @@ This script generates a teardrop shape at the appropriate angle to prevent overh module teardrop(radius, length, angle) { rotate([0, angle, 0]) union() { linear_extrude(height = length, center = true, convexity = radius, twist = 0) - circle(r = radius, center = true, $fn = 30); + circle(r = radius, $fn = 30); linear_extrude(height = length, center = true, convexity = radius, twist = 0) projection(cut = false) rotate([0, -angle, 0]) translate([0, 0, radius * sin(45) * 1.5]) cylinder(h = radius * sin(45), r1 = radius * sin(45), r2 = 0, center = true, $fn = 30); } @@ -36,6 +36,18 @@ module teardrop(radius, length, angle) { */ } +/* + * Simple intersection method to implement a flat/truncated teardrop + */ +module flat_teardrop(radius, length, angle) { + intersection() { + rotate([0, angle, 0]) { + cube(size=[radius * 2, radius * 2, length], center=true); + } + teardrop(radius, length, angle); + } +} + module test_teardrop(){ translate([0, -15, 0]) teardrop(5, 20, 90); translate([0, 0, 0]) teardrop(5, 20, 60); diff --git a/test_docs.py b/test_docs.py index cbf9b11b..ff5c188e 100644 --- a/test_docs.py +++ b/test_docs.py @@ -4,15 +4,17 @@ dirpath = py.path.local("./") def pytest_generate_tests(metafunc): + names = [] if "filename" in metafunc.funcargnames: for fpath in dirpath.visit('*.scad'): - metafunc.addcall(id=fpath.basename, funcargs=dict(filename=fpath.basename)) + names.append(fpath.basename) for fpath in dirpath.visit('*.py'): name = fpath.basename if not (name.startswith('test_') or name.startswith('_')): - metafunc.addcall(id=fpath.basename, funcargs=dict(filename=fpath.basename)) + names.append(name) + metafunc.parametrize("filename", names) def test_README(filename): - README = dirpath.join('README').read() + README = dirpath.join('README.markdown').read() assert filename in README diff --git a/transformations.scad b/transformations.scad index 1522ea74..54ca755c 100644 --- a/transformations.scad +++ b/transformations.scad @@ -2,5 +2,5 @@ // © 2010 by Elmo Mäntynen module local_scale(v, reference=[0, 0, 0]) { - translate(-reference) scale(v) translate(reference) child(0); + translate(-reference) scale(v) translate(reference) children(); } diff --git a/triangles.scad b/triangles.scad index 357f7d44..f0e14ad7 100644 --- a/triangles.scad +++ b/triangles.scad @@ -11,14 +11,16 @@ /** * 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 + * @param number o_len Length of the opposite side + * @param number a_len Length of the adjacent side + * @param number depth How wide/deep the triangle is in the 3rd dimension + * @param boolean center Whether to center the triangle on the origin * @todo a better way ? */ -module triangle(o_len, a_len, depth) +module triangle(o_len, a_len, depth, center=false) { - linear_extrude(height=depth) + centroid = center ? [-a_len/3, -o_len/3, -depth/2] : [0, 0, 0]; + translate(centroid) linear_extrude(height=depth) { polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]); } @@ -27,16 +29,14 @@ module triangle(o_len, a_len, depth) /** * 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 + * @param number tan_angle Angle of adjacent to hypotenuse (ie tangent) + * @param number a_len Length of the adjacent side + * @param number depth How wide/deep the triangle is in the 3rd dimension + * @param boolean center Whether to center the triangle on the origin */ -module a_triangle(tan_angle, a_len, depth) +module a_triangle(tan_angle, a_len, depth, center=false) { - linear_extrude(height=depth) - { - polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]); - } + triangle(tan(tan_angle) * a_len, a_len, depth, center); } // Tests: diff --git a/utilities.scad b/utilities.scad index 01e45111..b37d1557 100644 --- a/utilities.scad +++ b/utilities.scad @@ -50,7 +50,7 @@ module fromTo(from=[0,0,0], to=[1*m,0,0], size=[1*cm, 1*cm], align=[CENTER, CENT rotate(angle) translate( [ -endCaps[0]*size[0] - endExtras[0], size[0]*(-0.5-align[0]), size[1]*(-0.5+align[1]) ] ) rotate(rotation) - scale([length, size[0], size[1]]) child(); + scale([length, size[0], size[1]]) children(); } }