### 特殊变量

Special variables pass along their value from within the scope (see scope of variables) from which the module or function is called. This means that special variables can potentially have a different value each time a module or function is called.

```regular  = "regular global";
\$special = "special global";
module show() echo("         in show    ", regular,"   ", \$special );

echo ("         outside    ", regular,"   ", \$special );
// ECHO: "         outside    ", "regular global", "   ", "special global"

for ( regular = [0:1] ){ echo("in regular loop     ", regular,"   ", \$special ); show();}
// ECHO: "in regular loop     ", 0, "   ", "special global"
// ECHO: "         in show    ", "regular global", "   ", "special global"
// ECHO: "in regular loop     ", 1, "   ", "special global"
// ECHO: "         in show    ", "regular global", "   ", "special global"

for ( \$special = [5:6] ){ echo("in special loop     ", regular,"   ", \$special ); show();}
// ECHO: "in special loop     ", "regular global", "   ", 5
// ECHO: "         in show    ", "regular global", "   ", 5
// ECHO: "in special loop     ", "regular global", "   ", 6
// ECHO: "         in show    ", "regular global", "   ", 6

show();
// ECHO: "         in show    ", "regular global", "   ", "special global"
```

This is useful when multiple arguments need to be passed thru several layers of module calls.

#### \$fa, \$fs 与 \$fn

\$fa为片段的最小角度。即使是一个再巨大的圆形，也不能通过此值而将其划分为多于360个片段。此特殊变量的默认值为12 (即，整个圆形分为30个片段)。其最小值为0.01。若企图将其设置为小于0.01的值，会产生一个警告。

\$fs为片段的最小尺寸。Because of this variable very small circles have a smaller number of fragments than specified using \$fa. 此特殊变量的默认值为2。其最小值为0.01。若企图将其设置为小于0.01的值，会产生一个警告。

\$fn通常为0。当此变量大于0时，则忽略另外两个变量（\$fa, \$fs），且以此值作为片段数量来渲染整个圆形。其默认值为0。

TIP: If you want to create a circle/cylinder/sphere which has a axis aligned integer bounding box (i.e. a bounding box that has integral dimensions, and an integral position) use a value of \$fn that is divisible by 4.

```      int get_fragments_from_r(double r, double fn, double fs, double fa)
{
if (r < GRID_FINE) return 3;
if (fn > 0.0) return (int)(fn >= 3 ? fn : 3);
return (int)ceil(fmax(fmin(360.0 / fa, r*2*M_PI / fs), 5));
}
```

Or you can embed this OpenSCAD version in your code to work out what's going on, you need to set r= to your size

```   echo(n=(\$fn>0?(\$fn>=3?\$fn:3):ceil(max(min(360/\$fa,r*2*PI/\$fs),5))),a_based=360/\$fa,s_based=r*2*PI/\$fs);
```

Spheres are first sliced into as many slices as the number of fragments being used to render a circle of the sphere's radius, and then every slice is rendered into as many fragments as are needed for the slice radius. You might have recognized already that the pole of a sphere is usually a pentagon. This is why.

The number of fragments for a cylinder is determined using the greater of the two radii.

The method is also used when rendering circles and arcs from DXF files. The variables have no effect when importing STL files.

You can generate high resolution spheres by resetting the \$fX values in the instantiating module:

```      \$fs = 0.01;
sphere(2);
```

```      sphere(2, \$fs = 0.01);
```

```      sphere(2, \$fs = \$fs * 0.01);
```

#### \$t

\$t变量用于制作动画。如果您通过设置view->animate开启动画，并指定"FPS（帧率）"以及"Steps（步长）"，"Time"字段显示的就是\$t的当前值。掌握了这些信息，便能令您的设计以动画效果展示出来。The design is recompiled every 1/"FPS" seconds with \$t incremented by 1/"Steps" for "Steps" times, ending at either \$t=1 or \$t=1-1/steps.

• \$t=0/Steps filename="frame00001.png"
• \$t=1/Steps filename="frame00002.png
• \$t=2/Steps filename="frame00003.png"
• . . .
• \$t=1-3/Steps filename="frame<Steps-2>.png"
• \$t=1-2/Steps filename="frame<Steps-1>.png"
• \$t=1-1/Steps filename="frame00000.png"

• \$t=0/Steps filename="frame00001.png"
• \$t=1/Steps filename="frame00002.png
• \$t=2/Steps filename="frame00003.png"
• . . .
• \$t=1-3/Steps filename="frame<Steps-2>.png"
• \$t=1-2/Steps filename="frame<Steps-1>.png"
• \$t=1-1/Steps filename="frame<Steps-0>.png"
• \$t=1-0/Steps filename="frame00000.png"

