2007-10-25 23:31:42 Kenny

任意角度旋轉圖形

來源:cww  VB5.0進階程式開發指南

如果有一個圖範圍如下:

   P1+----------+ P2
    |     |
    |     |
    |     |
    |     |
    |     |
   P3+----------+ P4


我們以P3為軸,順時針轉某個角度,如果是NT的使用者,可以使用PlgBlt()這個API來完
成,如果是Win95那就沒辦法了,這裡也提供 VB5.0進階程式開發指南所用的方法來完成

PlgBlt()的第二個參數是重點,它是指向POINTAPI的一個3個元素之陣列,代表圖形旋轉
之後的三個端點,也就是說順時針轉了某個角度後,P1->P1'  P2->P2'  P3->P3',這陣
列便是存P1' P2' P3'。 所以了,重點在於這三個點的取得,數學不好的我可真痛苦;
如果這三個點沒有設好,那會產生一個變形的圖,原本 PlgBlt()便是用來扭曲圖形用的
,只是那三個點如果設好的話,剛好可以來旋轉圖。

 PlgBlt(
    HDC  hdcDest,	     // handle of destination device context
    CONST POINT *  lpPoint,  // vertices of destination parallelogram
    HDC  hdcSrc,	     // handle of source device context
    int  nXSrc, 	     // x-coord. of upper-left corner of source rect.
    int  nYSrc, 	     // y-coord. of upper-left corner of source rect.
    int  nWidth,	     // width of source rectangle
    int  nHeight,	     // height of source rectangle
    HBITMAP  hbmMask,	     // handle of bitmask
    int  xMask, 	     // x-coord. of upper-left corner of bitmask rect.
    int  yMask		     // y-coord. of upper-left corner of bitmask
 )

需2個Command Button  2個PictureBox,目的在Picture2畫出旋轉圖
Option Explicit
Private Declare Function PlgBlt Lib "gdi32" (ByVal hdcDest As Long, _
	lpPoint As POINTAPI, ByVal hdcSrc As Long, ByVal nXSrc As Long, _
	ByVal nYSrc As Long, ByVal nWidth As Long, ByVal nHeight As Long, _
	ByVal hbmMask As Long, ByVal xMask As Long, ByVal yMask As Long) As Long
Private Type POINTAPI
	x As Long
	y As Long
End Type
Const pi = 3.14159265358979
Dim dThetaDeg As Double
'以下只適用於NT
Private Sub Command1_Click()
Dim pt(1 To 3) As POINTAPI, p4 As POINTAPI
Dim dx As Long, dy As Long
Dim i As Long, offsetX As Long, offsetY As Long
Dim sida As Double
Dim MaxX As Long, MaxY As Long, MinX As Long, MinY As Long

sida = dThetaDeg * pi / 180
dx = Me.ScaleX(Picture1.Picture.Width, vbHimetric, vbPixels)
dy = Me.ScaleX(Picture1.Picture.Height, vbHimetric, vbPixels)
pt(1).x = dy * Sin(sida)
pt(1).y = dy - dy * Cos(sida)
pt(2).x = pt(1).x + dx * Cos(sida)
pt(2).y = pt(1).y + dx * Sin(sida)
pt(3).x = 0: pt(3).y = dy

'p4不用在pt()之陣列,它是由pt(1)-pt(3)所推出
p4.x = pt(3).x + dx * Cos(sida)
p4.y = pt(3).y + dx * Sin(sida)

'以下的工作只是為了讓旋轉後的圖在Picture2的中間顯示
MaxX = IIf(pt(1).x > pt(2).x, pt(1).x, pt(2).x)
MaxX = IIf(MaxX > pt(3).x, MaxX, pt(3).x)
MaxX = IIf(MaxX > p4.x, MaxX, p4.x)
MinX = IIf(pt(1).x < pt(2).x, pt(1).x, pt(2).x)
MinX = IIf(MinX < pt(3).x, MinX, pt(3).x)
MinX = IIf(MinX < p4.x, MinX, p4.x)

MaxY = IIf(pt(1).y > pt(2).y, pt(1).y, pt(2).y)
MaxY = IIf(MaxY > pt(3).y, MaxY, pt(3).y)
MaxY = IIf(MaxY > p4.y, MaxY, p4.y)
MinY = IIf(pt(1).y < pt(2).y, pt(1).y, pt(2).y)
MinY = IIf(MinY < pt(3).y, MinY, pt(3).y)
MinY = IIf(MinY < p4.y, MinY, p4.y)
offsetX = (Picture2.ScaleWidth - MaxX + MinX) \ 2 - MinX
offsetY = (Picture2.ScaleHeight - (MaxY - MinY)) \ 2 - MinY
pt(1).x = pt(1).x + offsetX: pt(1).y = pt(1).y + offsetY
pt(2).x = pt(2).x + offsetX: pt(2).y = pt(2).y + offsetY
pt(3).x = pt(3).x + offsetX: pt(3).y = pt(3).y + offsetY

i = PlgBlt(Picture2.hDC, pt(1), Picture1.hDC, 0, 0, dx, dy, 0, 0, 0)
End Sub

'這個方式不管95/NT都可行,來自vb5程式設計進階指南一書,但速度慢
Private Sub Command2_Click()
    Dim nX As Integer, nY As Integer
    Dim nX1 As Integer, nY1 As Integer
    Dim dX2 As Double, dY2 As Double
    Dim dX3 As Double, dY3 As Double

    Dim dThetaRad As Double

    'Compute angle in radians
    dThetaRad = -dThetaDeg * pi / 180
    'Set scale modes to pixels
    For nX = 0 To Picture2.ScaleWidth
	nX1 = nX - Picture2.ScaleWidth \ 2
	For nY = 0 To Picture2.ScaleHeight
	    nY1 = nY - Picture2.ScaleHeight \ 2
	    'Rotate picture by dThetaRad
	    dX2 = nX1 * Cos(-dThetaRad) + nY1 * Sin(-dThetaRad)
	    dY2 = nY1 * Cos(-dThetaRad) - nX1 * Sin(-dThetaRad)
	    'Translate to center of picture box
	    dX3 = dX2 + Picture1.ScaleWidth \ 2
	    dY3 = dY2 + Picture1.ScaleHeight \ 2
	    'If data point is in picOne, set its color in picTwo
	    If dX3 > 0 And dX3 < Picture1.ScaleWidth - 1 _
		And dY3 > 0 And dY3 < Picture1.ScaleHeight - 1 Then
		Picture2.PSet (nX, nY), Picture1.Point(dX3, dY3)
	    End If
	Next nY
    Next nX
End Sub

Private Sub Form_Load()
Picture1.ScaleMode = 3
Picture2.ScaleMode = 3
'設定旋轉角度
dThetaDeg = 30
Set Picture1.Picture = LoadPicture("e:\cli.bmp")

End Sub