OpenSCAD User Manual/Other Language Features

Echo As A Module

The echo() module prints its given arguments to the compilation window (aka Console), which is useful for debugging code. Any number of arguments may be given, may be of any type, and are output separated by a comma and a space. Strings are enclosed in double quotes ('"') and vectors by square brackets ("[]").

The String Function str() may be used to prepackage a number of values into a string so that values will NOT be separated by a blank. Str() also does not add quotes around strings and does not separate elements with ", ".

Numeric values are rounded off to 5 significant digits. This means that fractions smaller than 0.000001 are not displayed and that very large values are shown in scientific notation with only the first 6 digits shown.

Arguments to Echo() may be given individual labels by using the form: 'variable=variable' as will be seem in this example.

Usage examples:

 my_h=50;
 my_r=100;
 echo("a cylinder with height : ", my_h, " and radius : ", my_r);
 echo( high=my_h, rad=my_r); // will display as high=<num> rad=<num>
 cylinder(h=my_h, r=my_r);

small Decimal Fractions are Rounded Off

This example shows that the fractional part of 'b' may appear to be rounded off when printed by echo(), but is still present for use in calculations and logical comparisons:

a=1.0;
b=1.000002;
echo(a); // shows as '1'
echo(b); // also shows as '1'

if(a==b){
    echo ("a==b");
}else if(a>b){
    echo ("a>b");
}else if(a<b){
    echo ("a<b"); // will be the result
}else{
    echo ("???");
}

Shows in the Console as

ECHO: 1
ECHO: 1
ECHO: "a<b"

Very Small and Large Numbers

Echo shows very small decimal fractions, and very large values, in C Language style scientific notation.

c=1000002;
d=0.000002;
echo(c); //1e+06
echo(d); //2e-06

The syntax of values shown in this form is described in the section on []

Formatting Output

The only control over text output by echo() is the use of '\n', '\t', and '\r' characters. These are, of course, the Escape Characters for Newline, Tab, and Return and they may be used as part of a string to, respectively, begin a new line, insert blanks to the next tab stop (every 4 spaces), and return to the beginning of the line.

HTML output is not supported in development versions, starting 2025.

Echo As A Function

[Note: Requires version 2019.05]

A call to Echo() can be made as part of an expression to print information to the console just before the expression is evaluated. This means that in when the expression includes a recursive call to a function or module that echo's arguments are shown before the recursion. To be able to see values after the expression one may use a helper function as will be shown by "result()" in the second example following.

Example

 a = 3; b = 5;
 // echo() prints values before evaluating the expression
 r1 = echo(a, b) a * b; // ECHO: 3, 5
 
 // like a let(), a call to echo() may be included as part of an expression
 r2 = let(r = 2 * a * b) echo(r) r; // ECHO: 30
 
 // use echo statement for showing results 
 echo(r1, r2); // ECHO: 15, 30

A more complex example shows how echo() can be used in both the descending and ascending paths of a recursive function.

Example printing both input values and result of recursive sum()

 v = [4, 7, 9, 12];
 function result(x) = echo(result = x) x;
 function sum(x, i = 0) = echo(str("x[", i, "]=", x[i])) result(len(x) > i ? x[i] + sum(x, i + 1) : 0);
 echo("sum(v) = ", sum(v));
 
 // ECHO: "x[0]=4"
 // ECHO: "x[1]=7"
 // ECHO: "x[2]=9"
 // ECHO: "x[3]=12"
 // ECHO: "x[4]=undef"
 // ECHO: result = 0
 // ECHO: result = 12
 // ECHO: result = 21
 // ECHO: result = 28
 // ECHO: result = 32
 // ECHO: "sum(v) = ", 32

Render Operation

This operation causes meshes to be generated for surfaces in preview mode. This improves the rendered images when the normal preview renderer produces artifacts or misses parts of the image around complex bits of geometry. An issue on GitHub discusses some of these issues, and an FAQ covers more: OpenSCAD User Manual/FAQ#Why are some parts (e.g. holes) of the model not rendered correctly?

function definition
render( convexity = 1 )
convexity
an indication to the preview renderer that objects in view are not simple. See the section on the Convexity Parameter
example in preview
render() effects show edges

