1 / 40

台北總公司/台北縣汐止市新台五路一段 112 號 10 樓 A 棟

書名 Java 於資料結構與演算法之實習應用 書號  PG20098 原著  河西朝雄 著 譯者 周明憲 / 徐堯譯. 台北總公司/台北縣汐止市新台五路一段 112 號 10 樓 A 棟 Building A, 10F, 112, Shin-Tai-Wu Road Sec. 1, Shijr, Taipei, Taiwan. 電話/ 02-26962869  傳真/ 02-26962867 台中辦事處/台中市文心路一段 540 號 4 樓 -1 4-1F, 540, Wen Shing Road, Sec. 1, Taichung, Taiwan.

thad
Download Presentation

台北總公司/台北縣汐止市新台五路一段 112 號 10 樓 A 棟

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 書名 Java於資料結構與演算法之實習應用 書號 PG20098 原著 河西朝雄著 譯者 周明憲/徐堯譯 台北總公司/台北縣汐止市新台五路一段112號10樓A棟 Building A, 10F, 112, Shin-Tai-Wu Road Sec. 1, Shijr, Taipei, Taiwan. 電話/02-26962869 傳真/02-26962867 台中辦事處/台中市文心路一段540號4樓-1 4-1F, 540, Wen Shing Road, Sec. 1, Taichung, Taiwan. 電話/04-23287870 傳真/04-23108168 博碩網址:http://www.drmaster.com.tw

  2. 第八章 學習重點 • 我們導入座標以便將點的位置顯示出來,各點的位置關係如在直線上,則能以1次方程式呈現,各點如位於圓、橢圓、雙曲線、拋物線等曲線上,則能以2次方程式顯示出來。如此一來2維圖形就能以某種方程式(y=f(x))表示出來,因此以運算的方式就能解開圖形問題的解。這種學科稱為解析幾何學,其創始者為迪斯卡提(Rene Descartes) • 若將圖形以方程式表示出來,並以電腦加以解析的話,則以轉換座標方式進行的圖形平行移動、旋轉、放大與縮小等作業就能輕易的做到。此外, 3維空間座標也因而能投影至2維平面。 • 但如要以解析方式將自然界存在的物體,比如複雜的海岸線表示出來還很困難。目前碎形幾何(Fractals)可以表示這種複雜的圖形。這是以遞迴方式將圖形表示出來的方法,又稱為遞迴繪圖(recursive graphics)。

  3. 8-0 Java的繪圖處理 1 座標Java的畫面座標如右圖所示,y軸座標是朝畫面的下方前進。 由於這與數學座標的標示方式不同,因而採用圖8.2所示的座標系統。邏輯座標中的y軸座標朝畫面的上方前進,Java將此邏輯座標上的(WX1,WY1)-(WX2,WY2)區域(視窗)對應至畫面上的(VX1,VY1)-(VX2,VY2)區域(景象埠:view port)。

  4. 1 座標 • 將視窗上的座標(x,y)描繪成景象埠的座標時,可用下列的計算式計算: 視窗的設定 window(x1,y1,x2,y2) 將邏輯座標上的(x1,y1)-(x2,y2)範圍設定成視窗。 景象埠的設定 view(x1,y1,x2,y2) 將景象座標上的(x1,y1)-(x2,y2)範圍設定成景象埠。 …x方向的倍率 …y方向的倍率

  5. 2 Turtle Graphics Library • 下面為畫直線的2個方法: (1) 設起點與終點 (2) 設長度與方向 • Java製作了move、turn等2個method,使第2個方法得以在Java上使用。這個方法也適合用來製作Turtle Graphics。 • 用第2個方法來畫直線時,先要以描繪的目前位置(LPX,LPY)與目前角Angle為基點。

  6. 指定長度的直線 move(1) 從目前位置(LPX,LPY)起朝目前角Angle的方向畫長度為l的直線。 至指定位置的直線 move(x,y) 從目前位置(LPX,LPY)起畫直線到(x,y)。 描繪(目前角)方向的設定 setangle(a) 將目前角設定成a[°]。 目前位置的指定 setpoint(x,y) 將目前位置移至(x,y)。 描繪(目前角)方向的旋轉 turn(a) 將目前角旋轉a[°]。旋轉後的目前角修補成在0~360°之內。

  7. 8-1 move與turn • 例題56 多角形描繪正三角形~正九角形 只要如圖將move(1);turn(120); 執行3次,就可畫出正三角形。 畫正n角形時的旋轉角度為360/n[°]。

  8. ……………… class Rei56Panel extends Panel { public void paint(Graphics g) { Turtle t=new Turtle(g); int n,j; for (n=3;n<=9;n++) { t.setpoint(150,100); t.setangle(0); for (j=1;j<=n;j++) { t.move(80); t.turn(360.0/n); } } } }

  9. 練習問題56 螺旋圖案 • 反覆執行move與turn,並同時慢慢的縮減直線的長度 • 將turn的角度設為a,逐漸縮減的長度設為step,然後反覆執行move與turn,直至直線的長度等於10。 • 改變step與a的值,就能畫出不同的圖形。

  10. ……… class Dr56Panel extends Panel { public void paint(Graphics g) { Turtle t=new Turtle(g); double leng=200, // 邊的初始值 step=1, // 邊的減少值 a=89; // 旋轉角 t.setpoint(100,100); t.setangle(0); while (leng>10) { t.move(leng); t.turn(a); leng=leng-step; } } } …………

  11. 8-2 2維座標轉換 • 某點(x0, y0)經過各種轉換後,其各點(x, y)可分別以下列方式求出。 • 對稱移動對著與y軸平行的直線x=a進行對稱移動,則 相反的,若對著與x軸平行的直線進行對稱移動,則

  12. 旋轉移動 將點(x0, y0)旋轉θ,則 平行移動 將點(x0, y0)往x軸及y軸方向分別平行移動m與n,則 放大、縮小 將點(x0, y0)的x軸方向放大k倍,y軸方向放大1倍,則

  13. 例題57 對稱移動 • mirror的flag若為1,則對著x=m進行對稱移動,若flag為0,則對著y=m進行對稱移動。 void mirror(int flag,double m,double[] dat) { // 對稱移動 int i; for (i=1;i<=2*dat[0];i=i+2) { // dat[0]為資料數量 if (flag==1) // y軸中心 dat[i]=2*m-dat[i]; if (flag==0) // x軸中心 dat[i+1]=2*m-dat[i+1]; } } void draw(double[] dat) { // 描繪圖形 int i; t.setpoint(dat[1],dat[2]); // 起點 for (i=3;i<=2*dat[0];i=i+2) // dat[0]為資料數量 t.moveto(dat[i],dat[i+1]); } public void paint(Graphics g) { t=new Turtle(g); double[] a={11,0,80,5,75,17,80,20,60,15,55,0,55, 0,20,10,40,20,40,10,20,0,20}; t.window(-160,-160,160,160); t.view(0,0,400,400); draw(a); mirror(1,0.0,a);draw(a); mirror(0,0.0,a);draw(a); mirror(1,0.0,a);draw(a); }

  14. 練習問題57 旋轉移動 void rotate(double deg,Point p) { // 旋轉轉換 double dx,dy,rd=3.14159/180; dx=p.x*Math.cos(deg*rd)-p.y*Math.sin(deg*rd); dy=p.x*Math.sin(deg*rd)+p.y*Math.cos(deg*rd); p.x=(int)dx;p.y=(int)dy; } public void paint(Graphics g) { t=new Turtle(g); int j,k,n=5; Point[] p={new Point(0,0),new Point(100,0), new Point(100,200),new Point(0,200), new Point(0,0)}; t.window(-200,-200,200,200); t.view(0,0,400,400); for (j=0;j<12;j++) { for (k=0;k<n;k++) { multi(.8,.8,p[k]); rotate(30,p[k]); if (k==0) t.setpoint(p[k].x,p[k].y); else t.moveto(p[k].x,p[k].y); } } } 設有長方形的4點座標,對此長方形進行旋轉轉換與放大/縮小轉換作業,並將結果顯示出來

  15. 8-3 幾何繪圖 • 例題58 對稱圖案以三角形的重心為中心,再將基本圖形旋轉,反覆製作同樣的圖案 • 美麗的幾何圖案很乍見之下極為複雜,但這些圖案實際上是由基本的圖形(直線、多角形等)反覆製作而成的,具有協調性與規律性。 • 以正三角形的重心為中心,將基本圖形旋轉2次,每次均旋轉120°。由此作業產生的圖案會被收斂至正三角形之內,而形成1個新的圖形。皆下來將這個三角形圖形的倒立圖橫向描繪,如此反覆操作。

  16. public void paint(Graphics g) { Turtle t=new Turtle(g); final int N=9; // 資料數 final double rd=3.14159/180; // 弧度 double x[]={35,19,10,3,0,-3,-10,-19,-35}, y[]={-20,-20,-5,-5,0,-5,-5,-20,-20}; int a,b,j,k; double m,h,vy,vx,px,py; m=70;h=m*Math.sqrt(3.0)/2; // 正三角形的邊的長度、高度 t.window(-m/2,-h/3,m/2,h*2/3); b=1; for (vy=20;vy<=330;vy=vy+h) { a=1; for (vx=50;vx<=500;vx=vx+m/2) { t.view((int)vx,(int)vy,(int)(vx+m),(int)(vy+h)); // 景象 for (j=0;j<3;j++) { for (k=0;k<N;k++) { px=x[k]*Math.cos(120*j*rd)-y[k]*Math.sin(120*j*rd); py=x[k]*Math.sin(120*j*rd)+y[k]*Math.cos(120*j*rd); if (a*b==-1) py=-py+h/3; // 逆像修補 if (k==0) t.setpoint(px,py); else t.moveto(px,py); } } a=-a; } b=-b; } } 正三角形的重心為將三角形的高h劃分成2:1的點。而描繪的範圍則設為 因此在製作逆像時,不只要將y座標的符號反轉過來,而且還要進行h/3的修正。 此外還使用旗標a與b,以便正像與逆像能夠一再交互產生。

  17. 8-4 3維座標轉換 • 圖8.18中有1個直方體,我們即使以與z軸平行的平行光線投射至直方體的x-y平面上,也只會出現如圖8.19之(a)所示的長方形,看起來沒有立體的感覺。若將y軸旋轉β°,然後以平行光線照射至x-y平面上,則會出現如圖8.19的(b)所示的圖形,若將x軸旋轉α°,然後以平行光線照射至x-y平面上,則會出現如圖8.19的(c)所示的看起來有立體感覺的圖形。 • 將平行光線投射至x-y平面上的投影作業稱為軸測投影,執行下列2個基本作業後,就可製圖了。

  18. (1) 將立體物以y軸、x軸、z軸為軸心旋轉 旋轉角的正方向設為面對各軸正方向的順時鐘方向,y軸、x軸、z軸旋轉的角度則分別設為α、β、γ。旋轉的順序若設為y軸→x軸→z軸,則點(x,y,z)會轉換成: 設y軸的旋轉為β 設x軸的旋轉為α 設z軸的旋轉為γ (2) 將在以上的旋轉中所得到的座標平行的投射在z=0平面(x-y平面)上。 這並不難做到,因為將上面的結果(x3,y3,z3)中的忽略掉,即表示將光線平行投射到z=0平面上。 因此(1)的計算式中的與也就可以省略,並能簡化成下列的計算式: 投射至x-y平面的點的座標

  19. 例題59 軸測投影 • 設有1幢房子的資料,將此房子以軸測投影顯示出來。房子的各點的資料存在如下所示的陣列內。 dat[0].f=-1:dat[0].x=80:dat[0].y=50:dat[0].z=100 dat[0].f= 1:dat[1].x= 0:dat[1].y=50:dat[1].z=100 α=45° β=-45° γ=0° α=20° β=-45° γ=0° α=45° β=-45° γ=0°

  20. void rotate(double ax,double ay,double az, double x,double y,double z,Point p) { double x1,y1,z1,x2,y2; x1=x*Math.cos(ay)+z*Math.sin(ay); // x軸的旋轉 y1=y; z1=-x*Math.sin(ay)+z*Math.cos(ay); x2=x1; // y軸的旋轉 y2=y1*Math.cos(ax)-z1*Math.sin(ax); p.x=(int)(x2*Math.cos(az)-y2*Math.sin(az)); // z軸的旋轉 p.y=(int)(x2*Math.sin(az)+y2*Math.cos(az)); }

  21. 練習問題59 透視 • 軸測投影是對著投影面投射平行光線,而透視則如圖8.20所示,對著某點投射集中的光線。這點稱為投影中心(消失點),為了使透視轉換能夠更容易操作,我們將此點設在z軸上。 • 在透視中,與投影中心相對的立體位置如有不同,則立體的感覺就不同,立體物若位於投影中心的上方,則透視的結果如同俯視立體物,反之,則透視的結果如同仰視立體物。 • 因此在透視中,除了將立體物旋轉的動作外,還加上了平行移動的操作。一般而言,看透視圖時,為了讓物體看起來很立體,只要旋轉y軸即可,不須旋轉x、y、z等3軸。

  22. 以下的計算式為透視的轉換計算式,為了簡化起見,旋轉時僅將y軸旋轉β?,並將x、y、z方向的平行移動量設為l、m、n,將投影中心社為z=-vp。轉換後的點則設為透視成z=0平面(x-y平面)的點。以下的計算式為透視的轉換計算式,為了簡化起見,旋轉時僅將y軸旋轉β?,並將x、y、z方向的平行移動量設為l、m、n,將投影中心社為z=-vp。轉換後的點則設為透視成z=0平面(x-y平面)的點。 先進行旋轉與平行移動作業,則 再將其透視成z=0平面,則 這種透視為2點透視,為最常用的方法。當β=0時,則為單點透視(圖8.21)

  23. double ay=-35*3.14159/180, // y軸的旋轉角度 vp=-300.0, // 投影中心 l=-25.0, // x方向的移動量 m=-70.0, // y方向的移動量 n=0.0, // z方向的移動量 h,px,py; int k; t.window(-150,-150,150,150); t.view(0,0,400,400); for (k=0;a[k].f!=-999;k++) { // 透視轉換 h=-a[k].x*Math.sin(ay)/vp+a[k].z*Math.cos(ay)/vp+n/vp+1; px=(a[k].x*Math.cos(ay)+a[k].z*Math.sin(ay)+1)/h; py=(a[k].y+m)/h; if (a[k].f==-1) t.setpoint(px,py); else t.moveto(px,py); }

  24. 8-5 立體模型 立體圖形中比較容易製作的圖形有:錐狀體、柱狀體與旋轉體。 產生錐狀體所需的資料為底面各點的座標(x1,y1)、(x2,y2)、...(xn,xn)與投射至頂點的x-z平面的投影點(xc,xc)與高h。 產生柱狀體所需的資料為底面各點的座標(x1,y1)、(x2,y2)、...(xn,xn)與高h。 如要產生旋轉體,可將圖中a~h所示的2維圖形中的y軸旋轉即可。 若已知道各點的y座標與y軸的距離(半徑)r,則各點繞著y軸旋轉θ?時的座標如下: 我們是可以將這點旋轉轉換(以軸測投影所示的計算式進行),但光描繪a~h的旋轉軌跡,僅能單純的畫出8個橢圓,根本看不出有立體的感覺。因此我們將 連接a→b→c...h的直線(稜線)按某個旋轉角度分別畫在數個位置上。

  25. class Rei60Panel extends Panel { void rotate(double ax,double ay,double az, double x,double y,double z,Point p) { double x1,y1,z1,x2,y2; x1=x*Math.cos(ay)+z*Math.sin(ay); // y軸的旋轉 y1=y; z1=-x*Math.sin(ay)+z*Math.cos(ay); x2=x1; // x軸的旋轉 y2=y1*Math.cos(ax)-z1*Math.sin(ax); p.x=(int)(x2*Math.cos(az)-y2*Math.sin(az)); // z軸的旋轉 p.y=(int)(x2*Math.sin(az)+y2*Math.cos(az)); } public void paint(Graphics g) { Turtle t=new Turtle(g); int n,k; final double rd=3.14159/180; double x,z,px,py,ax,ay,az; double[] y={180,140,100,60,20,10,4,0,-999}, // 高度 r={100,55,10,10,10,50,80,80,-999}; // 半徑 Point p=new Point(0,0); ax=35*rd; ay=0*rd; az=20*rd; t.window(-250,-250,250,250); t.view(0,0,400,400);

  26. for (k=0;(int)y[k]!=-999;k++) { // y軸的旋轉軌跡 for (n=0;n<=360.0;n=n+10) { x=r[k]*Math.cos(n*rd); z=r[k]*Math.sin(n*rd); rotate(ax,ay,az,x,y[k],z,p); if (n==0) t.setpoint(p.x,p.y); else t.moveto(p.x,p.y); } } for (n=0;n<=360;n=n+60) { // 稜線 for (k=0;(int)y[k]!=-999;k++) { x=r[k]*Math.cos(n*rd); z=r[k]*Math.sin(n*rd); rotate(ax,ay,az,x,y[k],z,p); if (k==0) t.setpoint(p.x,p.y); else t.moveto(p.x,p.y); } }

  27. 8-6 陰線處理 前面已說明過將房子的資料以3維方式顯示的方法,而使用這種方法需要各頂點的資料,如要顯示複雜的立體物也需要大量的資料。 接下來我們將這種3維函數列出如下: 由於這項函數是以計算式的形式顯示,因此不需要用到資料,不用花太多心力就能畫出複雜的圖案。

  28. public void paint(Graphics g) { Turtle t=new Turtle(g); final double rd=3.1415927/180; double x,y,z,px,py,ax,ay; ax=30*rd; ay=-30*rd; t.window(-300,-200,300,200); t.view(0,0,600,400); for (z=-200;z<=200;z=z+10) { for (x=-200;x<=200;x=x+5) { y=30*(Math.cos(Math.sqrt(x*x+z*z)*rd) // 3維函數 +Math.cos(3*Math.sqrt(x*x+z*z)*rd)); px=x*Math.cos(ay)+z*Math.sin(ay); // 旋轉轉換 py=y*Math.cos(ax)-(-x*Math.sin(ay) +z*Math.cos(ay))*Math.sin(ax); if ((int)x==-200) t.setpoint(px,py); else t.moveto(px,py); } }

  29. 練習問題61 max‧min法 • 陰線處理是指將隱藏在面的後方之見不到的線消除之作業。 • 陰線處理的方法有很多種,本書使用非常簡單的max‧min法。 • 如圖8.29所示,以max‧min法描繪圖形時,一定要從面向自己的一方開始畫起,而且這之後所描繪的點若位於之前所描繪的點群(位於與螢幕畫面同一x座標前的點群)的最大點與最小點之間(點群的內側),則不顯示該點,反之若位於這些點群之外,則顯示該點。

  30. public void paint(Graphics g) { Turtle t=new Turtle(g); int[] ymin=new int[600],ymax=new int[600]; int k,px,py; final double rd=3.1415927/180; double x,y,z,ax,ay; ax=30*rd; ay=-30*rd; t.window(0,0,600,500); t.view(0,0,600,500); for (k=0;k<600;k++) { // 判定最大點與最小點的函數 ymin[k]=600;ymax[k]=0; } for (z=200;z>=-200;z=z-10){ for (x=-200;x<=200;x++){ y=30*(Math.cos(Math.sqrt(x*x+z*z)*rd) // 3維函數 +Math.cos(3*Math.sqrt(x*x+z*z)*rd)); px=(int)(x*Math.cos(ay)+z*Math.sin(ay)+300); // 旋轉轉換 py=(int)(y*Math.cos(ax)-(-x*Math.sin(ay) +z*Math.cos(ay))*Math.sin(ax)+250); if (py<ymin[px]) { // 比目前的最小點還小 ymin[px]=py;t.pset(px,py); } if (py>ymax[px]) { // 比目前的最大點還大 ymax[px]=py;t.pset(px,py); } }

  31. 8-7 遞迴繪圖Ⅰ • 單純的曲線(n次函數)能在座標系統中以解析的方式表示出來,也就是說若使用f(x)函數可將某一曲線表示出來的話,在某點x=x0中的f(x)就能以f(x0)求出來。 • 不過,曲線的型態越複雜就越不易以1個函數來表示整個曲面。因此就有近似方法的產生,這種方法將整個曲面分割成數塊小區域,再以解析的方式求出各小區域的f(x),其種類有spline曲線、最小平方近似與線段(segment)法。 • 將茂盛的樹木、複雜的出海口等自然界的物體以解析方式表示出來,是一件很麻煩(應該說近乎不可能)的事。 • 因此不以解析方式將圖案表示出來,而改以遞迴方式將圖案表現出來,這種繪圖方式稱為遞迴繪圖。這種繪圖方法引人入勝的地方在於,其可輕易的表示出接近自然的圖案,也令人產生科學能夠闡明自然與生命的神秘美之錯覺(也許不久以後就不是錯覺)。 • 自然界的生物在最初成行的階段都是1個細胞,然後經過無數次細胞的反覆分裂而成長,再形成現在的模樣。這種過程與遞迴顯示相當類似。換句話說,這種過程可以說是因為「n次的細胞(現在的模樣)是由n-1次的細胞所形成,n-1次的細胞則是由n-2次的細胞所形成......」的緣故。隨著0次細胞的模樣與成長的規則(+突變)的定義之不同,即可得到各種不同的物種。

  32. 描繪科赫曲線 • 科赫曲線是由數學家科赫(H.von Koch)所發現的,如圖8.30所示,0次的科赫曲線為長度為l的直線。1次的科赫曲線為1邊的長為l/3大的正三角形狀的角。2次的科赫曲線相對於1次科赫曲線的各邊(4個),為l/9大的正三角形狀。若無限的反覆操作下去,就成為由無數條的無限小長度的線條所組成的曲線。 • 描繪n次科赫曲線的演算法之大致內容為,如要描繪n次科赫曲線,則要按下面方式描繪4個n-1次的科赫曲線。這裡將科赫曲線的1邊的長度一直固定為leng。 (1)描繪1個n-1次的科赫曲線 (2)將角度改成60度,描繪1個n-1次的科赫曲線 (3)將角度改成-120度,描繪1個n-1次的科赫曲線 (4)將角度改成60度,描繪1個n-1次的科赫曲線

  33. class Rei62Panel extends Panel { private Turtle t; void koch(int n,double leng) { // 科赫遞迴的動作程序 if (n==0) { t.move(leng); } else { koch(n-1,leng); t.turn(60); koch(n-1,leng); t.turn(-120); koch(n-1,leng); t.turn(60); koch(n-1,leng); } } public void paint(Graphics g) { t=new Turtle(g); int n=4; // 科赫曲線的次數 double leng=4.0; // 0次的長度 t.setpoint(50,200); t.setangle(0); koch(n,leng); } }

  34. 練習問題62-1 科赫島 void koch(int n,double leng) { // 科赫遞迴的動作程序 if (n==0) { t.move(leng); } else { koch(n-1,leng); t.turn(60); koch(n-1,leng); t.turn(-120); koch(n-1,leng); t.turn(60); koch(n-1,leng); } } public void paint(Graphics g) { t=new Turtle(g); int i,n=4; // 科赫次數 double leng=4.0; // 0次的長度 t.setpoint(30,300); t.setangle(0); for (i=0;i<3;i++) { koch(n,leng); t.turn(-120); } } • 將3個科赫曲線以-120°的角度連接起來,就形成1個白雪結晶狀的科赫島圖案。

  35. 練習問題62-2 十字繡 • 科赫曲線是以正三角形為基礎,而十字繡圖形則是以正方形為基礎。十字繡圖形的繪圖原理與科赫曲線相同,如要描繪n次的十字繡圖形,則只須描繪5個描n-1次的十字繡圖形即可,描繪的角度則按+90°、-90 ° 、-90 ° 、+90 °的順序操作。 // 十字繡圖形的遞迴動作程序 public void stech(int n,double leng) { if (n==0) t.move(leng); else { stech(n-1,leng);t.turn(-90); stech(n-1,leng);t.turn(90); stech(n-1,leng);t.turn(90); stech(n-1,leng);t.turn(-90); stech(n-1,leng); } } public void paint(Graphics g) { t=new Turtle(g); int k,n=4; // 十字繡圖形的次數 double leng=2; // 0次的長度 t.setpoint(100,150);t.setangle(0); for (k=1;k<=4;k++) { stech(n,leng); t.turn(90); } }

  36. 8-8 遞迴繪圖Ⅱ • 描繪樹木曲線 樹木曲線的描繪規則如下: ‧ 0次的樹木曲線為長度為l的直線 ‧ 1次的樹木曲線為2支長度為l/2的分支,兩線的夾角為90° ‧ 2次的樹木曲線為2支長度為l/4的分支,兩線的夾角為90 ° 樹木的分支共有4支。 此外分支的縮小率、伸展角度不一定非得1/2與90 °不可。

  37. 樹木曲線之描繪演算法 n次的樹木曲線之描繪演算法的大致內容如下: (1)從(x0,y0)位置起以角度a畫出長度為leng的分支,並將畫好以後的終點座標設為新的(x0,y0)位置 (2)將n-1次的右邊的樹遞迴呼叫出來 (3)將n-1次的左邊的樹遞迴呼叫出來

  38. void tree(int n,double x0,double y0,double leng,double angle) { if (n==0) return; t.setpoint(x0,y0);t.setangle(angle); t.move(leng); x0=t.LPX;y0=t.LPY; // 取得現在位置 tree(n-1,x0,y0,leng/scale,angle-branch); tree(n-1,x0,y0,leng/scale,angle+branch); } public void paint(Graphics g) { t=new Turtle(g); int n; double x0,y0,leng,angle; n=8; // 分支的次數 x0=200.0;y0=50.0; // 根的位置 leng=100.0; // 分支的長度 angle=90.0; // 分支的角度 scale=1.4; // 分支的伸展率 branch=20.0; // 分支的分歧角 tree(n,x0,y0,leng,angle); }

  39. 練習問題63 樹木曲線II • 描繪樹木曲線時也可以用正方形來取代直線。 • 如圖8.39所示,在正方形的分支中以45?的角度描繪出的子正方形分支。 • 如圖8.40所示,以位置為起點,按(1)→(2)→(3)→(4)的順序描繪正方形。移到右邊分支後的新位置為: • 此外,由於右邊的分支返回時的主幹的位置為、角度為angle、長度為leng,因此從此點移到左邊分支後的新位置為:

  40. void ctree(int n,double x0,double y0,double leng,double angle) { final double rd=3.14159/180; int k; if (n==0) return; t.setpoint(x0,y0);t.setangle(angle); for (k=1;k<=4;k++) { // 描繪正方形 t.turn(90); t.move(leng); } // 右邊分支 ctree(n-1,x0+leng*Math.cos((angle-45)*rd)/Math.sqrt(2.0), y0+leng*Math.sin((angle-45)*rd)/Math.sqrt(2.0), leng/Math.sqrt(2.0),angle-45); // 左邊分支 ctree(n-1,x0+Math.sqrt(2.0)*leng*Math.cos((angle+45)*rd), y0+Math.sqrt(2.0)*leng*Math.sin((angle+45)*rd), leng/Math.sqrt(2.0),angle+45); } public void paint(Graphics g) { t=new Turtle(g); int n=9; // 分支的次數 double x0=0.0,y0=0.0, // 根的位置 leng=50.0, // 分支的長度 angle=90.0; // 分支的角度 t.window(-200,-200,200,200); t.view(0,0,400,400); ctree(n,x0,y0,leng,angle); }

More Related