自繪Mandelbrot集合(三)
六、Java程序代碼
本節給出Java程序代碼(JavaScript版本見下節)。目前這個程序運行後只能繪出一個全紅的800*600的png格式圖像,並存在c:盤的temp文件夾下,名為"image.png"。如果你的c:盤下還沒有temp文件夾,就請先創建一下。
七、JavaScript程序代碼
要使用HTML內嵌JavaScript程序的朋友則請將下列代碼拷貝粘貼到純文本編輯器中(比如Windows下的Notepad),並存為html文件,可將其命名為「mandelbrot.html」,然後用網路瀏覽器打開。你應該能看到顯示有一個紅色的長方形的頁面。
八、語言相關部分
首先我們解決掉和所使用的計算機語言密切相關,所以在不同語言之間寫法很不同的部分。這些部分和Mandelbrot集合的繪製演算法其實沒什麼關係,屬於相應語言中的特定知識,我在此只稍微提一下,不作詳細解釋。
首先是特定的聲明,包括Java程序中「// (1)可調參數」前面的那些行,以及HTML文件中不包含在和之間段落內(即JavaScript程序部分)的那些行,大多屬於「如果懂這門語言就必定懂為什麼這麼寫」的內容,不多做解釋。除了HTML中的這句
這是可以看作是創建了一塊畫布掛在網頁上,畫布的標識號「id」為「image」。我們將要畫出來的圖像,就是要顯示在這塊畫布上。
然後是兩個版本也都有的「(4)程序入口」部分,程序開始運行時就從這裡進入,注意到JavaScript版本的入口在JavaScript程序部分的最上方,而Java版本則是從函數開始。
和具體繪圖相關的則是第(3)、(9)、(10)部分。
「(3)圖象緩存」部分都是定義了一個圖像緩存。兩種語言的繪圖方式都必須先在緩存中進行,繪完以後才一次性地用「(10)保存圖像」中的函數表現出來。Java版本的函數中的語句
是將圖像保存在「c: emp」文件夾下的image.png文件中,如果把上面語句中的兩個「png」都改成「jpg」,那麼存成的文件就是jpeg格式的。大家可以按自己喜好決定。而JavaScript版本的是將圖像緩存內容表現在剛才說到的標識號為「image」的畫布上,從而讓我們在瀏覽器上看到畫出的圖像。
「(9)在圖像像素(col, row)處畫上顏色rgb」則就是在第四節中提到的點彩畫法,呼叫函數就能在圖像緩存的第col列第row行那個像素上點上顏色代碼為rgb的顏色。關於以整數表示的RGB顏色代碼,我們在談論調色盤時會作較具體的介紹。特別值得提一句的是,如果仔細看程序代碼的話,在兩個版本中,當我們宣稱是在第row行畫點時,我們其實都是在圖像緩存的第IMAGEHEIGHT - row - 1行畫點。
這是因為在數學習慣上,Y軸的方向朝上,越往上縱坐標越大;而在計算機繪圖中,Y軸的方向通常則朝下。所以如果我們真的是在圖像緩存的第row行畫點的話,畫出來的Mandelbrot集合圖像會是上下顛倒的。
上述兩個版本的特定聲明部分,程序入口的第(4)部分以及和具體繪圖相關的第(3)、(9)、(10)部分一直到本文結束都不會再變動,我也不再加解釋。
九、繪圖演算法部分
剩下的(1)、(2)、(5)、(6)、(7)、(8)部分則是和Mandelbrot集合的繪製具體相關部分,如果對比兩個版本,可以發現它們很相似。只是由於兩種語言的對數據類型的處理方式不同,在Java語言中必須顯式地說明每個變數,每個函數的參數以及返回值的數據類型(,等),而在JavaScript語言中則只須作和聲明。相信有一定的計算機編程經驗,但沒有學過這兩種語言的讀者也容易看懂。
在「 (1)可調參數」部分定義了7個參數,以Java版本為例:
前兩個參數先略過,接下去4個參數定義了一個區域坐標,而最後的IMAGEWIDTH則定義了要繪製的圖像的寬度即橫向像素數。讀者可以在任何時候嘗試改變這些參數,尤其是試用本文許多插圖下的區域坐標定義,來驗證是否能繪出和插圖一致的區域的圖像。
「 (2)計算所得參數」中則計算了一些通過在(1)中的參數所計算得到的參數,比如所繪圖像高度,每個像素所代表的在複平面上的正方形的邊長等等。COFFSET和ROFFSET被用在下面要介紹的「(6)計算顏色」函數中,它們的計算公式也許對不熟悉這樣寫法的讀者來說有點奇怪:
可其實這無非是在說,如果IMAGEWIDTH是偶數(等於0的話),那麼COFFSET的值就是;如果IMAGEWIDTH是奇數,那麼COFFSET的值就是,但因為這是整數除法,要去掉餘數,所以結果其實和相同。
「(5)主程序」部分就是第四節中介紹的點彩繪圖原理。兩個針對行和列的循環遍歷圖片上的每個像素,循環體則是兩句無比簡單的呼叫:
第一句用我們將介紹的(6)中的函數來計算每個像素的顏色,再用前面介紹的(9)方法在圖像緩存的對應像素上畫出計算出來的顏色。兩個循環執行後,所有像素都繪製完畢,最後呼叫(10)來表現圖像。
上面提到的(1)、(2)、(5)部分,除了會變動可調參數的數值外,一直到本文結束也不再改變。
本文中我們將要重大修改的則是剩下的(6)、(7)、(8)部分,當然也是關鍵。不過目前看起來它們也簡單得很。仍以Java版本為例。
首先計算了兩個值cx和cy,它們其實就是第col列第row行那個像素所代表的複平面上的正方形的中心點的坐標,計算中用到了前面計算的參數COFFSET、ROFFSET和PIXELSIZE。「有WIDTH長度的線段,其中心點坐標為OX。線段被均勻分成IMAGEWIDTH段,試問第col段的中心點cx是多少?」這是個非常簡單的數學問題,我不作詳細推導了,只需注意「第n段」的n是從0開始算的,最左邊的是第0段。
計算出像素中心點在複平面上的坐標後,我們將用這個坐標代表的複數進行Mandelbrot集合定義中的迭代運算,即呼叫(7)中的函數,然後調用(8)中的調色盤函數來取得對應的顏色。也就是說,這個像素就被它的中心點代表了。
不過目前(7)和(8)中沒什麼具體的東西,無論cx和cy是什麼,最終(6)總是返回十六進位數FF0000,這是紅色的顏色代碼,所以繪出的圖是一片通紅。
枯燥的準備工作終於做完,下面我們將逐步填充和修改(6)、(7)、(8)部分,以達到我們繪製Mandelbrot集合圖像的目的。注意到上面兩個版本的程序的長度都大約是80行,為達到最終程序只有150行的目標,我們只能再填充70行程序。
(待續)
※人為什麼會信仰上帝?
※從空氣中獲取水資源的新方法
※推薦優質公眾號——博科園、天文地理
※吸引力法則——極具吸引力的偽科學
TAG:科學公園 |
※自繪Mandelbrot集合(五)
※自繪Mandelbrot集合(四)
※自繪Mandelbrot集合(六)
※自繪Mandelbrot集合(七)
※自繪Mandelbrot集合(二)
※自繪Mandelbrot集合(一)
※C 集合(Collection)
※Java集合-LinkedList
※Java集合——LinkedList
※Java集合-ArrayList
※Java集合——ArrayList
※Hacking Tools搜羅大集合
※前端數據存儲方案集合(cookie localStorage等)以及詳解(一)
※WidgetLayout:一組繼承於 ViewGroup 的自定義容器集合
※Java集合-HashSet
※最佳cosplay鑒賞!PAX South遊戲展Coser大集合
※《Fate/Apocrypha》第二集,黑方陣營英靈大集合
※傳奇 Logo 大集合,Nike Presto X 「LEGACY」 定製版
※見色起意!Nike Free RN Flyknit跑鞋大集合