User:LABoyd2/General from manual 151002

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Introduction[edit | edit source]

OpenSCAD is a 2D/3D and solid modeling program which is based on a Functional programming language used to create models that are later previewed on the screen, and rendered into 3D mesh which allows the model to be exported to a variety of 2D/3D file formats.

Comments[edit | edit source]

Comments are a way of leaving notes within the 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[edit | edit source]

A 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[edit | edit source]

Numbers 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[edit | edit source]

Boolean 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' and 'cylinder' 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[edit | edit source]

A 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

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

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.");

Output:
ECHO: "The quick brown fox jumps "over" the lazy dog.
The quick brown fox.
The \lazy\ dog."

Output: in OpenSCAD version 2013.02.28
ECHO: "The quick brown fox \tjumps \"over\" the lazy dog.
The quick brown fox.\nThe \\lazy\\ dog."

Vectors[edit | edit source]

A 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. 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. The information here also applies to lists and tables which use vectors for their data.


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
example elements with lengths
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[edit | edit source]
concat[edit | edit source]

[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[edit | edit source]

len() 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.


See example elements with lengths

select[edit | edit source]

select() 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[edit | edit source]

A matrix is a vector of vectors.

Example

mr = [
      [cos(angle), -sin(angle)],
      [sin(angle),  cos(angle)]
     ];

Output Define a 2D rotation matrix.

Ranges[edit | edit source]

Ranges define a series of numerical values.

Range: [<start>:<end>] - iterate from start to end inclusive with a fixed increment of 1. Both start and end can be fractions. It also works if end is smaller than start but as of Version 2014.03 this usage is deprecated and will produce a warning message.

Range: [<start>:<increment>:<end>] - iterate from start to end with the given increment. The increment can be a fraction.
It's valid to use a negative increment, in this case end must be smaller than (or equal to) start.

Warning: If the increment is not an even divider of <end>-<start>, the iterator value for the last iteration will be <end>-(<end>-<start> mod <increment>).

Note for Version < 2014.03: The increment is given as an absolute value and cannot be negative. If <end> is smaller than <start> the increment should remain unchanged.

Example

r = [0.5 : 2.5];
for (n = r) echo(n);

Output
ECHO: 0.5
ECHO: 1.5
ECHO: 2.5

The Undefined Value[edit | edit source]

The 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[edit | edit source]

Variables in OpenSCAD are simply an identifier followed by an assignment via an expression (i.e. identifier = expression).

Example:

myvar = 5 + 4;

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' below. 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.

Currently it's not possible to do assignments at any place (the only places are file top-level and module top-level). So it is invalid inside an if/else  or for  loop, if you need it inside the for  loop you need to use the assign() module.

Update: [Note: Requires version 2015.03]

Since OpenSCAD-2015.03, the restriction on where assignments can be made have been lifted: Variables can now be assigned in any scope. Note that assignments are only valid in the scope in which they are defined - you are still not allowed to leak values to an outer scope.

for (i = [10:50]) {
    angle = i*360/20;
    distance = i*10;
    r = i*2;
    rotate(angle, [1, 0, 0])
    translate([0, distance, 0])
    sphere(r = r);
}

Note! Anonymous scopes are not considered scopes:

{
    angle = 45;
}
rotate(angle) square(10);

Undefined variable[edit | edit source]

A 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); // output 'Variable a is undef'
if (a==undef) {
   echo("Variable a is tested undefined");
}

Output Variable a is undef Variable a is tested undefined

Variables are set at compile-time, not run-time[edit | edit source]

Because OpenSCAD calculates its variable values at compile-time, not run-time, the last variable assignment will apply everywhere the variable is used (with some exceptions, mentioned below). It may be helpful to think of them as override-able constants rather than as variables.

Example:

 // The value of 'a' reflects only the last set value
    a = 0;
    echo(a);

    a = 5;
    echo(a);

Output

ECHO: 5
ECHO: 5

This also means that you can not reassign a variable inside an if  block:

Example:

a=0;
if (a==0) 
  {
  a=1; // <- this line will generate an error.
  }

Output Compile Error

Exception #1[edit | edit source]

This behavior is scoped to either the root or to a specific call to a module, meaning you can re-define a variable within a module without affecting its value outside of it. However, all instances within that call will behave as described above with the last-set value being used throughout.

Example:

p = 4;
test(5);
echo(p);
/*
 * we start with p = 4.  We step to the next command 'test(5)', which calls the 'test' module.
 * The 'test' module calculates two values for 'p', but the program will ONLY display the final value. 
 * There will be two executions of echo(p) inside 'test' module, but BOTH will display '9' because it is the FINAL
 * calculated value inside the module. ECHO: 9   ECHO: 9
 *
 * Even though the 'test' module calculated value changes for 'p', those values remained inside the module.  
 * Those values did not continue outside the 'test' module.  The program has now finished 'test(5)' and moves to the next command 'echo(p)'.
 * The call 'echo(p)' would normally display the original value of 'p'=4.  
 * Remember that the program will only show the FINAL values.  It is the next set of commands that produce the final values....which is ECHO: 6
 */
p = 6;
test(8);
echo(p);
/*
 * We now see 'p=6', which is a change from earlier.  We step to the next command 'test(8)', which calls the 'test' module.
 * Again, the 'test' module calculates two values for 'p', but the program will ONLY display the final value.
 * There will be two executions of echo(p) inside 'test' module, but BOTH will display '12' because it is the FINAL
 * compiled value that was calculated inside the module.  
 * Therefore, both echo(p) statements will show the final value of '12' ;
 * Remember that the 'test' module final values for 'p' will remain inside the module.  They do not continue outside the 'test' module.
 * ECHO:12   ECHO:  12
 *
 * The program has now finished 'test(8)' and moves to the next command 'echo(p)'.
 * Remember at compile that the pgm will show the FINAL values.  The first value of 'echo(p)' would have showed a value of '4'...
 * However, at compile time the final value of 'echo(p)' was actually '6'.  Therefore, '6' will be shown on both echo(p) statements.
 * ECHO 6
 */

module test(q)
{
    p = 2 + q;
    echo(p);

    p = 4 + q;
    echo(p);
}

Output

ECHO: 9
ECHO: 9
ECHO: 6
ECHO: 12
ECHO: 12
ECHO: 6

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.

Exception #2[edit | edit source]

See the assign, which provides for a more tightly scoped changing of values.

Getting input[edit | edit source]

Now 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.