跳转到内容

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

来自维基教科书,开放世界中的开放书籍

For 循环

[编辑 | 编辑源代码]

评估范围或向量中的每个值,将其应用于以下操作。

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

参数

作为范围 [ 开始 : <增量 : > 结束 ](参见关于 范围 的部分)
注意:对于范围,值由冒号分隔,而不是向量中使用的逗号。
开始 - 初始值
增量 或步长 - 增加值的量,可选,默认 = 1
结束 - 当下一个值超过结束时停止
示例:
 for (a =[3:5])echo(a);     // 3 4 5
 for (a =[3:0]){echo(a);}   // 0 1 2 3         start > end is invalid, deprecated by 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           a never equals end 
 for (a =[3:-2:-1])echo(a); // 3 1 -1          negative increment requires 2015.3
                                               be sure 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 each”
 animals = ["elephants", "snakes", "tigers", "giraffes"];
   for(animal = animals)
     echo(str("I've been to the zoo and saw ", animal));
 // "I've been to the zoo and saw elephants", for each animal

for() 是一个运算符。运算符如果包含多个操作,则需要使用大括号 {}。操作以分号结尾,运算符没有。

for() 并不违反关于变量在一个作用域中只有一个值的规则。每个评估都拥有自己的作用域,允许任何变量具有唯一的价值。不,你仍然不能执行 a=a+1;

请记住,这不是一种迭代语言,for() 不会以编程意义上的循环方式运行,它会构建一个对象树,每个范围/向量中的项目都有一个分支,在每个分支中,“变量”是一个特定的、独立的实例化或作用域。

因此

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

产生:[见设计/显示-CSG-树菜单]

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

虽然 group() 是按顺序构建的,但 for() 的所有实例都作为独立的实体存在,它们不会按顺序迭代同一部分代码。

嵌套 for()

虽然嵌套多个 for() 语句是合理的,例如

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

相反,所有范围/向量都可以包含在同一个 for() 运算符中。

for ( variable1 = <range or vector> , variable2 = <range or vector> ) <do something using both variables>
嵌套 3 层的 for() 循环
 example for() nested 3 deep
 
 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();}
 
 shorthand nesting for same result
 
 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() 循环向量向量(旋转)
example 1 - iteration over a vector of vectors (rotation)
  
 for(i = [ [  0,  0,   0],
           [ 10, 20, 300],
           [200, 40,  57],
           [ 20, 88,  57] ])
{
   rotate(i)
   cube([100, 20, 20], center = true);
}


示例 2 for() 循环向量向量(平移)
example 2 - iteration over a vector of vectors (translation)
  
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() 循环向量向量
example 3 - iteration over a vector of vectors
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]]);
}

交集 For 循环

[编辑 | 编辑源代码]

遍历范围或向量中的值,并为每次传递创建的每个对象创建 交集

除了为每次传递创建独立的实例外,标准 for() 还对所有这些实例进行分组,从而创建一个隐式的联合。intersection_for() 是一种解决方法,因为隐式的联合会阻止使用标准 for()intersection() 语句的组合来获得预期的结果。

intersection_for() 使用相同参数,并且工作方式与 For 循环 相同,只是消除了隐式的联合。

示例 1 - 遍历范围
intersection_for(n = [1 : 6])
{
    rotate([0, 0, n * 60])
    {
        translate([5,0,0])
        sphere(r=12);
    }
}
intersection_for()
intersection() for() 或 for() intersection()


示例 2 - 旋转:
 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()

If 语句

[编辑 | 编辑源代码]

执行测试以确定是否应执行子范围中的操作。

非常重要。你无法更改变量的值。如果你更新了方括号内变量的值,新值将在你退出该作用域后丢失。

if (test) scope1
if (test){scope1}
if (test) scope1  else  scope2
if (test){scope1} else {scope2}
参数
测试:通常是布尔表达式,但可以是任何值或变量。
参见此处了解值的真或假状态。
参见此处了解布尔运算符和逻辑运算符。
不要将赋值运算符 '=' 与等于运算符 '==' 混淆
范围 1:当测试为 true 时要采取的一个或多个操作。
范围 2:当测试为 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);

自 2015.03 年起,变量现在可以在任何作用域中分配。请注意,分配仅在定义它们的作用域内有效 - 你仍然不允许将值泄漏到外部作用域。有关更多详细信息,请参阅 变量作用域

嵌套 if

if() 部分和 else 部分的作用域都可以包含 if() 语句。这种嵌套可以达到很多深度。

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

当范围 1 和范围 2 包含 if() 语句时,可以删除外部大括号。

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

一种演变是

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

请注意,elseif 是两个单独的词。在遍历测试链时,第一个 true 使用其作用域。所有后续测试都将跳过。

示例
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);}

条件 ? :

[编辑 | 编辑源代码]

一个使用测试来确定要返回哪个值中的 2 个值的函数。

 a =   test ? TrueValue : FalseValue ;
 echo( test ? TrueValue : FalseValue );
参数
测试:通常是布尔表达式,但可以是任何值或变量。
参见此处了解值的真或假状态。
参见此处了解布尔运算符和逻辑运算符。
不要将赋值 '=' 与等于 '==' 混淆
TrueValue:当测试为 true 时要返回的值。
FalseValue:当测试为 false 时要返回的值。
OpenSCAD 中的值是数字(如 42)、布尔值(如 true)、字符串(如“foo”)、向量(如 [1,2,3])或未定义值(undef)。值可以存储在变量中,作为函数参数传递,并作为函数结果返回。

这类似于?:来自类 C 编程语言家族的运算符。

示例
 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]
Some forms of tail-recursion elimination are supported.

递归函数调用

[编辑 | 编辑源代码]

支持递归函数调用。使用条件 "... ? ... : ...",可以确保递归被终止。注意:有一个内置的递归限制,以防止应用程序崩溃。如果遇到限制,函数将返回 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

格式化复杂用法

[编辑 | 编辑源代码]

多个嵌套条件可能难以理解。将它们格式化为多行缩进的“if/else”语句会更清晰。

// find the maximum value in a vector
function maxv(v, m=-999999999999, i=0) = 
    (i == len(v) ) 
    ?     m 
    :     (m > v[i]) 
          ?    maxv(v, m, i+1) 
          :    maxv(v, v[i], i+1);

v=[7,3,9,3,5,6];
echo("max",maxv(v));   // ECHO: "max", 9

赋值语句

[编辑 | 编辑源代码]

[已弃用: assign() 将在将来的版本中删除。现在可以在任何地方分配变量。如果你更喜欢这种设置值的方式,可以使用新的 Let 语句 代替。]

为子树设置变量的新值。

参数
应该(重新)分配的变量
示例
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 版本]

将子树中的变量设置为新值。参数按顺序计算,可能互相依赖(与已弃用的 assign() 语句相反)。

参数
要设置的变量
示例
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);
    }
}
华夏公益教科书