From Gossip@caterpillar

Computer Graphics: 樹林與倒影

 

 


這是要介紹的最後一個遞迴繪圖,看起來很複雜,但其實只是程式碼長了一點,實際上並不會比雪花來得複雜,只要弄清楚繪圖順序就可以了。

在這邊只解釋單一樹木的基本繪圖方式,主要分為主幹與支幹的繪製,如下圖所示,其中標號表示頂點的前進順序:


接下來只要在主幹與支幹上不斷的繪製一定比例的相同圖形,就可以完成一顆樹,將這些樹排列起來就成為樹林,詳細的原始碼請看以下的程式,其中註解部份先不 用理會:

  • Forest.java
package onlyfun.caterpillar.graphics.recursive; 

import onlyfun.caterpillar.graphics.Turtle;
import java.awt.*;
import javax.swing.JApplet;

public class Forest extends JApplet {
private Turtle t;
private double ang = 86.0, k1 = 1.5, k2 = 1.0,
Leng = 2.0, k;

public void init() {
t = new Turtle();
k = 1.0/(k1+2*k2+2*(k1+k2)*Math.cos(
Math.toRadians(ang)));

setBackground(Color.black);
}

public void woods(double leng) {
if(leng > Leng) {
// Point p[] = new Point[3];
t.move(leng);
t.warp(-leng);


/* 畫實心倒影

// 畫主幹
t.warp(k*k1*leng);
p[0] = new Point((int)t.LPX, (int)t.LPY);
t.turn(ang);
t.warp(k*k1*leng);
p[1] = new Point((int)t.LPX, (int)t.LPY);
t.turn(-2*ang);
t.warp(k*k1*leng);
p[2] = new Point((int)t.LPX, (int)t.LPY);
t.polygonF(p,3);

// 畫右支幹
t.turn(ang);
t.warp(k*leng);
p[0] = new Point((int)t.LPX, (int)t.LPY);
t.turn(ang);
t.warp(k*k2*leng);
p[1] = new Point((int)t.LPX, (int)t.LPY);
t.turn(-2*ang);
t.warp(k*k2*leng);
p[2] = new Point((int)t.LPX, (int)t.LPY);
t.polygonF(p,3);

// 支幹退回
t.warp(-k*k2*leng);
t.turn(2*ang);
t.warp(-k*k2*leng);
t.turn(-ang);
t.warp(-k*leng);
t.turn(-ang);

// 主幹退回
t.warp(-k*k1*leng);
t.turn(2*ang);
t.warp(-k*k1*leng);
t.turn(-ang);
t.warp(-k*k1*leng);
*/

woods(k*k1*leng);
t.turn(ang);
woods(k*k1*leng);
t.turn(-2*ang);
woods(k*k1*leng);
t.turn(ang);
woods(k*leng);
t.turn(ang);
woods(k*k2*leng);
t.turn(-2*ang);
woods(k*k2*leng);
t.turn(ang);
woods(k*k2*leng);
}
else
t.warp(leng);
}

public void paint(Graphics g) {
g.setColor(Color.yellow);

t.setGraphics(g);

t.window(0, 0, getSize().width, getSize().height);
t.view(0, 0, getSize().width, getSize().height);
t.setpoint(10, getSize().height/2);
t.setangle(0);

woods(400);
}
}



如果將上例程式的註解符號去除,可以繪製樹林的倒影,繪製方法是大同小異,這邊是使用實心圖形來表示倒影,為了繪製實心圖形,在海龜繪圖法中加入繪製實心多邊形的方法polygonF,如下所示:
        public void polygonF(Point tri[], int n) {
            int[] xPoints = new int[n],
                  yPoints = new int[n];
 
            for(int i = 0; i < n; i++) {
                xPoints[i] = tri[i].x;
                yPoints[i] = tri[i].y;
            }
 
            g.fillPolygon(xPoints, yPoints, n);
        }
 

下圖為加上倒影後的繪圖成果:


到目前為止所介紹的遞迴繪圖都是在2D平面上,實際上遞迴繪圖在3D空間中也有相當的應用,不過複雜性也因維度的增加而複雜許多,如果有興趣,建議您研究一下 JAVA 2D/3D繪圖程式設計實例應用 書中的3D遞迴繪圖原始碼。