Recursion 理解Postscript中的递归Koch雪花函数

Recursion 理解Postscript中的递归Koch雪花函数,recursion,postscript,fractals,Recursion,Postscript,Fractals,我在后记中有一个很难理解的程序 /kochR { 2 copy ge {dup 0 rlineto} { 3 div 2 copy kochR 60 rotate 2 copy kochR -120 rotate 2 copy kochR 60 rotate 2 copy kochR } ifelse pop pop } def 0 0

我在后记中有一个很难理解的程序

/kochR
 {
   2 copy ge {dup 0 rlineto}
     {
       3 div
       2 copy kochR
       60 rotate
       2 copy kochR
       -120 rotate
       2 copy kochR
       60 rotate
       2  copy kochR
      } ifelse
     pop pop
  } def

0 0 moveto
27 81 kochR
0 27 moveto
9 81 kochR
0 54 moveto
3 81 kochR
0 81 moveto
1 81 kochR
stroke
我对上述计划的问题如下:

  • 这里的
    2 copy ge{dup 0 rlineto}
    是什么意思
  • ifelse
    在这里是如何工作的?条件是什么
  • 3div
    在这里做什么
  • 2 copy KochR
    语句在这里执行什么操作

  • 您似乎在基本的PostScript概念和操作方面遇到了一些问题,您有PostScript语言参考手册吗

  • copy复制操作数堆栈上的一个条目,前面的参数告诉解释器要复制堆栈上的多少个操作数。ge测试大于或等于,然后测试一个可执行数组

  • ifelse以您期望的方式工作,如果条件为true,则执行第一个可执行数组,否则执行第二个可执行数组

  • 3 div将堆栈上的操作数除以3,并将结果放在操作数堆栈上

  • 2 copy的作用与第1点相同,“KochR”是一个命名对象,在本例中,它是一个可执行数组。它必须是以前定义的,否则将发生“未定义”错误

  • 作为
    if
    ifelse
    操作符的THEN子句,它表示“if(stack(top-1)>stack(top))绘制水平线((current_x,current_y)->(current_x+stack(top),current_y)。过程体
    {dup 0 rlineto}
    是递归的结束:该部分决定何时停止以及如何代替递归。
    rlineto
    绘制了一条相对线。相对于当前点,即当前点是最后一个路径构造操作符所在的位置(如
    moveto
    lineto
    ,但不是
    rotate
    ,也不是
    stroke
    )离开了它

    ifelse
    始终以相同的方式工作:booleantype过程体过程体ifelse:如果布尔值为true,则执行第一个过程体,否则执行第二个过程体。该条件是应用于堆栈上2个数字的
    gt
    运算符的布尔值结果。由于
    gt
    使用其参数,因此请预先ding
    2 copy
    表示执行此操作时数据不会丢失

    What does 3 div do here?
    
    由于第二个参数(堆栈顶部)控制图形的总体大小,因此它还控制由所有子调用的组合绘图命令表示的部分图形的“大小”。
    3div
    表示在每个递归级别,图形的“大小”小于“大小”"在叶调用中,条件a>=b保持不变,b用作组成图像的各个线段的长度。这意味着a本身不是线段长度,而是一个阈值。只要b下降到b/3、b/9、b/27、b/81时满足或超过阈值a,则关闭t的时间就到了他发明了一台克隆机,让每个人都拿起铅笔

    What does the 2 copy KochR statement perform here?
    
    此行使用与传递到当前调用的两个参数相同的阈值和减小的大小,执行对kochR过程的递归调用。使用
    2 copy
    表示这两个值在堆栈上持续存在,直到
    pop
    进一步向下


    这里是C语言的粗略翻译,假设有一个实现Adobe图像模型(也称为模具蒙版,或路径绘制模型)的可用图形库。参数似乎分别是线段的大小和图形的总体大小。因此,最大递归级别由方程式a>=b*(1/3)^R间接控制

    因此,您应该能够从中看到,所有的
    2拷贝
    内容都意味着postscript必须“保持活力”2个未命名变量。每行对应一个过程调用,该过程调用使用堆栈中的2个变量。如果您还忽略了上一个“过程调用”中的最终
    2 copy
    ,您应该能够看到最终
    pop
    将是不必要的从postscript编程的角度来看,这些都是非常基本的东西。但是递归的边界是非常复杂的

    顺便说一句,如果你喜欢这种分形(我喜欢),你一定要看看。它太神奇了


    实现Adobe图像模型的一个流行的C库是,但我将把创建工作程序的任务留给读者作为练习:

    2 copy gecopies
    KochR
    的2个参数(我假设它是一个坐标对)然后,
    ifelse
    根据该真值决定是否执行
    {dup 0 rlineto}
    或另一个块中的语句。
    3div
    将坐标对的y值分为三,使该点沿该轴更靠近原点。
    2copy KochR
    创建坐标对的副本(该坐标对具有三分之一的y剖切或其位置旋转),然后递归使用它们对它们执行相同的操作


    我对函数所做的最好估计是,它从当前点沿传递到
    KochR
    的点的方向绘制一个渐变之字形,将点列表留在操作数堆栈上。程序将几个这样的之字形附加到当前路径,每个都是自己的子路径,然后将它们全部笔划,留下整个路径堆栈上的点列表(一个可能的问题)。

    从上面的程序透视什么是“2拷贝ge{dup 0 rlineto}”正在做什么?实际上我正在尝试将这个程序转换为C?我不是一个常规的post脚本程序员。这里是什么2?如果其他人只是好奇,第一个大写的K是一个错误,应该都是小写的。在修复代码后绘制了一个科赫曲线分形图案(对于这样一个小程序来说很酷)
    What does 3 div do here?
    
    What does the 2 copy KochR statement perform here?
    
    void kochR(double a, double b) {
        if (a >= b) {
            // line from currentpoint to currentpoint+(b,0)
            // ie. line of length b along current x-axis
            rlineto(b, 0);
        } else {
            b /= 3;
            kochR(a, b); // recurse with reduced length
            rotate(60);  // rotate x-axis CCW by 60 degrees
            kochR(a, b);
            rotate(-120); // rotate x-axis CW by 120 degrees
            kochR(a, b);
            rotate(60);
            kochR(a, b);
        }
    }
    
    int main(void) {
        moveto(0,0);
        kochR(27, 81);
        moveto(0, 27);
        kochR(9, 81);
        moveto(0, 54);
        kochR(3, 81);
        moveto(0, 81);
        kochR(1, 81);
        stroke();
    }