OpenSCAD用户手册/条件与迭代函数

维基教科书,自由的教学读本

for循环[编辑]


计算出范围或向量中的每一个值,并对其执行其后的动作(action)。

 for(variable = [start : increment : end])
 for(variable = [start : end])
 for(variable = [vector])

参数

针对范围 [ start : <increment : > end ] (参见range部分)
请注意: 对于范围而言,其中的值用冒号分隔,而非如向量那样用逗号。
start - 初始值
increment 或称 step(步长) - 每次循环都要为start加上此值(start = start + increment)作为比较值,该参数为可选项, 默认值 = 1
end - 当本次循环计算后的比较值大于此值时,停止循环
示例:
 for (a =[3:5])echo(a);     // 3 4 5
 for (a =[3:0]){echo(a);}   // 0 1 2 3         开始循环时start > end是非法的,本特性自2015.3版废止
 for (a =[3:0.5:5])echo(a); // 3 3.5 4 4.5 5
 for (a =[0:2:5])echo(a);   // 0 2 4           整个循环过程中,比较值从未等于过end 
 for (a =[3:-2:-1])echo(a); // 3 1 -1          自2015.3版起开始支持负值increment
                                               确保end > start
针对向量
为向量中的每一个元素执行其后的动作。
 for (a =[3,4,1,5])echo(a); // 3 4 1 5
 for (a =[0.3,PI,1,99]){echo(a);}    // 0.3 3.14159 1 99
 x1=2; x2=8; x3=5.5;
 for (a =[x1,x2,x3]){echo(a);} // 2 8 5.5 
 for (a =[[1,2],6,"s",[[3,4],[5,6]]])echo(a);  // [1,2] 6 "s" [[3,4],[5,6]] 

for()是一种运算符(算子)。如果运算符的作用域中存在多个动作,就用大括号{}将这些动作圈在其中。动作要以分号作为结尾,运算符不必如此。

对于变量规则而言,for()函数也非例外,其作用域中的变量各有自己的唯一值。循环中的每次求值都有其自己的作用域,借此令任一变量都有其唯一值。所以,您依然不能使用a=a+1;语句。

请牢记,OpenSCAD并非支持迭代(iterative)的语言,而在编写代码时也应意识到for()其实也并非循环:它会针对范围/向量中的每一项构建一颗对象分支树,在每一个分支中'变量'是一个独立的特定实例或作用域。

因此:

for (i=[0:3])
   translate([i*10,0,0])
     cube(i+1);

将生成: [参见Design/Display-CSG-Tree菜单]

 group() {
       group() {
               multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
                       cube(size = [1, 1, 1], center = false);
               }
               multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
                       cube(size = [2, 2, 2], center = false);
               }
               multmatrix([[1, 0, 0, 20], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
                       cube(size = [3, 3, 3], center = false);
               }
               multmatrix([[1, 0, 0, 30], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
                       cube(size = [4, 4, 4], center = false);
               }
       }
}

所有的for()实例同时存在,并非按顺序迭代。

嵌套for()

多个for()语句的嵌套调用也是合情合理的:

for(z=[-180:45:+180])
  for(x=[10:5:50])
    rotate([0,0,z]) translate([x,0,0]) cube(1);

instead, all ranges/vectors can be include in the same for() operator.

for ( variable1 = <range or vector> , variable2 = <range or vector> ) <do something using both variables>
深度为3的for()循环嵌套
 深度为3的for()嵌套示例
 
 color_vec = ["black","red","blue","green","pink","purple"];
 for (x = [-20:10:20] )
 for (y = [0:4] )color(color_vec[y])
 for (z = [0,4,10] )
     {translate([x,y*5-10,z])cube();}
 
 上述for()嵌套的等效简化写法
 
 color_vec = ["black","red","blue","green","pink","purple"];
 for (x = [-20:10:20],
 y = [0:4],
 z = [0,4,10] )
     translate([x,y*5-10,z]){color(color_vec[y])cube();}
关于元素为向量的向量示例
示例1:对元素为向量的向量执行for()循环(旋转操作)
示例1 - 对元素为向量的向量进行迭代(旋转操作)
  
 for(i = [ [  0,  0,   0],
           [ 10, 20, 300],
           [200, 40,  57],
           [ 20, 88,  57] ])
{
   rotate(i)
   cube([100, 20, 20], center = true);
}


示例2:对元素为向量的向量执行for()循环(平移操作)
示例2 - 对元素为向量的向量进行迭代(平移操作)
  
for(i = [ [ 0,  0,  0],
          [10, 12, 10],
          [20, 24, 20],
          [30, 36, 30],
          [20, 48, 40],
          [10, 60, 50] ])
{
   translate(i)
   cube([50, 15, 10], center = true);
}
示例3:对元素为向量的向量执行for()循环
示例3 - 对元素为向量的向量进行迭代
for(i = [ [[ 0,  0,  0], 20],
          [[10, 12, 10], 50],
          [[20, 24, 20], 70],
          [[30, 36, 30], 10],
          [[20, 48, 40], 30],
          [[10, 60, 50], 40] ])
{
  translate([i[0][0], 2*i[0][1], 0])
  cube([10, 15, i[1]]);
}

intersection_for循环[编辑]


Iterate over the values in a range or vector and create the intersection of objects created by each pass.

