User:LABoyd2/function, module to manual 151016
Introduction
[edit | edit source]Users can extend the language by defining their own modules and functions. This allows grouping portions of script for easy reuse with different values. Well chosen names also help document your script.
OpenSCAD provides:
- functions which return values.
- modules which perform actions, but do not return values.
OpenSCAD calculates the value of variables at compile-time, not run-time. The last variable assignment within a scope will apply everywhere in that scope. It also applies to any inner scopes, or children, thereof. See Scope of variables for more details. It may be helpful to think of them as override-able constants rather than as variables.
For functions and modules OpenSCAD makes copies of pertinent portions of the script for each use. Each copy has its own scope, which contains fixed values for variables and expressions unique to that instance.
Functions
[edit | edit source]Functions operate on values to calculate and return new values.
- function definition
function name ( parameters ) = value ;
- name
- Your name for this module. A meaningful name is helpful later.
- parameters
- Zero or more arguments. Parameters can be assigned default values,to use in case they are omitted in the call. Parameter names are local and do not conflict with external variables of the same name.
- value
- an expression which calculates a value. This value can be a vector.
- name
- function use
- When used, functions are treated as values, and do not themselves end with a semi-colon ';'.
example 1 function func0() = 5; function func1(x=3) = 2*x+1; function func2() = [1,2,3,4]; function func3(y=7) = (y==7) ? 5 : 2 ; function func4(p0,p1,p2,p3) = [p0,p1,p2,p3]; echo (func0()); // 5 a = func1(); // 7 b= func1(5); // 5 echo (func2()); // [1, 2, 3, 4] echo( func3(2),func3()); // 2, 5 z= func4(func0(),func1(),func2(),func3()); // [5, 7, [1, 2, 3, 4], 5] translate([0,-4*func0(),0])cube([func0(),2*func0(),func0()]); // same as translate([0,-20,0])cube([5,10,5]);
example 2 creates for() range to give desired no of steps to cover range function steps( start, no_steps, end) = [start:(end-start)/(no_steps-1):end]; echo( steps(10,3,5)); // [10 : -2.5 : 5] for( i=steps(10,3,5))echo(i); // 10 7.5 5 echo(steps(10,3,15)); //[10 : 2.5 : 15] for( i=steps(10,3,15))echo(i); // 10 12.5 15 echo(steps(0,5,5)); // [0 : 1.25 : 5] for( i=steps(0,5,5))echo(i); // 0 1.25 2.5 3.75 5
example 3 rectangle with top pushed over, keeping same y function rhomboid(x=1,y=1,angle=90) = [[0,0],[x,0] ,[x+x*cos(angle)/sin(angle),y] ,[x*cos(angle)/sin(angle),y]]; echo (v1); v1 = rhomboid(10,10,35); // [[0, 0], // [10, 0], // [24.2815, 10], // [14.2815, 10]] polygon(v1); polygon(rhomboid(10,10,35)); // alternate
performing the same action with a module module parallelogram(x=1,y=1,angle=90) {polygon([[0,0],[x,0] ,[x+x*cos(angle)/sin(angle),y] ,[x*cos(angle)/sin(angle),y]]);}; parallelogram(10,10,35);
Recursive functions
[edit | edit source]Recursive function calls are supported. Using the Conditional Operator "... ? ... : ... ", it is possible to ensure the recursion is terminated.
Note: There is a built-in recursion limit to prevent an application crash. If the limit is hit, the result of the function call is undef.
// recursion - find the sum of the values in a vector (array) // from the start (or s'th element) to the i'th element - remember elements are zero based function sumv(v,i,s=0) = (i==s ? v[i] : v[i] + sumv(v,i-1,s)); vec=[ 10, 20, 30, 40 ]; echo("sum vec=", sumv(vec,2,1)); // is 20+30=50
Modules
[edit | edit source]Once defined, modules are temporarily added to the language as another action.
- module definition
module name ( parameters ) { actions }
- name
- Your name for this module. Try to pick something meaningful.
- parameters
- Zero or more arguments. Parameters may be assigned default values,to use in case they are omitted in the call. Parameter names are local and do not conflict with external variables of the same name.
- name
- actions
- Nearly any statement valid outside a module can be included within a module.
- actions
- module use
In use, modules are actions ending with a semi-colon ';'.
name ( parameter values );
Variables can be assigned, but their scope is limited to within each individual use of the module. There is no mechanism in OpenSCAD to return values to the outside. See Scope of variables for more details.
example 1 translate([-30,-20,0]) ShowColorBars(Expense); ColorBreak=[[0,""], [20,"lime"], // upper limit of color range [40,"greenyellow"], [60,"yellow"], [75,"LightCoral"], [200,"red"]]; Expense=[16,20,25,85,52,63,45]; module ColorBar(value,period,range){ // 1 color on 1 bar RangeHi = ColorBreak[range][0]; RangeLo = ColorBreak[range-1][0]; color( ColorBreak[range][1] ) translate([10*period,0,RangeLo]) if (value > RangeHi) cube([5,2,RangeHi-RangeLo]); else if (value > RangeLo) cube([5,2,value-RangeLo]); } module ShowColorBars(values){ for (month = [0:len(values)-1], range = [1:len(ColorBreak)-1]) ColorBar(values[month],month,range); }
example 2
module house(roof="flat",paint=[1,0,0]) {
color(paint)
if(roof=="flat") { translate([0,-1,0]) cube(); }
else if(roof=="pitched") {
rotate([90,0,0]) linear_extrude(height=1)
polygon(points=[[0,0],[0,1],[0.5,1.5],[1,1],[1,0]]); }
else if(roof=="domical") {
translate([0,-1,0]){
translate([0.5,0.5,1]) sphere(r=0.5,$fn=20); cube(); }
} }
house();
translate([2,0,0]) house("pitched");
translate([4,0,0]) house("domical",[0,1,0]);
translate([6,0,0]) house(roof="pitched",paint=[0,0,1]);
translate([0,3,0]) house(paint=[0,0,0],roof="pitched");
translate([2,3,0]) house(roof="domical");
translate([4,3,0]) house(paint=[0,0.5,0.5]);
example 3 element_data = [[0,"","",0], // must be in order [1,"Hydrogen","H",1.008], // indexed via atomic number [2,"Helium", "He",4.003] // redundant atomic number to preserve your sanity later ]; Hydrogen = 1; Helium = 2; module coaster(atomic_number){ element = element_data[atomic_number][0]; symbol = element_data[atomic_number][1]; atomic_mass= element_data[atomic_number][2]; //rest of script }
children
[edit | edit source]The child nodes of the module instantiation can be accessed using the children() statement within the module. The number of module children can be accessed using the $children variable.
Parameters
- empty
- select all the children
- index
- integer. select one child, at index value. Index start at 0 and should be less than or equal to $children-1.
- vector
- vector of integer. select children with index in vector. Index should be between 0 and $children-1.
- range
- [<start>:<end>] or [<start>:<increment>:<end>]. select children between <start> to <end>, incremented by <increment> (default 1).
Deprecated child() module
Up to release 2013.06 the now deprecated child()
module was used instead. This can be translated to the new children() according to the table:
up to 2013.06 | 2014.03 and later |
---|---|
child() | children(0) |
child(x) | children(x) |
for (a = [0:$children-1]) child(a) | children([0:$children-1]) |
Examples
Transfer all children to another module:
// rotate and translate to another center point:
module rz(angle, center=undef) {
translate(center)
rotate(angle)
translate(-center)
children();
}
rz(35, [500,0]) sphere(30);
Use the first child, multiple time:
module lineup(num, space) {
for (i = [0 : num-1])
translate([ space*i, 0, 0 ]) children(0);
}
lineup(5, 65) sphere(30);
If you need to make your module iterate over all children you will need to make use of the $children variable, e.g.:
module elongate() {
for (i = [0 : $children-1])
scale([10 , 1, 1 ]) children(i);
}
elongate() { sphere(30); cube([10,10,10]); cylinder(r=10,h=50); }