Usage examples:

 render( convexity = 2 ) 
    difference()
        { // stretch a cube vertically
        cube([20, 20, 150], center = true);
        // make a notch in one corner 
        translate([-10, -10, 0])
            cylinder(h = 80, r = 10, center = true);
        translate([-10, -10, +40])
            sphere(r = 10);
        translate([-10, -10, -40])
            sphere(r = 10);
        }

Surface(): Apply a Height Map

The Surface module draws a surface based on the Height map information given either as numbers in a text data file, or by interpreting the luminance of each pixel in an image file.

The origin of the generated surface is normally placed at the origin of the coordinate system and extends outwards in the positive X and Y Directions. Setting the center parameter to true causes the generated surface to be centered on the X-Y origin.

The extent of the drawn surface is either

* the number of rows, and the quantity of numbers in each row, in a data file
* the number of pixels in each direction of an image.

Each height is applied at the corner of each pixel starting at [0,0] with the X index incrementing by one across each row, and the Y index increasing by one as each row is completed. This means that the surface may be considered as a grid of squares the four corners of which are:

[0,0] x-->
 y  [x,y]   [x+1,y]
 |
 V  [x,y+1] [x+1,y+1]

each of which may have a different height value, dividing the square into a number of polygons.

A one unit thick base is drawn under the generated surface at the level of the smallest value in the data file, which does consider negative values. This means that when least height value is zero the base will extend down to z=-1.

Parameters

filename
Required String. The filename may include an absolute or a relative path to the height map data file. There is no default extension so that must be explicitly given.
center
Optional Boolean, default=false. When true the X-Y placement of the surface is centered on the X-Y origin.
invert
Optional Boolean, default=false. Limitation: Only applies to image based maps

. Inverts how the pixel values are interpreted into height values.[Note: Requires version 2015.03]

convexity
Integer. Limitation: Only used by OpenCSG Preview
Higher values improve preview rendering of complex shapes.

Text Data Format

A text data height map is simply rows of whitespace separated floating point numbers.

The X-Y position of each data point is implied by their position along their row, for X, and by the row it is in for Y. The implicit indexing starts at the beginning of the file. The first row is at Y equals zero and the first value on each row is at X equals zero. The X and Y position increments by one for each row and value in a row.

Each row's data points are on, or parallel to, the X axis and all must have the same quantity of numbers.

The appearance of a hash sign ('#') as the first, non-whitespace character on a line marks it as a comment. A hash mark following numbers on a row cause a lexical fault making the data file unreadable.

Examples Using Data Map

//surface.scad
surface(file = "surface.dat", center = true, convexity = 5);
%translate([0,0,5])cube([10,10,10], center = true);
#surface.dat
10 9 8 7 6 5 5 5 5 5 
9 8 7 6 6 4 3 2 1 0 
8 7 6 6 4 3 2 1 0 0
7 6 6 4 3 2 1 0 0 0
6 6 4 3 2 1 1 0 0 0
6 6 3 2 1 1 1 0 0 0
6 6 2 1 1 1 1 0 0 0
6 6 1 0 0 0 0 0 0 0
3 1 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0

Result:

One may use an application like Octave or Matlab to make a data file. This is a small Matlab script that superimposes two sine waves to create a 3D surface:

d = (sin(1:0.2:10)' * cos(1:0.2:10)) * 10;
save("-ascii", "example010.dat", "d");

The data file can then be used to draw the surface in OpenSCAD:

//draw an instance of the surface
surface(file = "example010.dat", center = true);
//draw another instance, now rotated
translate(v = [70, 0, 0])
  rotate(45, [0, 0, 1])
    surface(file = "example010.dat", center = true);
// and two last instances, intersected 
translate(v = [35, 60, 0])
intersection() {
  surface(file = "example010.dat", center = true);
    rotate(45, [0, 0, 1])
      surface(file = "example010.dat", center = true);
}

Image Base Height Maps

[Note: Requires version 2015.03]

The height at each surface point is is calculated using the linear luminance for the sRGB color space (Y = 0.2126R + 0.7152G + 0.0722B) to derive a Grayscale value, which are further scaled to range 0 to 100.

Normally, with invert=false, the surface will be drawn upwards from the X-Y plane with black being z=0 increasing up to white=100. When invert=true the shape is still drawn starting at the X-Y plane, but now downwards to white=-100.

Currently only PNG (.png) images are supported and only the RGB information is used. The Alpha channel is ignored.

Example Using Invert

// Example 3a - apply a scale to the surface
scale([1, 1, 0.1])
  surface(file = "smiley.png", center = true);
scale([1, 1, 0.1])
  surface(file = "smiley.png", center = true, invert = true);
Input image
Input image
Surface output
Example 3a: surface(invert = false)
Surface output inverted
Example 3b: surface (invert = true)
Example 3: Using surface() with a PNG image as heightmap input.

Example Grayscale Effects [Note: Requires version 2015.03]

surface(file = "BRGY-Grey.png", center = true, invert = false);

The search() function is a general-purpose function to find one or more (or all) occurrences of a value or list of values in a vector, string or more complex list-of-list construct.

Search usage

search( match_value , string_or_vector [, num_returns_per_match [, index_col_num ] ] );

Search arguments

  • match_value
  • Can be a single string value. Search loops over the characters in the string and searches for each one in the second argument. The second argument must be a string or a list of lists (this second case is not recommended). The search function does not search for substrings.
  • Can be a single numerical value.
  • Can be a list of values. The search function searches for each item on the list.
  • To search for a list or a full string give the list or string as a single element list such as ["abc"] to search for the string "abc" (See Example 9) or [[6,7,8]] to search for the list [6,7,8]. Without the extra brackets, search looks separately for each item in the list.
  • If match_value is boolean then search returns undef.
  • string_or_vector
  • The string or vector to search for matches.
  • If match_value is a string then this should be a string and the string is searched for individual character matches to the characters in match_value
  • If this is a list of lists, v=[[a0,a1,a2...],[b0,b1,b2,...],[c0,c1,c2,...],...] then search looks only at one index position of the sublists. By default this is position 0, so the search looks only at a0, b0, c0, etc. The index_col_num parameter changes which index is searched.
  • If match_value is a string and this parameter is a list of lists then the characters of the string are tested against the appropriate index entry in the list of lists. However, if any characters fail to find a match a warning message is printed and that return value is excluded from the output (if num_returns_per_match is 1). This means that the length of the output is unpredictable.
  • num_returns_per_match (default: 1)
  • By default, search only looks for one match per element of match_value to return as a list of indices
  • If num_returns_per_match > 1, search returns a list of lists of up to num_returns_per_match index values for each element of match_value.
  • See Example 8 below.
  • If num_returns_per_match = 0, search returns a list of lists of all matching index values for each element of match_value.
  • See Example 6 below.
  • index_col_num (default: 0)
  • As noted above, when searching a list of lists, search looks only at one index position of each sublist. That index position is specified by index_col_num.
  • See Example 5 below for a simple usage example.

Search usage examples

See example023.scad included with OpenSCAD for a renderable example.

Index values return as list

Example Code Result

1

search("a","abcdabcd");

[0]

2

search("e","abcdabcd");

[]

3

search("a","abcdabcd",0);

[[0,4]]

4

data=[ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ];

search("a", data, num_returns_per_match=0);

[[0,4]] (see also Example 6 below)

Search on different column; return Index values

Example 5:

 data= [ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",3] ];
 echo(search(3, data));    // Searches index 0, so it doesn't find anything
 echo(search(3, data, num_returns_per_match=0, index_col_num=1));

Outputs:

 ECHO: []
 ECHO: [2, 8]

Search on list of values

Example 6: Return all matches per search vector element.

 data= [ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ];
 search("abc", data, num_returns_per_match=0);

Returns:

   [[0,4],[1,5],[2,6]]

Example 7: Return first match per search vector element; special case return vector.

 data= [ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ];
 search("abc", data, num_returns_per_match=1);

Returns:

   [0,1,2]

Example 8: Return first two matches per search vector element; vector of vectors.

 data= [ ["a",1],["b",2],["c",3],["d",4],["a",5],["b",6],["c",7],["d",8],["e",9] ];
 search("abce", data, num_returns_per_match=2);

Returns:

 [[0,4],[1,5],[2,6],[8]]

Search on list of strings

Example 9:

 lTable2=[ ["cat",1],["b",2],["c",3],["dog",4],["a",5],["b",6],["c",7],["d",8],["e",9],["apple",10],["a",11] ];
 lSearch2=["b","zzz","a","c","apple","dog"];
 l2=search(lSearch2,lTable2);
 echo(str("Default list string search (",lSearch2,"): ",l2));

Returns

 ECHO: "Default list string search (["b", "zzz", "a", "c", "apple", "dog"]): [1, [], 4, 2, 9, 3]"

Getting the right results

// workout which vectors get the results
v=[ ["O",2],["p",3],["e",9],["n",4],["S",5],["C",6],["A",7],["D",8] ];
//
echo(v[0]);					// -> ["O",2]
echo(v[1]);                                     // -> ["p",3]
echo(v[1][0],v[1][1]);                          // -> "p",3
echo(search("p",v));                            // find "p" -> [1]
echo(search("p",v)[0]);                         // -> 1
echo(search(9,v,0,1));                          // find  9  -> [2] 
echo(v[search(9,v,0,1)[0]]);                    // -> ["e",9]
echo(v[search(9,v,0,1)[0]][0]);                 // -> "e"
echo(v[search(9,v,0,1)[0]][1]);                 // -> 9
echo(v[search("p",v,1,0)[0]][1]);               // -> 3
echo(v[search("p",v,1,0)[0]][0]);               // -> "p"
echo(v[search("d",v,1,0)[0]][0]);               // "d" not found -> undef
echo(v[search("D",v,1,0)[0]][1]);               // -> 8

OpenSCAD version

version() and version_num() returns the OpenSCAD version number.

  • The version() function returns the OpenSCAD version as a vector of three numbers, e.g. [2011, 9, 23]
  • The version_num() function returns the OpenSCAD version as a number, e.g. 20110923

parent_module(n) and $parent_modules

$parent_modules contains the number of modules in the instantiation stack. parent_module(i) returns the name of the module i levels above the current module in the instantiation stack. The stack is independent of where the modules are defined. It's where they're instantiated that counts. This can, for example, be used to build a BOM (Bill Of Material).

Example:

 module top() {
   children();
 }
 module middle() {
   children();
 }
 top() middle() echo(parent_module(0)); // prints "middle"
 top() middle() echo(parent_module(1)); // prints "top"

assert

[Note: Requires version 2019.05]

see also Assertion (software development)

Assert evaluates a logical expression. If the expression evaluates to false, the generation of the preview/render is stopped, and an error condition is reported via the console. The report consists of a string representation of the expression and an additional string (optional) that is specified in the assert command.

 assert(condition);
 assert(condition, message);

Parameters

condition
Expression. The expression to be evaluated as check for the assertion.
message
String. Optional message to be output in case the assertion failed.

Example

The simplest example is a simple assert(false);, e.g. in a file named assert_example1.scad.

cube();
assert(false);
sphere();
  
// ERROR: Assertion 'false' failed in file assert_example1.scad, line 2

This example has little use, but the simple assert(false); can be used in code sections that should be unreachable.

Checking parameters

A useful example is checking the validity of input parameters:

module row(cnt = 3){
    // Count has to be a positive integer greater 0
    assert(cnt > 0);
    for (i = [1 : cnt]) {
        translate([i * 2, 0, 0]) sphere();
    }
}

row(0);

// ERROR: Assertion '(cnt > 0)' failed in file assert_example2.scad, line 3

Adding message

When writing a library, it could be useful to output additional information to the user in case of an failed assertion.

module row(cnt = 3){
    assert(cnt > 0, "Count has to be a positive integer greater 0");
    for(i = [1 : cnt]) {
        translate([i * 2, 0, 0]) sphere();
    }
}

row(0);

// ERROR: Assertion '(cnt > 0)': "Count has to be a positive integer greater 0" failed in file assert_example3.scad, line 2

Using assertions in function

Assert returns its children, so when using it in a function you can write

function f(a, b) =
    assert(a < 0, "wrong a") // assert input
    assert(b > 0, "wrong b") // assert input
    let (c = a + b) // derive a new value from input
    assert(c != 0, "wrong c") // assert derived value
    a * b; // calculate
Category:Book:OpenSCAD User Manual#Other%20Language%20Features%20
Category:Book:OpenSCAD User Manual