Which pattern it chooses appears to be an unpredictable, but consistent, function of Steps. For example, when Steps=4, it follows the first pattern, and outputs a total of 4 files. When Steps=3, it follows the second pattern, and also outputs 4 files. It will always output either Steps or Steps+1 files, though it may not be predictable which. When finished, it will wrap around and recreate each of the files, looping through and recreating them forever.

#### \$vpr, \$vpt 与 \$vpd

• \$vpr表示旋转
• \$vpt表示平移(即此值不受旋转或缩放操作影响)
• \$vpd表示摄像机距离 [请注意: 需要使用版本 2015.03]

``` cube([10, 10, \$vpr[0] / 10]);
```

You can also make bits of a complex model vanish as you change the view.

All three variables are writable but only assignments at the top-level of the main file will have an effect on the viewport. [请注意: 需要使用版本 2015.03]

``` \$vpr = [0, 0, \$t * 360];
```

which allows a simple 360 degree rotation around the Z axis in animation mode.

The menu command Edit - Paste Viewport Rotation/Translation copies the current value of the viewport, but not the current \$vpr or \$vpt.

#### \$preview

[请注意: 需要使用版本 2019.05]

This can, for example, be used to reduce detail during preview to save time, without losing detail in the final rendered result:

```\$fn = \$preview ? 12 : 72;
sphere(r = 1);
```

```render(){
\$fn = \$preview ? 12 : 72;
sphere(r = 1);
}
```

Another use could be to make the preview show an assembly view and the render generate just the printed parts laid out for printing.

If printed parts need extra features that are removed post printing, for example support for suspended holes, then the preview can omit these to show the finished part after post processing.

When OpenSCAD is run from the command line \$preview is only true when generating a PNG image with OpenCSG. It is false when generating STL, DXF and SVG files with CGAL. It is also false when generating CSG and ECHO files. This may or may not be what you want, but you can always override it on the command line like any other variable with the -D option.

### echo语句

It can be handy to use 'variable=variable' as the expression to easily label the variables, see the example below.

#### 用例

```my_h=50;
my_r=100;
echo("This is a cylinder with h=", my_h, " and r=", my_r);
echo(my_h=my_h,my_r=my_r); // shortcut
cylinder(h=my_h, r=my_r);
//
echo("Hello Qt!");
```

```ECHO: "This is a cylinder with h=", 50, " and r=", 100
ECHO: my_h = 50, my_r = 100
ECHO: "Hello Qt!"
```

#### 四舍五入示例

```a=1.0;
b=1.000002;
echo(a);
echo(b);

if(a==b){ // 尽管回显结果相同，但是二值仍有差别
echo ("a==b");
}else if(a>b){
echo ("a>b");
}else if(a<b){
echo ("a<b");
}else{
echo ("???");
}
```

#### 小数与大数示例

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

#### HTML

HTML工作示例：

```echo("<h1>Heading</h1>");
echo("<b>Bold</b> <i>italic</i> <big>big</big>");
echo("i<sub>1</sub><sup>2<sup>");
echo("<font color='red'>red</font> <font color='green'>green</font> <font color='blue'>blue</font>");
```

```echo("<img src='http://www.openscad.org/assets/img/logo.png'></img>");
echo("<a href='http://en.wikibooks.org/'>wikibooks</a>");
```

### echo函数

[请注意: 需要使用版本 2019.05]

Echo can be used in expression context to print information while the function/expression is evaluated. The output is generated before the expression evaluation to allow debugging of recursive functions.

