지난번과 같은 소스이면 여기 다차원, 즉 여러개의 점을 지원하기 위해 약간 변경되어 있다.
다음 그림은 2차원 베지어 곡선이다. 직선이 2개인 경로에 대한 베지어 곡선을 그린 예이다.
다음 이미지는 베지어 곡선을 그려 나가는 중
다음 이미지는 3차원 곡선에 대한 베지어 곡선을 그리기 위한 초기 화면이다.
다음 이미지는 3차원 경로에 대한 베지어 곡선을 그려 나가는 이미지이다.
다음 이미지는 다차원 경로에 대한 베지어 곡선을 그리기 위한 초기 화면으로 8개의 점으로 된 경로이다.
다차원 경로에 대한 베이저 곡선을 그려나가는 이미지
다차원 곡선에 대한 완료된 베지어 곡선을 그린 이미지이다.
여기서 한가지 베지어 곡선에서 경로의 시작점은 베지어 곡선의 시작점이 되고, 경록의 마지막 점은 베지어 곡선도 마지막 점이 된다.
다음은 소스이다.
Option Explicit ' 모든 변수는 선언된 뒤에 사용 할 수 있다.
Option Base 1
Private Const XPoint = 1 ' 점 위치의 X좌표 첨자
Private Const YPoint = 2 ' 점 위치의 Y좌표 첨자
Private Const StartDotNumber = 3 ' 시작점 수
Private Const AddPercent = 0.01 ' 변경 비율
Private HarfDot As Long ' 점의 반지름
Private DotPoint() As Long ' 현재 점의 위치
Private Dimension() As Long ' 각 차수 시작 첨자
Private DotBezier() As Long ' 베지어 곡선 좌표
Private SelectDot As Long ' 현재 마우스로 선택된 점의 인덱스 번호
Private Sub CreatePoint(ByVal index As Long) ' 점을 생성한다.
With picClient
DotPoint(XPoint, index) = Rnd(1) * .Width
DotPoint(YPoint, index) = Rnd(1) * .Height
End With
End Sub
Private Function GetDimension(ByVal index As Long) As Long ' 점의 어떤 차원의 점인지를 얻는다
For GetDimension = UBound(Dimension) To 1 Step -1
If index >= Dimension(GetDimension) Then Exit For
Next GetDimension
End Function
Private Sub DisplayPoint(ByVal index As Long) ' 점을 표시한다.
Dim LoadConffirm As Boolean ' 표시하기 위한 점 컨트롤이 로드된 컨트롤인지 확인
On Error Resume Next
LoadConffirm = shpPoint(index).Visible
If Err.Number > 0 Then Load shpPoint(index) ' 에러라면 로드하지 않은 컨트롤
On Error GoTo 0
With shpPoint(index)
.BackColor = QBColor(GetDimension(index))
.Left = DotPoint(XPoint, index) - HarfDot
.Top = DotPoint(YPoint, index) - HarfDot
.Visible = True
End With
End Sub
'
Private Sub DrawLine(ByVal index As Long, ByVal Befor As Boolean, ByVal Clear As Boolean) ' 점과 점을 잊는 선을 그린다.
Dim x2 As Long ' 연결할 점의 좌표
Dim y2 As Long
x2 = DotPoint(XPoint, index + IIf(Befor, -1, 1)) ' 연결할 점의 좌표를 얻는다.
y2 = DotPoint(YPoint, index + IIf(Befor, -1, 1))
picClient.Line (DotPoint(XPoint, index), DotPoint(YPoint, index))-(x2, y2), IIf(Clear, picClient.BackColor, QBColor(GetDimension(index)))
End Sub
Private Function CursorInDot(ByVal x As Long, ByVal y As Long) As Long ' 커서가
For CursorInDot = GetDotNumber To 1 Step -1
If DotPoint(XPoint, CursorInDot) - HarfDot <= x And DotPoint(XPoint, CursorInDot) + HarfDot >= x And _
DotPoint(YPoint, CursorInDot) - HarfDot <= y And DotPoint(YPoint, CursorInDot) + HarfDot >= y Then
Exit For
End If
Next CursorInDot
End Function
Private Function GetDotNumber() As Long ' 점 수
GetDotNumber = UBound(DotPoint, 2)
End Function
Private Sub cmdStart_Click() ' 시작
timProcess = True
cmdStart.Enabled = False
End Sub
Private Function GetLastIndexInDimension(Dimen As Long) As Long ' 차원의 마지막 점의 인덱스 -1
If UBound(Dimension) = Dimen Then
GetLastIndexInDimension = GetDotNumber - 1
Else
GetLastIndexInDimension = (Dimension(Dimen + 1) - 1) - 1
End If
End Function
Private Sub Form_Load()
Dim forDotCounter As Long ' 점 카운터
Randomize ' 난수 발생기를 초기화 한다
HarfDot = shpPoint(0).Width / 2 ' 점의 반지름
ReDim Dimension(1) ' 1차원
ReDim DotPoint(YPoint, StartDotNumber) ' 포인터가 저장될 배열의 초기화
Dimension(1) = 1 ' 1차원 포인터의 시작 첨자
picClient.AutoRedraw = True
For forDotCounter = 1 To StartDotNumber ' 점을 생성한다.
CreatePoint forDotCounter
Next forDotCounter
For forDotCounter = 1 To StartDotNumber ' 점을 표시한다.
DisplayPoint forDotCounter
Next forDotCounter
For forDotCounter = 2 To StartDotNumber ' 점과 점을 잇는 직선을 그린다.
DrawLine forDotCounter, True, False
Next forDotCounter
End Sub
Private Sub picClient_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
If Not Button = vbLeftButton Then Exit Sub ' 왼쪽 버튼일때만 처리
SelectDot = CursorInDot(x, y) ' 선택된 점 지정
End Sub
Private Sub picClient_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single) ' 점 이동시
Dim forDotCounter As Long ' 점 카운터
Me.MousePointer = IIf(CursorInDot(x, y) = 0, vbDefault, vbCrosshair)
If Not Button = vbLeftButton Or SelectDot = 0 Then Exit Sub ' 왼족 버튼과, 점을 선택한경우만 처리
If Not SelectDot = GetDotNumber Then
DrawLine SelectDot, False, True
End If
If Not SelectDot = 1 Then
DrawLine SelectDot, True, True
End If
DotPoint(XPoint, SelectDot) = x
DotPoint(YPoint, SelectDot) = y
DisplayPoint SelectDot
For forDotCounter = GetDotNumber - 1 To 1 Step -1
DrawLine forDotCounter, False, False
Next
End Sub
Private Sub picClient_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
SelectDot = 0
End Sub
Private Sub timProcess_Timer() ' 베지어 곡선을 그린다
Static T As Double ' 비율
Static Bx As Long ' 이전 베지어 곡선 마지막 좌표
Static By As Long ' 이전 베지어 곡선 마지막 좌표
Dim CurrentDimension As Long ' 현재 차운
Dim ForPointerCounter As Long ' 현재 포인터 인덱스
Dim LastPointIndex As Long ' 현재 차원의 마지막 점의 인덱스-1
Dim NextDimensionDotIndex As Long ' 현재 직선에 대한 다음 차원의 점 인덱스 번호
timProcess.Enabled = False
If T >= 1 Then ' 비율 계산, 및 초기화
Exit Sub
Else
T = T + AddPercent
labRateValue.Caption = Format(T, "0.00")
CurrentDimension = 1
ForPointerCounter = 1
End If
Do
If Not UBound(Dimension) = CurrentDimension Then ' 새로운 차원이 첨이 생긴 경우, 이전에 그렸던 직선을 지우기 위함
LastPointIndex = GetLastIndexInDimension(CurrentDimension + 1)
For ForPointerCounter = Dimension(CurrentDimension + 1) To LastPointIndex
DrawLine ForPointerCounter, False, True
Next ForPointerCounter
End If
LastPointIndex = GetLastIndexInDimension(CurrentDimension)
For ForPointerCounter = Dimension(CurrentDimension) To LastPointIndex
If ForPointerCounter = Dimension(CurrentDimension) And UBound(Dimension) = CurrentDimension Then
ReDim Preserve Dimension(CurrentDimension + 1)
Dimension(CurrentDimension + 1) = GetDotNumber + 1
End If
NextDimensionDotIndex = Dimension(CurrentDimension + 1) + (ForPointerCounter - Dimension(CurrentDimension))
If GetDotNumber < NextDimensionDotIndex Then ReDim Preserve DotPoint(YPoint, NextDimensionDotIndex)
DotPoint(XPoint, NextDimensionDotIndex) = DotPoint(XPoint, ForPointerCounter) + (DotPoint(XPoint, ForPointerCounter) - DotPoint(XPoint, ForPointerCounter + 1)) * T * -1
DotPoint(YPoint, NextDimensionDotIndex) = DotPoint(YPoint, ForPointerCounter) + (DotPoint(YPoint, ForPointerCounter) - DotPoint(YPoint, ForPointerCounter + 1)) * T * -1
DisplayPoint NextDimensionDotIndex
Next
CurrentDimension = CurrentDimension + 1 ' 다음 차원
For ForPointerCounter = 1 To GetDotNumber - 1
If GetDimension(ForPointerCounter) = GetDimension(ForPointerCounter + 1) Then
DrawLine ForPointerCounter, False, False
End If
Next
Loop While Not GetDotNumber - Dimension(CurrentDimension) = 0 ' 마지막 차원의 점이 하나일 때까지 반복
' 이전 이벤트의 마지막 점과, 현재의 마지막 점을 연결하여 베지어 곡선을 그린다
If T = AddPercent Then
ReDim DotBezier(YPoint, 1)
DotBezier(XPoint, 1) = DotPoint(XPoint, 1)
DotBezier(YPoint, 1) = DotPoint(YPoint, 1)
End If
ReDim Preserve DotBezier(YPoint, UBound(DotBezier, 2) + 1)
DotBezier(XPoint, UBound(DotBezier, 2)) = DotPoint(XPoint, GetDotNumber)
DotBezier(YPoint, UBound(DotBezier, 2)) = DotPoint(YPoint, GetDotNumber)
For ForPointerCounter = UBound(DotBezier, 2) To 2 Step -1
picClient.Line (DotBezier(XPoint, ForPointerCounter), DotBezier(YPoint, ForPointerCounter))-(DotBezier(XPoint, ForPointerCounter - 1), DotBezier(YPoint, ForPointerCounter - 1)), vbRed
Next ForPointerCounter
timProcess.Enabled = True
End Sub
위 소스의 공식은 베지어 곡선을 그리는 방법이 이런것이다를 표시하기 위해 베지어 곡선을 구하는 공식을 각 단계별로 풀어서 사용했다고 보시면 됩니다. 따라서 속도는 느립니다. 빠른 속도를 원핫시면 베지어 곡선을 구하는 공식이 있읍니다. 그 공식을 적용하시면 빠른 곡선을 그리실수 있읍니다.
베지어 곡선(bezie-curve)이란에서 베지어 곡선 수학 공신 관련 링크를 참조하세요
'VB6' 카테고리의 다른 글
ActiveX DLL 프로젝트와 EXE 프로젝트를 같은 그룹 프로젝트에 추가하면 (0) | 2011.09.20 |
---|---|
DLL의 클래스의 폼에 텍스트 박스에 입력한 값을 클래스의 개체를 생성한 모듈에 전달 (0) | 2011.09.19 |
베지어 곡선 그리기(1차 곡선) (0) | 2011.09.18 |
vb6에서 정규식으로 문자열을 찾자. (0) | 2011.09.16 |
소수를 분수로 바꾸기 (0) | 2011.09.16 |