OpenSCAD 用户手册/条件和迭代函数
评估范围或向量中的每个值,将其应用于以下操作。
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>
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();}
- 使用向量向量示例
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); }
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); }
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() 还对所有这些实例进行分组,从而创建一个隐式的联合。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);
}
}
|
示例 2 - 旋转: | ||
intersection_for(i = [ [ 0, 0, 0],
[ 10, 20, 300],
[200, 40, 57],
[ 20, 88, 57] ])
{
rotate(i)
cube([100, 20, 20], center = true);
}
|
执行测试以确定是否应执行子范围中的操作。
非常重要。你无法更改变量的值。如果你更新了方括号内变量的值,新值将在你退出该作用域后丢失。
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}
请注意,else 和 if 是两个单独的词。在遍历测试链时,第一个 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);
}
[注意: 需要 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);
}
}