이번에는 저번 글에 이어 다차원 베지어 곡선을 그리는 방법을 보자, 즉 초기 점의 3개 이상의로된 점으로 된 경로에 대한 배지어 곡선을 그리는 것이다.
지난번과 같은 소스이면 여기 다차원, 즉 여러개의 점을 지원하기 위해 약간 변경되어 있다.
다음 그림은 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)이란

에서 베지어 곡선 수학 공신 관련 링크를 참조하세요

+ Recent posts