Powerpoint를 도형을 생성하게 되면 아래와 같이 직선 및 곡선 Segment를 조합하여 그림을 그립니다. 직선형인 경우, P1, P2, P3.. 점들은 꼭지점이 되고, 각 꼭지점을 연결한 직선으로 구성이 됩니다. 그러나, 곡선인 경우, P1~P4가 1개의 Bezier 곡선을 그리고, P4~P7이 다음 Bezier 곡선을 그려서 연결하는 방식으로 도형을 만들어 나갑니다. 따라서, 순수한 직선형인 경우, n개의 Segment가 있으면 n+1개 점(node)의 위치 정보만 있으면 되고, 순수한 곡선형인 경우, n개의 Segment를 표현하기 위해 3n-2개 점의 위치 정보가 있으면 되며, 점들의 위치 정보만으로도 도형을 완벽하게 재현해낼 수 있습니다.
그러나, 경우에 따라서는 곡선형 Segment와 직선형 Segment가 연속되어있는 경우도 있으며, 연속된 점들의 정보만으로는 직선인지, 곡선인지 구분할 수 없기 때문에, Segment의 특성을 직선형 또는 곡선형으로 정의해 주어야 합니다. 따라서, 각 점의 위치 정보만으로 도형을 완벽하게 재현하지 못합니다.
곡선형인 경우, P1, P4, P7... 의 점은 Bezier 곡선을 그릴 때, 시작 및 끝점(End point)에 해당하고, 이 점들은 자유형 그림을 그릴 때, 사용자가 마우스로 클릭해주는 위치입니다. P2, P3, P5, P7은 곡선형 도형을 생성할 때 Powerpoint에서 자동으로 삽입해주며, 도형을 클릭해서 '점편집' 메뉴를 이용하여 인위적으로 변경할 수 있습니다. 이 점들은 곡선의 꺾인 정도나 모양을 결정해주는 점들이며 Bezier 곡선의 Control Point라고 합니다.
만약, 곡선형 도형의 점들 중, 3n+1번째 점들만 남겨놓고 나머지 점들을 지워버린다면 P1, P4, P7... 의 정보만 남게 되며, 점들만 선으로 연결하면, 직선형으로 바뀌게 됩니다.
반대로, P1, P2, P3... 의 직선형 도형에 인위적으로 Control Point를 삽입해주면 원하는 형태의 곡선형 도형으로도 바꿔줄 수 있습니다. 예를 들어, Powerpoint에서 원은 마름모 모양으로 배열된 4개의 End point와 원이 될수 있도록 적절한 위치에 Control Point를 삽입해준 형태이며, Control Point를 삭제하게 되면 다시 마름모가 됩니다.
도형의 모든 점들의 위치 정보는 Shape.Vertices 속성으로부터 쉽게 얻을 수 있습니다. 그러나, Vertices 속성은 msoFreedom 형식, 즉 자유형 도형에만 지원하기 때문에 도형 템플릿으로 그린 도형은 바로 구할 수 없습니다. 따라서, 도형이 가진 점들의 위치 정보를 얻기 위해서는 이전 글에서 소개해드린 함수를 이용하여 자유형 도형으로 변환한 후 Shape.Vertices 속성으로 구하게 됩니다.
점에 대한 정보를 구하는 목적은 해당 점들을 이용해서 새로운 도형을 생성하거나, 점을 새로 배치해서 도형을 변형하는 등의 작업을 하기 위해서 입니다. 만약 도형에 점을 추가하고 싶다면, Shape.Nodes.Insert를 사용할 수 있습니다. 직선형이나 곡선형 모두 추가할 수 있고, 점의 위치만 정확하게 지정해주면 됩니다. 1~2개 점은 이런 식으로 추가할 수 있지만, 도형에 포함된 node 갯수가 증가할수록 실행 속도는 점점 느려집니다. 100여개 정도의 점을 추가해주려고 하니 PC 사양에 따라서는 몇 분 이상이 걸리기도 합니다. 따라서, Node가 많은 여러 개의 도형에 대해 작업하려고 한다면, 작업 시간이 매우 느려지는 문제가 있습니다. (freehand 형태의 도형으로 작업하다보면, 포함되는 node 갯수가 많기 때문에, 때로는 Powerpoint가 멈춰버리는 문제도 생깁니다.)
한편, 모든 점들에 대한 정보만 있다면, 직선형인 경우 Slide.Shapes.AddPolyLine(좌표배열), 곡선형인 경우 Slide.Shapes.AddCurve(좌표배열)을 이용하여 한꺼번에 도형을 생성하게 되면 상대적으로 실행속도가 매우 빠른 것을 알 수 있습니다. 따라서, 처리해야할 점의 갯수가 많다면, 점들의 정보를 모두 읽어와서, 이 점들의 정보로부터 새로운 좌표배열을 생성한 후, 완전히 새로운 도형으로 생성하는 것이 속도면에서는 훨씬 빠릅니다. 다만, AddPolyLine이나 AddCurve는 도형의 모든 node가 직선형이거나 곡선형이어야 한다는 제약이 있습니다.
따라서, 도형의 좌표를 읽어올 때, 처음부터 곡선형 좌표 또는 직선형 좌표 배열 형식으로 읽어오도록 함수를 만들어 둡니다.
아래에 도형(Drawing)의 좌표배열을 구하는 함수를 생성해두었습니다. 앞으로 슬라이드에 간단히 생성한 도형을 변형하거나, 배열하는데 있어 이러한 점 좌표 배열을 이용할 예정입니다.
Function GetVertices(iSh As Shape, Optional iDelControl As Boolean = False) As Single()
On Error GoTo ErrorHandler
Dim tSh As Shape, tP() As Single, tPX() As Single, tPY() As Single, i As Long, j As Long, n As Long
If iSh.Type = msoFreeform Then
tP = tSh.Vertices
n = 1
ReDim Preserve tPX(1 To 1): ReDim Preserve tPY(1 To 1)
tPX(1) = tP(1, 1): tPY(1) = tP(1, 2)
If iDelControl Then
For i = 2 To tSh.Nodes.Count
n = n + 1
ReDim Preserve tPX(1 To n): ReDim Preserve tPY(1 To n)
If tSh.Nodes(i).SegmentType = msoSegmentLine Then
tPX(n) = tP(i, 1): tPY(n) = tP(i, 2)
Else
i = i + 2
tPX(n) = tP(i, 1): tPY(n) = tP(i, 2)
End If
Next
ReDim tP(1 To n, 1 To 2)
For i = 1 To n: tP(i, 1) = tPX(i): tP(i, 2) = tPY(i): Next
Else
For i = 2 To tSh.Nodes.Count
n = n + 3
ReDim Preserve tPX(1 To n): ReDim Preserve tPY(1 To n)
If tSh.Nodes(i).SegmentType = msoSegmentLine Then
tPX(n - 2) = tP(i - 1, 1): tPY(n - 2) = tP(i - 1, 2)
tPX(n - 1) = tP(i, 1): tPY(n - 1) = tP(i, 2)
tPX(n) = tP(i, 1): tPY(n) = tP(i, 2)
Else
i = i + 2
tPX(n - 2) = tP(i - 2, 1): tPY(n - 2) = tP(i - 2, 2)
tPX(n - 1) = tP(i - 1, 1): tPY(n - 1) = tP(i - 1, 2)
tPX(n) = tP(i, 1): tPY(n) = tP(i, 2)
End If
Next
ReDim tP(1 To n, 1 To 2)
For i = 1 To n: tP(i, 1) = tPX(i): tP(i, 2) = tPY(i): Next
End If
GetVertices = tP
If Not iSh.Type = msoFreeform Then tSh.Delete
ErrorHandler:
Erase tP, tPX, tPY
End Function