Besides creating separate instances for each pass, the standard for() also groups all these instances creating an implicit union. intersection_for() is a work around because the implicit union prevents getting the expected results using a combination of the standard for() and intersection() statements.

intersection_for() uses the same parameters, and works the same as a For Loop, other than eliminating the implicit union.

示例1 - loop over a range:
intersection_for(n = [1 : 6])
{
    rotate([0, 0, n * 60])
    {
        translate([5,0,0])
        sphere(r=12);
    }
}
intersection_for()
either intersection() for() or for() intersection()


示例2 - rotation :
 intersection_for(i = [ [  0,  0,   0],
 			[ 10, 20, 300],
 			[200, 40,  57],
 			[ 20, 88,  57] ])
{
    rotate(i)
    cube([100, 20, 20], center = true);
}
intersection_for()
intersection() for()

In

if语句[编辑]


执行一个测试,用于确定其子域中的动作是否该执行。

if (test) scope1
if (test){scope1}
if (test) scope1  else  scope2
if (test){scope1} else {scope2}
参数
test: 通常是一个布尔表达式,但是也可为任意值或变量。
See here for true or false state of values.
See here for boolean and logical operators
Do not confuse the assignment operator '=' with the equal operator '=='
scope1: one or more actions to take when test is true.
scope2: one or more actions to take when test is false.
if (b==a)  cube(4);
if (b<a)  {cube(4); cylinder(6);}
if (b&&a) {cube(4); cylinder(6);}
if (b!=a)  cube(4); else cylinder(3);
if (b)    {cube(4); cylinder(6);} else {cylinder(10,5,5);} 
if (!true){cube(4); cylinder(6);} else  cylinder(10,5,5); 
if (x>y)   cube(1, center=false); else {cube(size = 2, center = true);}
if (a==4) {}                      else  echo("a is not 4");
if ((b<5)&&(a>8))  {cube(4);      else cylinder(3);}
if (b<5&&a>8)       cube(4);      else cylinder(3);

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

嵌套if

The scopes of both the if() portion and the else portion, can in turn contain if() statements. This nesting can be to many depths.

 if (test1) 
 {
   scope1 if (test2) {scope2.1}
          else {scope2.2}
 }
 else
{
  scope2 if (test3) {scope3.1}
         else {scope3.2}
}

When scope1 and scope2 contain only the if() statement, the outer sets of braces can be removed.

 if (test1)
   if (test2) {scope2.1}
   else {scope2.2}
 else
   if (test3) {scope3.1}
   else {scope3.2}

One evolution is this:

else if[编辑]

      if(test1) {scope1}
 else if(test2) {scope2}
 else if(test3) {scope3}
 else if(test4) {scope4}
 else           {scope5}

Note that else and if are two separate words. When working down the chain of tests, the first true will use its scope. All further tests will be skipped.

示例
  
if((k<8)&&(m>1)) cube(10);
else if(y==6)   {sphere(6);cube(10);}
else if(y==7)    color("blue")sphere(5);
else if(k+m!=8) {cylinder(15,5,0);sphere(8);}
else             color("green"){cylinder(12,5,0);sphere(8);}

条件语句? :[编辑]


A function which uses a test to determine which of 2 values to return.

 a =   test ? TrueValue : FalseValue ;
 echo( test ? TrueValue : FalseValue );
参数
test: Usually a boolean expression, but can be any value or variable.
See here for true or false state of values.
See here for boolean and logical operators
Do not confuse assignment '=' with equal '=='
TrueValue: the value to return when test is true.
FalseValue: the value to return when test is false.
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.

This works like the ?: operator from the family of C-like programming languages.

示例
 a=1; b=2; c= a==b ? 4 : 5 ;                  //  5
 a=1; b=2; c= a==b ? "a==b" : "a!=b" ;        //  "a!=b"
  
 TrueValue = true; FalseValue = false;
 a=5; test = a==1;
 echo( test ? TrueValue : FalseValue );       // false
  
 L = 75; R = 2; test = (L/R)>25;
 TrueValue =  [test,L,R,L/R,cos(30)];
 FalseValue = [test,L,R,sin(15)];
 a1 = test ? TrueValue : FalseValue ;         // [true, 75, 2, 37.5, 0.866025]

函数递归调用[编辑]

Recursive function calls are supported. Using the Conditional "... ? ... : ... " it's 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 function returns undef.

示例
 // recursion - find the sum of the values in a vector (array) by calling itself
 // 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)); // calculates 20+30=50

Some forms of tail-recursion elimination are supported.

assign语句[编辑]


[废止: assign() 将从未来发行版中去掉。 现在可在任意作用域对变量进行赋值。如果您更喜欢以这种方式来设置值,可以用新的Let语句来替代它。] Template:Bookcat

针对一颗子树对变量设置的新值。

参数
(重新)赋予变量的值
示例:
for (i = [10:50])
{
    assign (angle = i*360/20, distance = i*10, r = i*2)
    {
        rotate(angle, [1, 0, 0])
        translate([0, distance, 0])
        sphere(r = r);
    }
}
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);
}

let语句[编辑]


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

针对一颗子树为变量设置新值。 The parameters are evaluated sequentially and may depend on each other (as opposed to the deprecated assign() statement).

参数
为变量设置的值
示例:
for (i = [10:50])
{
    let (angle = i*360/20, r= i*2, distance = r*5)
    {
        rotate(angle, [1, 0, 0])
        translate([0, distance, 0])
        sphere(r = r);
    }
}