VB6 繪製橢圓的相關討論

這篇是原先在 VB研究小站 張貼的文章,全文有很多人參與討論,我只把我的部份整理出來,以利保留參照。
一開始,有使用者問到:怎麼做橢圓的圖形壓?
VB6 本身的 Circle 方法是可以畫正交的橢圓,所以我想使用者會問的,可能是斜的橢圓,所以提供了一個範例位置:


Re: 橢圓
作者: 璉璉 (—.HINET-IP.hinet.net)
日期:   03-23-05 21:46
 
PictureBox.Cicle 就可以畫了
 
如果要畫斜的,可以參考:http://tlcheng.twbbs.org/TLCheng/Basic/vb/vbgdi.htm#VBEllipseEx



結果原提問者是要問如何用 PSet 來畫橢圓。
所以又做了更進一步的回覆:


Re: 橢圓
作者: 璉璉 (—.HINET-IP.hinet.net)
日期:   03-26-05 10:12
 
延續上次加速繪圖的議題
用 PSet 畫的時候,可以計算圖形高、寬 (pixel) 後,直接 1 對 1 mapping ,要用 twips 再把 pixel 座標轉成 twips 座標即可。
為保證不因進位誤差而掉點,可以分別對 x 軸畫一次, y 軸畫一次。 (較美觀)
只要求加速可以只對長軸畫。
 
Re: 橢圓
作者: 璉璉 (—.HINET-IP.hinet.net)
日期:   03-27-05 10:59
 
範圍當然用公式反算,若長軸與直角座標軸平行的橢圓,
當 x = 0 , -y 為 min, +y 為 max
當 y = 0 , -x 為 min, +x 為 max
算法跟上面逐點畫的差不多
 
(長軸與直角座標軸不平行的橢圓要先取得傾斜軸,在頂點座標那個象限分別求出 x, y 微分等於 0 的點)
 
知道 minX, maxX 後,用
.ScaleX 轉成 Pixel 座標,得到 minXp, maxXp ,迴圈用
For iXp = minXp To maxXp
   用 .ScaleX 轉回自定座標 pX,算出 +- pY ,畫兩個點
Next
 
同上,將 minY, maxY 轉成 minYp, maxYp 後,算出 +- pX, pY 畫兩個點。
所以最大動作數 (PSet 呼叫次數) 小於螢幕可視尺寸的兩倍(以矩形為邊框),比如說 1024 * 768 來說,呼叫 PSet 次數必小於 2 (1024 + 768) = 3584 。
 
以瓜大的程式碼來說,呼叫 PSet 次數約為 (1649.99 – (- 1649.99)) / 0.04 * 2 = 164999
 
在電腦上來說,繪圖動作數越少,繪圖效能越高,依此概估,效能可提升 46 倍。
 
這跟前面那篇繪圖加速觀念是一樣的,繪圖動作只作最小必要繪圖。
 
Re: 橢圓
作者: 璉璉 (—.HINET-IP.hinet.net)
日期:   03-28-05 08:26
 
只考慮加速來說,就是只畫必要點
 
起迄範圍 < DC < Wnd <= 螢幕可視範圍 (ex. 1024 * 768)
 
當 Wnd > 螢幕可視範圍時,比如說 PictureBox 很大,就加速而言,螢幕外的不畫,就減低問題複雜度而言,仍然會畫,這時取捨看個人。
 
如何去剪一張圖,你可參考:
陳雪美 譯,「快速 3D 繪圖演算法」,初版,和碩科技文化,臺灣,台北,民國 86 年 4 月。 
 
Re: 橢圓
作者: 璉璉 (—.HINET-IP.hinet.net)
日期:   03-29-05 11:29
 
… 我貼一段程式碼,自己看。註解應該夠多了,看不懂的話,請看得懂得人解釋。
多一段偵測視窗尺寸,強制改用正交,因為放在 DblClick 內,所以可以縮放視窗後,在按兩下看差異。
應該是全部都參數化了,除了 Me … ,可以放到副程式中來傳遞,這樣就可以在畫在 Form/PictureBox/Printer 上。 
[這段程式碼有更新,原帖跳過] 
 
Re: 橢圓
作者: 璉璉 (—.HINET-IP.hinet.net)
日期:   03-29-05 13:07
 
寫的時候沒仔細想,在繪圖時,不需要由 Pixel 轉使用者自訂座標,因為 Mapping 也是有計算量的
直接先求得點數跟 dx, dy 即可。
 
兩個都可以跑啦…
 
調整程式碼如下:
Private Sub Form_DblClick()
‘ x^2/a^2 + y^2/b^2 = c^2,橢圓方程式
a = 4
b = 3
c = 5
 
iColor = RGB(255, 0, 0) ‘ 線的顏色
 
‘ y = 0,長軸頂點座標
xMax = Sqr(c ^ 2 * a ^ 2)
xMin = -xMax
 
‘ x = 0,短軸頂點座標
yMax = Sqr(c ^ 2 * b ^ 2)
yMin = -yMax
 
ax = IIf(xMax > yMax, xMax, yMax) ‘ 座標軸最小必要長
 
With Me
‘ 依視窗大小取得正規化座標系,短軸長 25,正規化指顯示比例 x:y 為 1:1
   .ScaleMode = vbTwips
   xScale = .ScaleWidth / ax / 2
   yScale = .ScaleHeight / ax / 2
   dScale = IIf(xScale < yScale, xScale, yScale)
   xScale = .ScaleWidth / dScale / 2
   yScale = .ScaleHeight / dScale / 2
 
   Me.Scale (-xScale, yScale)-(xScale, -yScale)
 
‘ 最大區間
   xMaxP = .ScaleX((xMax – .ScaleLeft), .ScaleMode, vbPixels)
   xMinP = .ScaleX((xMin – .ScaleLeft), .ScaleMode, vbPixels)
   yMaxP = .ScaleY((yMax – .ScaleTop), .ScaleMode, vbPixels)
   yMinP = .ScaleY((yMin – .ScaleTop), .ScaleMode, vbPixels)
 
‘ 取得 x, y 點數及間距
   nx = Abs(xMaxP – xMinP)
   ny = Abs(yMaxP – yMinP)
   xScale = (xMax – xMin) / nx
   yScale = (yMax – yMin) / ny
   nx = Int(nx)
   ny = Int(ny)
 
‘ 畫上半、下半
   For ip = 0 To nx
      xp = xMin + ip * xScale
      yp = Sqr(Abs(c ^ 2 – xp ^ 2 / a ^ 2) * b ^ 2)
      Me.PSet (xp, yp), iColor
      Me.PSet (xp, -yp), iColor
   Next
 
‘ 畫右半、左半
   For ip = 0 To ny
      yp = yMin + ip * yScale
      xp = Sqr(Abs(c ^ 2 – yp ^ 2 / b ^ 2) * a ^ 2)
      Me.PSet (xp, yp), iColor
      Me.PSet (-xp, yp), iColor
   Next
End With
End Sub


VB研究小站由於 dns 不再續約,迫使站長搬家,導致舊站文章無法再瀏覽,故整理在網誌上以供參考。
 
本篇討論緒承蒙小瓜瓜站長張啟民提供原始文章供摘錄整理,謹致謝忱。
 
註:VB研究小站已轉成立新站:我的資訊盒子:http://www.myinfobox.net/
廣告
Categories: 技術分享 | 發表留言

文章分頁導航

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

在WordPress.com寫網誌.

%d 位部落客按了讚: