Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
372 lines (297 sloc) 9.69 KB
//---------------------------------------------------------------
//-- 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();
*/
You can’t perform that action at this time.