diff --git a/assembly/attach.scad b/assembly/attach.scad new file mode 100644 index 00000000..ce014f8f --- /dev/null +++ b/assembly/attach.scad @@ -0,0 +1,150 @@ +//--------------------------------------------------------------- +//-- Openscad Attachment library +//-- Attach parts easily. Make your designs more reusable and clean +//--------------------------------------------------------------- +//-- This is a component of the obiscad opescad tools by Obijuan +//-- (C) Juan Gonzalez-Gomez (Obijuan) +//-- Sep-2012 +//--------------------------------------------------------------- +//-- Released under the GPL license +//--------------------------------------------------------------- + +use + +//-------------------------------------------------------------------- +//-- Draw a connector +//-- A connector is defined a 3-tuple that consist of a point +//--- (the attachment point), and axis (the attachment axis) and +//--- an angle the connected part should be rotate around the +//-- attachment axis +//-- +//--- Input parameters: +//-- +//-- Connector c = [p , v, ang] where: +//-- +//-- p : The attachment point +//-- v : The attachment axis +//-- ang : the angle +//-------------------------------------------------------------------- +module connector(c) +{ + //-- Get the three components from the connector + p = c[0]; + v = c[1]; + ang = c[2]; + + //-- Draw the attachment poing + color("Gray") point(p); + + //-- Draw the attachment axis vector (with a mark) + translate(p) + rotate(a=ang, v=v) + color("Gray") vector(unitv(v)*6, l_arrow=2, mark=true); +} + + +//------------------------------------------------------------------------- +//-- ATTACH OPERATOR +//-- This operator applies the necesary transformations to the +//-- child (attachable part) so that it is attached to the main part +//-- +//-- Parameters +//-- a -> Connector of the main part +//-- b -> Connector of the attachable part +//------------------------------------------------------------------------- +module attach(a,b) +{ + //-- Get the data from the connectors + pos1 = a[0]; //-- Attachment point. Main part + v = a[1]; //-- Attachment axis. Main part + roll = a[2]; //-- Rolling angle + + pos2 = b[0]; //-- Attachment point. Attachable part + vref = b[1]; //-- Atachment axis. Attachable part + //-- The rolling angle of the attachable part is not used + + //-------- Calculations for the "orientate operator"------ + //-- Calculate the rotation axis + cref = cross(vref,v); + raxis = norm(cref) == 0 ? ortho2(vref) : cref; + + //-- Calculate the angle between the vectors + ang = anglev(vref,v); + //--------------------------------------------------------.- + //-- Apply the transformations to the child --------------------------- + + //-- Place the attachable part on the main part attachment point + translate(pos1) + //-- Orientate operator. Apply the orientation so that + //-- both attachment axis are paralell. Also apply the roll angle + rotate(a=roll, v=v) rotate(a=ang, v=raxis) + //-- Attachable part to the origin + translate(-pos2) + children([0:$children-1]); +} + + +//-------------------------------------------------------------------- +//--- An example of the attach operator +//--- +//--- There are two parts: the main body and an arm +//--- They both are cubes (for simplicity) +//--- +//-- In the main body there are 2 connectors defined, so that +//-- the arm can be attached to any of them (or both if you like) +//------------------------------------------------------------------ + +//-- In the debug mode the connectors and additional information +//-- are shown +debug=true; + +//-- Define the Main part: A cube +//-- Two attachment points are defined: one on the top, another in the +//--- left side +size = [10,10,10]; + +//-- Connectors defined: + +//-- Att. point Att. Axis Roll +c1 = [ [0,0,size[2]/2], [0,0,1], 20]; //-- Connector on the top +c2 = [ [-size[0]/2,0,0], [-1,0,0], 90]; //-- Connector on the left +c3 = [ [0,0,-size[0]/2], [0,0,-1], 90]; //-- Connector on the bottom, degenerate case ! + + +//-- Draw the main part along with the connectors (for debugging) +cube(size,center=true); + +//-- In debug mode: Draw the main part connectors! +if (debug) { + connector(c1); + connector(c2); + connector(c3); +} + +//-- Define the Attachable part. It is another cube, with one connector +asize = [5,20,3]; +a = [ [0,asize[1]/2-3,-asize[2]/2], [0,0,1], 0 ]; + + +//-- Do the attach! +//-- Just change c1 by c2 to attach the part to the other +//-- connector. Super-easy!! :-) +//-- Modify the c1 and c2 roll angle for rotating the attachable +//-- part to the desired orientation +attach(c1,a) + //-- This is the attachable part! + union() { + cube(asize,center=true); //-- The part + + //-- In debug mode show additional info: + if (debug) { + frame(l=10); //-- The part frame of reference. + connector(a); //-- Show the part connector + } + }; + + + + + + diff --git a/assembly/vector.scad b/assembly/vector.scad new file mode 100644 index 00000000..ce8a1bce --- /dev/null +++ b/assembly/vector.scad @@ -0,0 +1,371 @@ +//--------------------------------------------------------------- +//-- Openscad vector library +//-- This is a component of the obiscad opescad tools by Obijuan +//-- (C) Juan Gonzalez-Gomez (Obijuan) +//-- Sep-2012 +//--------------------------------------------------------------- +//-- Released under the GPL license +//--------------------------------------------------------------- + +obiscad_drawing_resolution = 6; + +//---------------------------------------- +//-- FUNCTIONS FOR WORKING WITH VECTORS +//---------------------------------------- + +//-- Calculate the module of a vector +function mod(v) = (sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])); + +//-- Calculate the cros product of two vectors +function cross(u,v) = [ + u[1]*v[2] - v[1]*u[2], + -(u[0]*v[2] - v[0]*u[2]) , + u[0]*v[1] - v[0]*u[1]]; + +//-- Calculate the dot product of two vectors +function dot(u,v) = u[0]*v[0]+u[1]*v[1]+u[2]*v[2]; + +//-- Return the unit vector of a vector +function unitv(v) = v/mod(v); + +//-- Return the angle between two vectores +function anglev(u,v) = acos( dot(u,v) / (mod(u)*mod(v)) ); + +//-- Return an arbitrary unitary vector othogonal to v +function orthounit2(v) = (v.x == 0 && v.y == 0 && v.z ==0 ) ? undef : (v.x == 0 && v.y == 0) ? [1,0,0] : let (r=norm([v.x, v.y, 0])) [v.y/r, -v.x/r, 0]; + +//-- Return an arbitrary vector othogonal to v +function ortho2(v) = (v.x == 0 && v.y == 0 && v.z== 0) ? undef : (v.x == 0 && v.y == 0) ? [1,0,0] : (v.y == 0) ? [1,0,0] : [1, -v.x/v.y, 0]; + +//---------------------------------------------------------- +//-- Draw a point in the position given by the vector p +//---------------------------------------------------------- +module point(p) +{ + translate(p) + sphere(r=0.7,$fn=obiscad_drawing_resolution); +} + +//------------------------------------------------------------------ +//-- Draw a vector poiting to the z axis +//-- This is an auxiliary module for implementing the vector module +//-- +//-- Parameters: +//-- l: total vector length (line + arrow) +//-- l_arrow: Vector arrow length +//-- mark: If true, a mark is draw in the vector head, for having +//-- a visual reference of the rolling angle +//------------------------------------------------------------------ +module vectorz(l=10, l_arrow=4, mark=false) +{ + //-- vector body length (not including the arrow) + lb = l - l_arrow; + + //-- The vector is locatead at 0,0,0 + translate([0,0,lb/2]) + union() { + + //-- Draw the arrow + translate([0,0,lb/2]) + cylinder(r1=2/2, r2=0.2, h=l_arrow, $fn=obiscad_drawing_resolution); + + //-- Draw the mark + if (mark) { + translate([0,0,lb/2+l_arrow/2]) + translate([1,0,0]) + cube([2,0.3,l_arrow*0.8],center=true); + } + + //-- Draw the body + cylinder(r=1/2, h=lb, center=true, $fn=obiscad_drawing_resolution); + } + + //-- Draw a sphere in the vector base + sphere(r=1/2, $fn=obiscad_drawing_resolution); +} + +//----------------------------------------------------------------- +//-- ORIENTATE OPERATOR +//-- +//-- Orientate an object to the direction given by the vector v +//-- Parameters: +//-- v : Target orientation +//-- vref: Vector reference. It is the vector of the local frame +//-- of the object that want to be poiting in the direction +//-- of v +//-- roll: Rotation of the object around the v axis +//------------------------------------------------------------------- +module orientate(v,vref=[0,0,1], roll=0) +{ + //-- Calculate the rotation axis + cref = cross(vref, v); + raxis = mod(cref) == 0 ? [1,0,0] : cref; + + //-- Calculate the angle between the vectors + ang = anglev(vref,v); + + //-- Rotate the child! + rotate(a=roll, v=v) + rotate(a=ang, v=raxis) + child(0); +} + +//--------------------------------------------------------------------------- +//-- Draw a vector +//-- +//-- There are two modes of drawing the vector +//-- * Mode 1: Given by a cartesian point(x,y,z). A vector from the origin +//-- to the end (x,y,z) is drawn. The l parameter (length) must +//-- be 0 (l=0) +//-- * Mode 2: Give by direction and length +//-- A vector of length l pointing to the direction given by +//-- v is drawn +//--------------------------------------------------------------------------- +//-- Parameters: +//-- v: Vector cartesian coordinates +//-- l: total vector length (line + arrow) +//-- l_arrow: Vector arrow length +// mark: If true, a mark is draw in the vector head, for having +//-- a visual reference of the rolling angle +//--------------------------------------------------------------------------- +module vector(v,l=0, l_arrow=4, mark=false) +{ + //-- Get the vector length from the coordinates + mod = mod(v); + + //-- The vector is very easy implemented by means of the orientate + //-- operator: + //-- orientate(v) vectorz(l=mod, l_arrow=l_arrow) + //-- BUT... in OPENSCAD 2012.02.22 the recursion does not + //-- not work, so that if the user use the orientate operator + //-- on a vector, openscad will ignore it.. + //-- The solution at the moment (I hope the openscad developers + //-- implement the recursion in the near future...) + //-- is to repite the orientate operation in this module + + //---- SAME CALCULATIONS THAN THE ORIENTATE OPERATOR! + //-- Calculate the rotation axis + + vref = [0,0,1]; + cref = cross(vref, v); + raxis = mod(cref) == 0 ? [1,0,0] : cref; + + //-- Calculate the angle between the vectors + ang = anglev(vref,v); + + //-- orientate the vector + //-- Draw the vector. The vector length is given either + //--- by the mod variable (when l=0) or by l (when l!=0) + if (l==0) + rotate(a=ang, v=raxis) + vectorz(l=mod, l_arrow=l_arrow, mark=mark); + else + rotate(a=ang, v=raxis) + vectorz(l=l, l_arrow=l_arrow, mark=mark); + +} + +//---------------------------------------------------- +//-- Draw a Frame of reference +//-- Parameters: +//-- l: length of the Unit vectors +//----------------------------------------------------- +module frame(l=10, l_arrow=4) +{ + + //-- Z unit vector + color("Blue") + vector([0,0,l], l_arrow=l_arrow); + + //-- X unit vector + color("Red") + vector([l,0,0], l_arrow=l_arrow ); + + //-- Y unit vector + color("Green") + vector([0,l,0],l_arrow=l_arrow); + + //-- Origin + color("Gray") + sphere(r=1, $fn=obiscad_drawing_resolution); +} + +//-------------------------------------------------- +//-- Modules for testings and examples +//-- Testing that the vector library is working ok +//-------------------------------------------------- + +//-- 22 vectors in total are drawn, poiting to different directions +module Test_vectors1() +{ + + a = 20; + k = 1; + + //-- Add a frame of reference (in the origin) + frame(l=a); + + //-- Negative vectors, pointing towards the three axis: -x, -y, -z + color("Red") vector([-a, 0, 0]); + color("Green") vector([0, -a, 0]); + color("Blue") vector([0, 0, -a]); + + //-- It is *not* has been implemented using a for loop on purpose + //-- This way, individual vectors can be commented out or highlighted + + //-- vectors with positive z + vector([a, a, a*k]); + vector([0, a, a*k]); + vector([-a, a, a*k]); + vector([-a, 0, a*k]); + + vector([-a, -a, a*k]); + vector([0, -a, a*k]); + vector([a, -a, a*k]); + vector([a, 0, a*k]); + + + //-- Vectors with negative z + vector([a, a, -a*k]); + vector([0, a, -a*k]); + vector([-a, a, -a*k]); + vector([-a, 0, -a*k]); + + vector([-a, -a, -a*k]); + vector([0, -a, -a*k]); + vector([a, -a, -a*k]); + vector([a, 0, -a*k]); +} + +//--- Another test... +module Test_vectors2() +{ + + //-- Add the vector into the vector table + //-- This vectors are taken as directions + //-- All the vectors will be drawn with the same length (l) + vector_table = [ + [1, 1, 1], + [0, 1, 1], + [-1, 1, 1], + [-1, 0, 1], + [-1, -1, 1], + [0, -1, 1], + [1, -1, 1], + [1, 0, 1], + [0, 0, -1], // degenerate case + [1, 1, -1], + [0, 1, -1], + [-1, 1, -1], + [-1, 0, -1], + [-1, -1, -1], + [0, -1, -1], + [1, -1, -1], + [1, 0, -1], + ]; + + //-- Vector length + l=20; + + frame(l=10); + + //-- Draw all the vector given in the table + //-- The vectors point to the direction given in the table + //-- They all are drawn with a length equal to l + for (v=vector_table) { + //-- Vector given by direction and length + vector(v,l=l); + } +} + + +//-- Test the cross product and the angle +//-- between vectors +module Test_vector3() +{ + //-- Start with 2 unit vectors + v=unitv([1,1,1]); + u=unitv([0,1,0]); + + //-- Draw the vector in different colors + //-- Increase the length for drawing + color("Red") vector(v*20); + color("blue") vector(u*20); + + //-- Get the cross product + w = cross(v,u); + vector(w*20); + + //-- The cross product is NOT conmutative... + //-- change the order of v and u + w2 = cross(u,v); + vector(w2*20); + + //-- w should be perpendicular to v and u + //-- Calculate the angles between them: + echo("U , V: ", anglev(u,v)); + echo("W , U: ", anglev(w,u)); + echo("W , V: ", anglev(w,v)); + +} + +//-- Test the orientate operator +module Test_vector4() +{ + o = [10,10,10]; + v = [-10,10,10]; + + color("Red") vector(o); + color("Blue") vector(v); + + //-- Orientate the vector o in the direction of v + orientate(v,o) + vector(o); + + //-- Inverse operation: orientate the v vector in the direction + //-- of o + orientate(o,v) + vector(v); + + //-- Example of orientation of a cube + orientate(o,vref=[10,-2,5],roll=0) + cube([10,2,5],center=true); + + vector([10,-2,5]); + +} + +//-- Test the degenerate case ie. the vectors are (anti)collinear +module Test_vector5() +{ + o = [0,0,10]; + v = [0,0,-10]; + + color("Red") vector(o); + color("Blue") vector(v); + + //-- Orientate the vector o in the direction of v + orientate(v,o) + vector(o); + + //-- Inverse operation: orientate the v vector in the direction + //-- of o + orientate(o,v) + vector(v); +} + +//-------- Perform tests...... + +Test_vector4(); + + +/* + +Test_vectors1(); + + +translate([60,0,0]) + Test_vectors2(); +*/ + +