``` a = 3; b = 5;

// echo() prints values before evaluating the expression
r1 = echo(a, b) a * b; // ECHO: 3, 5

// using let it's still easy to output the result
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 descending and ascending path of a recursive function. The result() helper function is a simple way to output the value of an expression after evaluation.

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

Forces the generation of a mesh even in preview mode. Useful when the boolean operations become too slow to track.

Needs description.

```render(convexity = 2) difference() {
cube([20, 20, 150], center = true);
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

Surface reads Heightmap information from text or image files.

file
String. The path to the file containing the heightmap data.
center
Boolean. This determines the positioning of the generated object. If true, object is centered in X- and Y-axis. Otherwise, the object is placed in the positive quadrant. Defaults to false.
invert
Boolean. Inverts how the color values of imported images are translated into height values. This has no effect when importing text data files. Defaults to false. [请注意: 需要使用版本 2015.03]
convexity
Integer. The convexity parameter specifies the maximum number of front sides (back sides) a ray intersecting the object might penetrate. This parameter is only needed for correctly displaying the object in OpenCSG preview mode and has no effect on the final rendering.

#### 文本文件格式

The format for text based heightmaps is a matrix of numbers that represent the height for a specific point. Rows are mapped to the Y-axis, columns to the X axis. The numbers must be separated by spaces or tabs. Empty lines and lines starting with a # character are ignored.

#### 图片

[请注意: 需要使用版本 2015.03]

Currently only PNG images are supported. Alpha channel information of the image is ignored and the height for the pixel is determined by converting the color value to Grayscale using the linear luminance for the sRGB color space (Y = 0.2126R + 0.7152G + 0.0722B). The gray scale values are scaled to be in the range 0 to 100.

#### 示例

```//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
```

``` // example010.dat generated using octave:
// d = (sin(1:0.2:10)' * cos(1:0.2:10)) * 10;
// save("example010.dat", "d");
intersection() {
surface(file = "example010.dat", center = true, convexity = 5);
rotate(45, [0, 0, 1]) surface(file = "example010.dat", center = true, convexity = 5);
}
```

[请注意: 需要使用版本 2015.03]

```// 示例 3a
scale([1, 1, 0.1])
surface(file = "smiley.png", center = true);
```
```// 示例 3b
scale([1, 1, 0.1])
surface(file = "smiley.png", center = true, invert = true);
```

[请注意: 需要使用版本 2015.03]

```// 示例4
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( match_value , string_or_vector [, num_returns_per_match [, index_col_num ] ] );

#### 查找函数的参数

• match_value
• Can be a single string value. Search will loop over the characters in the string and search 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 will search 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 will look 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 will look 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

##### 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);`

##### Search on different column; return Index values

``` 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));
```

``` ECHO: []
ECHO: [2, 8]
```
##### 对一组值进行搜索

``` 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]]
```

``` 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]
```

``` 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

``` 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]][1]);               // -> 8
```

### parent_module(n) 与 \$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 be used to e.g. build BOMs.

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

### assert

[请注意: 需要使用版本 2019.05]

Assert evaluates a logical expression. If the expression evaluates to false, the generation of the preview/render is stopped with an error. A string representation of the expression and, if given, the message is output to the console.

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

#### 示例

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.

#### 检查参数

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
```

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
```

### is_undef

[请注意: 需要使用版本 2019.05]

is_undef accepts one parameter. If the parameter is undef, this function returns true. If the parameter is not undef, it returns false. When checking a variable (like `is_undef(a)`), it does the variable lookup silently, meaning that is_undef(a) does not cause `WARNING: Ignoring unknown variable 'a'. `

The alternative is code like this:

```if(a==undef){
//code goes here
}
```

or

```b = (a==undef) ? true : false;
```

will cause

```WARNING: Ignoring unknown variable 'a'.
```

is_undef also works for special variables, allowing for things like this:

```exploded = is_undef(\$exploded) ? 0 : \$exploded; // 1 for exploded view
```

#### legacy support

For older openscad version, is_undef can be emulated with

```function is_undef ( a ) = (undef == a) ;
```

which off-course causes warning(s), but requires no changes to code relaying on is_undef().

### is_list

[请注意: 需要使用版本 2019.05]

```echo("returning true");
echo(is_list([]));
echo(is_list([1]));
echo(is_list([1,2]));
echo(is_list([true]));
echo(is_list([1,2,[5,6],"test"]));
echo("--------");
echo("returning false");
echo(is_list(1));
echo(is_list(1/0));
echo(is_list(((1/0)/(1/0))));
echo(is_list("test"));
echo(is_list(true));
echo(is_list(false));
echo("--------");
echo("causing warnings:");
echo(is_list());
echo(is_list(1,2));
```

### is_num

[请注意: 需要使用版本 2019.05]

```echo("a number is a number:");
echo(is_num(0.1));
echo(is_num(1));
echo(is_num(10));

echo("inf is a number:");
echo(is_num(+1/0)); //+inf
echo(is_num(-1/0)); //-inf

echo("nan is not a number:");
echo(is_num(0/0)); //nan
echo(is_num((1/0)/(1/0)));  //nan

echo("resulting in false:");
echo(is_num([]));
echo(is_num([1]));
echo(is_num("test"));
echo(is_num(false));
echo(is_num(undef));
```

### is_bool

[请注意: 需要使用版本 2019.05]

```echo("resulting in true:");
echo(is_bool(true));
echo(is_bool(false));
echo("resulting in false:");
echo(is_bool([]));
echo(is_bool([1]));
echo(is_bool("test"));
echo(is_bool(0.1));
echo(is_bool(1));
echo(is_bool(10));
echo(is_bool(0/0)); //nan
echo(is_bool((1/0)/(1/0)));  //nan
echo(is_bool(1/0));  //inf
echo(is_bool(-1/0));  //-inf
echo(is_bool(undef));
```

### is_string

[请注意: 需要使用版本 2019.05]

```echo("resulting in true:");
echo(is_string(""));
echo(is_string("test"));
echo("resulting in false:");
echo(is_string(0.1));
echo(is_string(1));
echo(is_string(10));
echo(is_string([]));
echo(is_string([1]));
echo(is_string(false));
echo(is_string(0/0)); //nan
echo(is_string((1/0)/(1/0)));  //nan
echo(is_string(1/0));  //inf
echo(is_string(-1/0));  //-inf
echo(is_string(undef));
```