User:LABoyd2/General to manual 151003
Introduction
editOpenSCAD is a 2D/3D and solid modeling program which is based on a Functional programming language used to create models that are previewed on the screen, and rendered into 3D mesh which allows the model to be exported in a variety of 2D/3D file formats.
A script in the OpenSCAD language is used to create 2D or 3D models. This script is a free format list of action statements. Actions include creating object using primitives, creating and assigning variables and others actions. All action statements end in a semicolon ';'. The language also include operators, or transformations, which can modify the location, color and other properties of objects. Operators do not have semicolons, but do use braces '{}' when there scope is intended to cover more than one action.
Comments
editComments are a way of leaving notes within the script, or code, (either to yourself or to future programmers) describing how the code works, or what it does. Comments are not evaluated by the compiler, and should not be used to describe self-evident code.
OpenSCAD uses C++-style comments:
// This is a comment myvar = 10; // The rest of the line is a comment /* Multi-line comments can span multiple lines. */
Values and Data Types
editA value in OpenSCAD is either a Number (like 42), a Boolean (like true), a String (like "foo"), a Vector (like [1,2,3]), or the Undefined value (undef). Values can be stored in variables, passed as function arguments, and returned as function results.
[OpenSCAD is a dynamically typed language with a fixed set of data types. There are no type names, and no user defined types. Functions are not values. In fact, variables and functions occupy disjoint namespaces.]
Numbers
editNumbers are the most important type of value in OpenSCAD, and they are written in the familiar decimal notation used in other languages. Eg, -1, 42, 0.5, 2.99792458e+8. [OpenSCAD does not support octal or hexadecimal notation for numbers.]
In additional to decimal numerals, the following names for special numbers are defined:
- PI
OpenSCAD has only a single kind of number, which is an IEEE floating point number. [OpenSCAD does not distinguish integers and floating point numbers as two different types, nor does it support complex numbers.] Because OpenSCAD uses the IEEE floating point standard, there are a few deviations from the behaviour of numbers in mathematics:
- The largest representable number is about 1e308. If a numeric result is too large, then the result can be infinity (printed as inf by echo).
- The smallest representable number is about -1e308. If a numeric result is too small, then the result can be -infinity (printed as -inf by echo).
- If a numeric result is invalid, then the result can be Not A Number (printed as nan by echo).
- If a non-zero numeric result is too close to zero to be representable, then the result will be -0 if the result is negative, otherwise it will be 0. Zero (0) and negative zero (-0) are treated as two distinct numbers by some of the math operations, and are printed differently by 'echo', although they compare equal.
Note that 'inf' and 'nan' are not supported as numeric constants by OpenSCAD, even though you can compute numbers that are printed this way by 'echo'. You can define variables with these values by using:
inf = 1e200 * 1e200; nan = 0 / 0; echo(inf,nan);
Note that 'nan' is the only OpenSCAD value that is not equal to any other value, including itself. Although you can test if a variable 'x' has the undefined value using 'x == undef', you can't use 'x == 0/0' to test if x is Not A Number. Instead, you must use 'x != x' to test if x is nan.
Boolean Values
editBoolean values are truth values. There are two Boolean values, named 'true' and 'false'. A Boolean value is passed as the 'center' argument to the cube() , cylinder() and other primitives, as the argument to 'if', and as the arguments to the logical operators '!' (not), '&&' (and), and '||' (or).
In all of these contexts, you can actually pass any type of value. Most values, when used in a Boolean context, are equivalent to 'true', but there are a few that are equivalent to 'false'. The values that count as false are:
- false
- 0 and -0
- ""
- []
- undef
Note that nan (Not A Number) counts as true.
Strings
editA string is a sequence of zero or more unicode characters. String values are used to specify file names when importing a file, and to display text for debugging purposes when using echo(). Strings can also be used with the new text() primitive added in 2015.03.
A string literal is written as a sequence of characters enclosed in quotation marks ("), like this: "", or "this is a string".
To include a " character in a string literal, use \". To include a \ character in a string literal, use \\. The following escape sequences beginning with \ can be used within string literals:
- \" → "
- \\ → \
- \t → tab
- \n → newline
- \r → carriage return
- \u03a9 → Ω
Note: This behavior is new since OpenSCAD-2011.04. You can upgrade old files using the following sed command: sed 's/\\/\\\\/' non-escaped.scad > escaped.scad
Example: echo("The quick brown fox \tjumps \"over\" the lazy dog.\rThe quick brown fox.\nThe \\lazy\\ dog."); result
ECHO: "The quick brown fox jumps "over" the lazy dog. The quick brown fox. The \lazy\ dog." old result ECHO: "The quick brown fox \tjumps \"over\" the lazy dog. The quick brown fox.\nThe \\lazy\\ dog."
Ranges
editRanges are used by for() loops. They have 2 varieties:
- [<start>:<end>]
- [<start>:<increment>:<end>]
Although enclosed in square brackets [] , they are not vectors. They use colons : for separators rather than commas.
r1 = [0:10]; r2 = [0.5:2.5:20];
The Undefined Value
editThe undefined value is a special value written as undef. It's the initial value of a variable that hasn't been assigned a value, and it is often returned as a result by functions or operations that are passed illegal arguments. Finally, 'undef' can be used as a null value, equivalent to 'null' or 'NULL' in other programming languages.
Note that numeric operations may also return nan to indicate an illegal argument. For example, 0/false is undef, but 0/0 is nan. Relational operators like < and > return false if passed illegal arguments.
Variables
editOpenSCAD variables are created by a statement with a name or identifier, assignment via an expression and a semicolon. The role of arrays, found in many imperative languages, is handled in OpenSCAD via vectors.
var = 25; xx = 1.25 * cos(50); y = 2*xx+var; logic = true; MyString = "This is a string"; a_vector = [1,2,3]; rr = a_vector[2]; // member of vector range1 = [-1.5:0.5:3]; // for() loop range xx = [0:5]; // alternate for() loop range
OpenSCAD is a Functional programming language, as such variables are bound to expressions and keep a single value during their entire lifetime due to the requirements of referential transparency. In imperative languages, such as C, the same behavior is seen as constants, which are typically contrasted with normal variables.
In other words OpenSCAD variables are more like constants, but with an important difference. If variables are assigned a value multiple times, only the last assigned value is used in all places in the code. See further discussion at Variables are set at compile-time, not run-time. This behavior is due to the need to supply variable input on the command line, via the use of -D variable=value option. OpenSCAD currently places that assignment at the end of the source code, and thus must allow a variables value to be changed for this purpose.
The variable retains its last assigned value at compile time, in line with Functional programming languages. Unlike Imperative languages, such a C, OpenSCAD is not an iterative language, as such the concept of x = x + 1 is not valid, get to understand this concept and you will understand the beauty of OpenSCAD.
- Before version 2015.03
It was not possible to do assignments at any place except the file top-level and module top-level. Inside an if/else or for loop, assign() was needed.
- Since version 2015.03
Variables can now be assigned in any scope. Note that assignments are only valid within the scope in which they are defined - you are still not allowed to leak values to an outer scope. See Scope of variables for more details.
a=0; if (a==0) { a=1; // before 2015.03 this line would generate a Compile Error // since 2015.03 no longer an error, but the value a=1 is confined to within the braces {} }
Undefined variable
editA non assigned variable has the special value undef. It could be tested in conditional expression, and returned by a function.
Example echo("Variable a is ", a); // Variable a is undef if (a==undef) { echo("Variable a is tested undefined"); // Variable a is tested undefined }
Scope of variables
editWhen operators such as translate() and color() need to encompass more than one action ( actions end in ; ), braces {} are needed to to group the actions, creating a new, inner scope. When there is only one semicolon, braces are usually optional.
Each pair of braces create a new scope inside the scope where they were used. Since 2015.03, new variables can be created within this new scope. New values can be given to variables which were created in an outer scope . These variables and their values are also available to further inner scopes created within this scope, but are not available to any thing outside this scope. Variables still have only the last value assigned within a scope.
// scope 1 a = 6; // create a echo(a,b); // 6, undef translate([5,0,0]){ // scope 1.1 a= 10; b= 16; // create b echo(a,b); // 100, 16 a=10; was overridden by later a=100; color("blue") { // scope 1.1.1 echo(a,b); // 100, 20 cube(); b=20; } // back to 1,1 echo(a,b); // 100, 16 a=100; // override a in 1.1 } // back to 1 echo(a,b); // 6, undef color("red"){ // scope 1.2 cube(); echo(a,b); // 6, undef } // back to 1 echo(a,b); // 6, undef //In this example, scopes 1 and 1.1 are outer scopes to 1.1.1 but 1.2 is not.
- Anonymous scopes are not considered scopes:
{ angle = 45; } rotate(angle) square(10);
For() loops are not an exception to the rule about variables having only one value within a scope. A copy of loop contents is created for each pass. Each pass is given its own scope, allowing any variables to have unique values for that pass. No, you still can't do a=a+1;
Variables are set at compile-time, not run-time
editBecause OpenSCAD calculates its variable values at compile-time, not run-time, the last variable assignment, within a scope will apply everywhere in that scope, or inner scopes thereof. It may be helpful to think of them as override-able constants rather than as variables.
// The value of 'a' reflects only the last set value a = 0; echo(a); // 5 a = 3; echo(a); // 5 a = 5;
While this appears to be counter-intuitive, it allows you to do some interesting things: For instance, if you set up your shared library files to have default values defined as variables at their root level, when you include that file in your own code, you can 're-define' or override those constants by simply assigning a new value to them.
Vectors
editA vector is a sequence of zero or more OpenSCAD values. Vectors are a collection (or list or table) of numeric or boolean values, variables, vectors, strings or any combination thereof. They can also be expressions which evaluate to one of these. Vectors handle the role of arrays found in many imperative languages. The information here also applies to lists and tables which use vectors for their data.
A vector has square brackets, [] enclosing zero or more items (elements or members), separated by commas. A vector can contain vectors, which contain vectors, etc.
- examples
[1,2,3] [a,5,b] [] [5.643] ["a","b","string"] [[1,r],[x,y,z,4,5]] [3, 5, [6,7], [[8,9],[10,[11,12],13], c, "string"] [4/3, 6*1.5, cos(60)]
use in OpenSCAD:
cube( [width,depth,height] ); // optional spaces shown for clarity translate( [x,y,z] ) polygon( [ [x0,y0], [x1,y1], [x2,y2] ] );
- creation
Vectors are created by writing the list of elements, separated by commas, and enclosed in square brackets. Variables are replaced by their values.
cube([10,15,20]); a1 = [1,2,3]; a2 = [4,5]; a3 = [6,7,8,9]; b = [a1,a2,a3]; // [ [1,2,3], [4,5], [5,7,8,9] ] note increased nesting depth
- elements within vectors
Elements within vectors are numbered from 0 to n-1 where n is the length returned by len(). Address elements within vectors with the following notation:
e[5] // element no 5 (sixth) at 1st nesting level e[5][2] // element 2 of element 5 2nd nesting level e[5][2][0] // element 0 of 2 of 5 3rd nesting level e[5][2][0][1] // element 1 of 0 of 2 of 5 4th nesting level
e = [ [1], [], [3,4,5], "string", "x", [[10,11],[12,13,14],[[15,16],[17]]] ]; // length 6 address length element e[0] 1 [1] e[1] 0 [] e[5] 3 [ [10,11], [12,13,14], [[15,16],[17]] ] e[5][1] 3 [ 12, 13, 14 ] e[5][2] 2 [ [15,16], [17] ] e[5][2][0] 2 [ 15, 16 ] e[5][2][0][1] undef 16 e[3] 6 "string" e[3 ][2] 1 "r" s = [2,0,5]; a = 2; e[s[a]] 3 [ [10,11], [12,13,14], [[15,16],[17]] ]
vector operators
editconcat
edit[Note: Requires version 2015.03 or later]
concat() combines the elements of 2 or more vectors into a single vector. No change in nesting level is made.
vector1 = [1,2,3]; vector2 = [4]; vector3 = [5,6]; new_vector = concat(vector1, vector2, vector3); // [1,2,3,4,5,6] string_vector = concat("abc","def"); // ["abc", "def"] one_string = str(string_vector[0],string_vector[1]); // "abcdef"
len
editlen() is a function which return the length of vectors or strings. Indices of elements are from [0] to [length-1].
- vector
- Returns the number of elements at this level.
- Single values, which are not vectors, return undef.
- string
- Returns the number of characters in string.
a = [1,2,3]; echo(len(a); // 3
See example elements with lengths
select
editselect() performs selection and reordering of elements into a new vector. NOTE: To use, copy this function into your script.
function select(source_vector,select_vector)= [ for (i = [0 : len(select_vector) - 1]) source_vector[select_vector[i]] ]; vector1 = [[0,0],[1,1],[2,2],[3,3],[4,4]]; selector1 = [4,0,3]; vector2 = select(vector1,selector1); // [[4, 4], [0, 0], [3, 3]] vector3 = select(vector1,[0,2,4]); // [[0, 0], [2, 2], [4, 4]]
Matrix
editA matrix is a vector of vectors.
Example which defines a 2D rotation matrix mr = [ [cos(angle), -sin(angle)], [sin(angle), cos(angle)] ];
Getting input
editNow we have variables, it would be nice to be able to get input into them instead of setting the values from code. There are a few functions to read data from DXF files, or you can set a variable with the -D switch on the command line.
Getting a point from a drawing
Getting a point is useful for reading an origin point in a 2D view in a technical drawing. The function dxf_cross will read the intersection of two lines on a layer you specify and return the intersection point. This means that the point must be given with two lines in the DXF file, and not a point entity.
OriginPoint = dxf_cross(file="drawing.dxf", layer="SCAD.Origin",
origin=[0, 0], scale=1);
Getting a dimension value
You can read dimensions from a technical drawing. This can be useful to read a rotation angle, an extrusion height, or spacing between parts. In the drawing, create a dimension that does not show the dimension value, but an identifier. To read the value, you specify this identifier from your program:
TotalWidth = dxf_dim(file="drawing.dxf", name="TotalWidth",
layer="SCAD.Origin", origin=[0, 0], scale=1);
For a nice example of both functions, see Example009 and the image on the homepage of OpenSCAD.