VBA 로 곡선을 그릴 때
1. BuildFreeform으로 시작 좌표를 초기화한 후
2. AddNodes로 직선이나 곡선 좌표를 계속 추가하여 그립니다.
AddNodes에 대한 MS도움말의 설명이 자세하지 않고 친절하지 않습니다.
심지어 파워포인트 도움말은 맞는데 엑셀과 워드 도움말에는 아직도 마지막 인수인 X3,Y3가 조절점좌표라는 틀린 설명이 들어가 있습니다.
이에 좀 더 설명도 필요하고 눈에 보이는 예시가 절실히 요구됩니다.
먼저 이해하기위해 필요한 기본적인 용어입니다.
아래 그림을 기준으로 AddNodes 로 새로 추가되는 선 조각을 Segment (세그먼트) 라고 부르고 왼쪽에 첫번째 조절점(제어점)1과 오른쪽에 두번째 제어점(조절점)2가 필요합니다. 2차원 베지어 곡선의 형태입니다. 참고로 TTF폰트 는 2차원 베지어 곡선형태이고 OTF 폰트는 3차원 곡선이라 더 정교하다고 합니다.
AddNodes 는 두 가지 선 노드를 추가하는데 직선 세그먼트를 추가하거나 곡선 세그먼트를 추가합니다.
AddNodes로 세그먼트의 노드를 추가할 때 시작점은 인수로 넘기지 않습니다. 이전 세그먼트의 끝점이 새 세그먼트의 시작점이 됩니다. 처음 시작시에는 BuildFreeformBuilder로 초기화한 시작 좌표가 출발 좌표가 됩니다.
직선을 추가할 때는 간단히 새 세그먼트의 끝점의 좌표만 인수로 넘기면 됩니다.
곡선을 추가할 때 좀 더 복잡합니다. 새 세그먼트 시작점(부분)에 대한 첫번째 조절점, 그리고 끝점(부분)에 대한 두번째 조절점, 마지막으로 끝점의 x,y좌표가 인수로 넘겨집니다. 조절점의 각도가 커질수록, 길이가 멀어질수록 곡선이 휘는 강도는 강해집니다.
간단한 설명은 이것으로 갈무리하고 이제 .AddNodes에 대한 전반적인 매뉴얼(설명)입니다.
기존 MS의 도움말이 제대로 설명하고 있지 않아 많은 수정을 거친 내용입니다. 아직 수정할 부분이 있을 수 있습니다.
.AddNodes 메서드는 FreeformBuilder 개체 ( Shapes.BuildFreeform 메서드로 반환됨) 에 점 (노드) 을 추가하여 자유형 도형을 정의하는 데 사용됩니다. 기본적인 문법 규칙은 다음과 같습니다. FreeformBuilderObject.AddNodes SegmentType, EditingType, X1, Y1, [X2], [Y2], [X3], [Y3] 각 매개변수에 대한 설명은 다음과 같습니다. * FreeformBuilderObject: 필수 항목입니다. FreeformBuilder 개체입니다. * SegmentType: 필수 항목입니다. 새로 추가할 세그먼트의 유형을 지정하는 MsoSegmentType 상수 중 하나입니다. 가능한 값은 다음과 같습니다. ** msoSegmentCurve: 이전 노드와 지정된 끝점 사이에 곡선 세그먼트를 추가합니다. 이 유형을 사용하는 경우 X2, Y2, X3, Y3 매개변수를 지정해야 합니다. 특히 마지막 인수로 넘어오는 좌표가 새 세그먼트 끝점의 좌표가 됩니다. ** msoSegmentLine: 이전 노드와 지정된 끝점 사이에 직선 세그먼트를 추가합니다. 이 유형을 사용하는 경우 X1, Y1 매개변수만 필요합니다. * EditingType: 필수 항목입니다. 세그먼트의 편집점을 지정하는 MsoEditingType 상수 중 하나입니다. 가능한 값은 다음과 같습니다. ** msoEditingCorner: 세그먼트가 꼭짓점을 가집니다. 곡선 세그먼트의 경우 두 개의 제어점(조절점)이 지정됩니다. ** msoEditingSmooth: 세그먼트가 부드러운 연결을 가집니다. 이전 세그먼트의 조절점과 새 세그먼트의 조절점이 (직선으로) 부드럽게 연결되도록 기존의 제어점이 계산되어 부드러운 곡률을 유지합니다. ** msoEditingAuto: 세그먼트의 편집 유형이 자동으로 결정됩니다.(Curve Segment 일 경우도 끝점 좌표만 지정하면 되고 두 제어점을 인수로 추가할 필요가 없습니다.) 인수로 추가되는 Node 좌표 설명: Segment가 직선(msoSegmentLine)인 경우: * X1: 필수 항목입니다. 새로운 세그먼트의 끝점의 가로 좌표 (단위: 포인트) 를 지정하는 Single 형식의 값입니다. * Y1: 필수 항목입니다. 새로운 세그먼트의 끝점의 세로 좌표 (단위: 포인트) 를 지정하는 Single 형식의 값입니다. 예시: FreeformBuilderObject.AddNodes msoSegmentLine, msoEditingAuto, 100, 200 ( 초기화된 시작점에서 출발하여 x=100, y=200 위치를 끝점으로 하는 직선을 그림) Segment가 곡선(msoSegmentCurve)인 경우: 만약 EditingType이 msoEditingAuto인 경우 인수의 마지막 좌표가 새 세그먼트 끝 점의 좌표가 되고 다른 인수는 필요가 없게 됩니다. 그 외 EditingType이 msoEditiongCorner 등인 경우입니다 *일단 '세그먼트'란 직선이나 곡선의 기본 단위로 '선 조각'의 개념입니다. • X1: msoEditingCorner등인 경우에 새 세그먼트의 왼쪽(첫번째) 조절점(제어점)의 가로x좌표. 첫 번째 베지어 곡선 제어점의 가로 좌표 (단위: 포인트) 를 지정하는 Single 형식의 값입니다. EditingType이 msoEditingSmooth인 경우에 이 제어점과 기존 세그먼트의 마지막 제어점이 (길이는 변하지 않지만) 직선을 이루도록 각도가 자동 조절될 수 있습니다. EditingType이 msoEditingSymmetric인 경우 기존 제어점과 대칭되도록 길이와 각도가 자동으로 조절될 수 있습니다. • Y1: msoEditingCorner등인 경우에는 새 세그먼트의 왼쪽(첫번째) 조절점(제어점)의 세로y좌표. 첫 번째 베지어 곡선 제어점의 세로 좌표 (단위: 포인트) 를 지정하는 Single 형식의 값입니다. EditingType이 msoEditingSmooth인 경우에 이 제어점과 기존 세그먼트의 마지막 제어점이(길이는 변하지 않지만) 직선을 이루도록 각도가 자동 조절될 수 있습니다. EditingType이 msoEditingSymmetric인 경우 기존 제어점과 대칭되도록 길이와 각도가 자동으로 조절될 수 있습니다. * X2: msoEditingCorner등인 경우에 새 세그먼트의 오른쪽(두 번째) 베지어 곡선 제어점의 가로x 좌표 (단위: 포인트) 를 지정하는 Single 형식의 값입니다. EditingType이 msoEditingSmooth인 경우에 다음에 추가될 제어점에 의해 자동으로 조절될 수 있습니다. EditingType이 msoEditingSymmetric인 경우 다음 세그먼트의 첫번째 제어점에 영향을 줄 수 있습니다. * Y2: msoEditingCorner등인 경우에 새 세그먼트의 오른쪽(두 번째) 베지어 곡선 제어점의 세로y 좌표 (단위: 포인트) 를 지정하는 Single 형식의 값입니다. EditingType이 msoEditingSmooth인 경우에 다중에 추가될 제어점에 의해 자동으로 조절될 수 있습니다. EditingType이 msoEditingSymmetric인 경우 다음 세그먼트의 첫번째 제어점에 영향을 줄 수 있습니다. * X3: msoEditingCorner등인 경우에 새 세그먼트 끝 점의 x 좌표. 조절점 좌표가 생략된 경우 인수의 마지막 좌표가 끝점의 좌표로 사용됨. * Y3: msoEditingCorner등인 경우에 새 세그먼트 끝 점의 y 좌표. 조절점 좌표가 생략된 경우 인수의 마지막 좌표가 끝점의 좌표로 사용됨. 요약: * 직선 세그먼트를 추가할 때는 msoSegmentLine을 사용하고 EditingType은 msoEditingAuto만 사용하고 끝점 (X1, Y1)만 지정합니다. * 곡선 세그먼트를 추가할 때는 msoSegmentCurve를 사용하며, EditingType에 따라 필요한 제어점 좌표가 달라집니다. ** msoEditingAuto: 끝점 (X1, Y1)만 지정하면 편집 유형이 자동으로 결정됩니다. 제어점은 자동으로 추가됩니다. ** msoEditingCorner: 끝점 (X3, Y3)과 양쪽 두 개의 제어점 (X1, Y1), (X2, Y2)를 지정합니다. 두 제어점들은 이전 세그먼트나 다음 세그먼트의 제어점과 관계없는 독립적인 제어점 역할을 합니다. ** msoEditingSmooth: 끝점 (X3, Y3)과 양쪽 두 개의 제어점 (X1, Y1), (X2, Y2)를 지정합니다. 특히 X1, Y1 에 의해 이전 세그먼트의 오른쪽 두번째 제어점이 X1, Y1 제어점과 직선이 되도록 각도가 자동으로 조절될 수 있습니다. ** msoEditingSymmetric: 끝점 (X3, Y3)과 양쪽 두 개의 제어점 (X1, Y1), (X2, Y2)를 지정합니다. 특히 X1, Y1 에 의해 이전 세그먼트의 오른쪽 두번째 제어점이 X1, Y1 제어점과 대칭이 되도록 각도와 길이가 자동으로 조절될 수 있습니다. 자유형 도형은 일련의 연결된 세그먼트로 구성되므로, .AddNodes 메서드를 여러 번 호출하여 원하는 복잡한 형태의 도형을 만들 수 있습니다. 각 .AddNodes 호출은 이전 노드의 끝점을 시작점으로 하여 새로운 세그먼트를 추가합니다. BuildFreeform 메서드의 초기 시작점이 첫 번째 세그먼트의 시작점이 됩니다. AddNodes가 종료되면 .ConverToShape로 일반 도형으로 변환해야 합니다. |
예시1. 슬라이드 왼쪽 상단에서 오른쪽 하단으로 이어지는 직선 추가
Sub addNodes_Sample()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!
Set sld = ActiveWindow.Selection.SlideRange(1) '현재 슬라이드
'슬라이드 가로, 세로 크기
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
'FreeformBuilder초기화
Set ff = sld.Shapes.BuildFreeform(msoEditingAuto, 0, 0)
'직선 노드 추가
ff.AddNodes msoSegmentLine, msoEditingAuto, SW, SH
'도형으로 변환
ff.ConvertToShape.Name = "Freeform 1"
End Sub
AddNodes 명령을 우리말로 표현하자면 노드추가, 직선으로, 조절점 자동, 끝점의 x,y좌표 의 순서(의미)입니다.
먼저 BuildFreeform 으로 우선 시작 좌표를 초기화한 다음
AddNodes로 다음 좌표를 추가하는 방식입니다.
직선이거나 단순 곡선일 때는 좌표세트를 한 개만 추가하면 됩니다.
SegmentType을 Curve 로 지정하면 직선처럼 보이지만 곡선 조절점(제어점)이 추가됩니다.
SW는 슬라이드의 넓이 (960pt)이고 SH는 슬라이드의 높이 (480pt)입니다.
EditingType을 msoEditingSmooth 혹은 msoEditingCorner 나 msoEditingSymmetric 으로 하고 시작 제어점(조절점) 좌표를 슬라이드 왼쪽 아래 끝으로 지정하면 아래 빨간색 곡선처럼 더 아래로 휘어진 곡선이 그려집니다.
이 때 아래 빨간 곡선의 경우 ff.AddNodes msoSegmentCurve, msoEditingCorner, 0, SH, SW, 0, SW, SH 로 조절점을 두 개 지정할 수 있습니다.
첫번째 조절점은 새 세그먼트의 시작점의 조절점을 왼쪽 하단(0, SH)으로 설정하고
두번째 조절점은 새 세그먼트의 끝 점의 조절점을 상단 오른쪽(SW, 0)으로 설정해서 아래와 같은 곡선이 그려집니다.
이 경우 msoEditingAuto 외의 Corner, Smooth, Symmetric 등 나머지 옵션은 효과가 모두 같아 같은 곡선을 그려줍니다.
msoEditingAuto는 특히 곡선이 계속 이어질 때 진가를 발휘합니다.
Set ff = sld.Shapes.BuildFreeform(msoEditingAuto, 0, 0)
ff.AddNodes msoSegmentCurve, msoEditingAuto, SW / 2, SH / 2
ff.AddNodes msoSegmentCurve, msoEditingAuto, 0, SH
위 처럼 곡선 2개를 이어 그릴 때 msoEditingAuto로 설정하면 조절점이 자동으로 추가됩니다.
왼쪽 상단에서 출발해서 슬라이드 화면 중앙으로 갔다가 다시 왼쪽 아래로 가는 곡선인데 조절점이 자동으로 추가되었습니다.
EditingType이 Symmetric 인 경우 이전 세그먼트의 조절점과 대칭된 조절점을 만들어줍니다.
아래의 경우 시작점인 0,0 인데 이경우 조절점도 시작점의 좌표와 동일합니다.
이제 화면 중앙을 끝점으로 하는 새 세그먼트가 추가되는데 시작 조절점이 화면 왼쪽 끝과 대칭으로 오른쪽 상단 끝으로 지정되었습니다.
또한 EditingType이 Smooth 인 경우 이전 조절점과 이후 조절점이 일직선으로 연계되어 묶입니다.
Symmetric과 Smooth 는 서로 비슷한데 다른 점은
Symmetric 의 경우는 이전 세그먼트의 조절점과 거리까지 똑같게 대칭되게 만들지만
Smooth 인 경우 이전 조절점과 직선으로만 만들고 좌표와의 거리는 달라도 허용합니다.
Smooth인 경우 예시 하나 더 참고하세요.
아래의 경우 조절점을 화면 넓이의 1/4 아래 지점과 3/4 오른쪽 위 지점으로 지정하면 두 조절점이 서로 대각선 방향으로 대칭되도록 만들어줍니다. 한쪽 조절점을 움직이면 반대쪽 조절점도 따라서 움직입니다.
이 때 위 코드에서 Smooth 를 Corner로 바꾸면 모양은 똑같은데
Smooth 인 경우 양쪽 조절점이 연결되어 직선으로 움직이지만
Corner 인 경우에는 아래처럼 해당 조절점만 독립적으로 조절할 수 있는 분리된 조절점을 가진 곡선으로 만들어집니다.
말 그대로 Corner 즉, 꼭지점을 갖을 수 있는 EditingType입니다.
반대로 각이 없는 부드러운 연결을 원한다면 Smooth EditingType을 사용해야겠습니다.
이렇듯 EditingType인 Corner(모서리), Smooth(부드럽게), Symmetric(대칭)은 이전 세그먼트의 조절점과의 관계를 나타냅니다.
특히 아래와 같은 경우 EditingType 에 따라 똑같은 조절점과 좌표를 사용하더라도 파란색 Smooth Type 곡선은 부드러운 곡선이 이어지게 되고 빨간색 Corner Type의 경우는 모서리가 있는 곡선이 생성됩니다. EditingType 에 따라 완전히 다른 모양의 곡선이 생성될 수 있습니다.
만약 조절점을 모두 알고 있다면 일반적인 경우 EditingType은 대개 Corner를 사용해도 됩니다.
조절점 좌표가 생략된 경우에는 자동으로 추가되지만
뒤에 추가되는 세그먼트의 EditingType과 조절점 좌표에 따라 이전 세그먼트의 조절점 좌표가 영향을 받아서 달라질 수 있습니다.
이제 실제로 여러가지 모양을 그리는 예시를 들어보겠습니다.
😎 하트 그리기:
Sub Sample_DrawHeart()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!
Set sld = ActiveWindow.Selection.SlideRange(1)
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
Set ff = sld.Shapes.BuildFreeform(msoEditingCorner, SW / 2, SH * 2 / 9)
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW * 10 / 16, 0, SW, SH * 3 / 9, SW / 2, SH
ff.AddNodes msoSegmentCurve, msoEditingCorner, 0, SH * 3 / 9, SW * 6 / 16, 0, SW / 2, SH * 2 / 9
With ff.ConvertToShape
.Line.ForeColor.RGB = rgbGreen
.Line.Weight = 2
.Fill.Visible = msoFalse
.Name = "Heart 1"
End With
End Sub
주) 여기서는 수식(숫자)를 간단히 하기 위해 슬라이드를 16*9칸으로 나누고 각 블럭을 기준으로 모양을 만드는 설정입니다.
😎 원 그리기: 특히 kappa 상수를 이용
Sub Sample_Circle()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!, KP!
Set sld = ActiveWindow.Selection.SlideRange(1)
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
' 원을 베지어 곡선으로 근사하는 데 사용되는 상수 (kappa : 0.5522847498)
KP = 4 * (Sqr(2) - 1) / 3
KP = SH / 2 * KP '반지름 * kappa상수
Set ff = sld.Shapes.BuildFreeform(msoEditingCorner, SW / 2, 0)
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 + KP, 0, SW / 2 + SH / 2, SH / 2 - KP, SW / 2 + SH / 2, SH / 2
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 + SH / 2, SH / 2 + KP, SW / 2 + KP, SH, SW / 2, SH
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 - KP, SH, SW / 2 - SH / 2, SH / 2 + KP, SW / 2 - SH / 2, SH / 2
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 - SH / 2, SH / 2 - KP, SW / 2 - KP, 0, SW / 2, 0
With ff.ConvertToShape
.Line.ForeColor.RGB = rgbGreen
.Line.Weight = 2
.Fill.Visible = msoFalse
.Name = "Circle 1"
End With
End Sub
정확히 동그란 원을 그릴 때 조절점의 각도는 수직으로, 길이는 kappa 상수값(약 0.55)을 원의 반지름과 곱한 길이로 지정합니다.
😎 타원 그리기:
Sub Sample_Oval()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!, KP!
Set sld = ActiveWindow.Selection.SlideRange(1)
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
' 원을 베지어 곡선으로 근사하는 데 사용되는 상수 (kappa : 0.5522847498)
KP = 4 * (Sqr(2) - 1) / 3
KP = SH / 2 * KP '반지름 * kappa상수
'타원의 경우 KP값에 16/9비율을 곱해줌.
Set ff = sld.Shapes.BuildFreeform(msoEditingCorner, SW / 2, 0)
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 + KP * 16 / 9, 0, SW, SH / 2 - KP, SW, SH / 2
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW, SH / 2 + KP, SW / 2 + KP * 16 / 9, SH, SW / 2, SH
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 - KP * 16 / 9, SH, 0, SH / 2 + KP, 0, SH / 2
ff.AddNodes msoSegmentCurve, msoEditingCorner, 0, SH / 2 - KP, SW / 2 - KP * 16 / 9, 0, SW / 2, 0
With ff.ConvertToShape
.Line.ForeColor.RGB = rgbGreen
.Line.Weight = 2
.Fill.Visible = msoFalse
.Name = "Oval 1"
End With
End Sub
화면을 가득 채우는 타원의 넓은 쪽의 조절점의 길이는 화면이 16:9여서 원래 kappa값에 16/9를 곱해 늘려주었습니다.
😎 물결 모양 그리기:
Sub Sample_Wave()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!
Set sld = ActiveWindow.Selection.SlideRange(1)
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
Set ff = sld.Shapes.BuildFreeform(msoEditingCorner, 0, SH / 9)
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW * 6 / 16, -SH * 2 / 9, SW * 12 / 16, SH / 2, SW, SH / 9
ff.AddNodes msoSegmentLine, msoEditingCorner, SW, SH * 8 / 9
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW * 12 / 16, SH + SH * 2 / 9, SW * 6 / 16, SH / 2, 0, SH * 8 / 9
ff.AddNodes msoSegmentLine, msoEditingCorner, 0, SH / 9
With ff.ConvertToShape
.Line.ForeColor.RGB = rgbGreen
.Line.Weight = 2
.Fill.Visible = msoFalse
.Name = "Wave 1"
End With
End Sub
여기서도 화면을 16*9개의 블럭으로 나누고 블럭 한 개를 기준으로 모양을 생성합니다.
😎 눈물 방울 그리기:
Sub Sample_TearDrop()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!, KP!, R!
Set sld = ActiveWindow.Selection.SlideRange(1)
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
KP = 4 * (Sqr(2) - 1) / 3
R = SH * 5 / 9 / 2 '반지름
KP = KP * R 'kappa상수
Set ff = sld.Shapes.BuildFreeform(msoEditingCorner, SW / 2, 0)
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW * 9 / 16, SH / 2, SW / 2 + R, SH / 2, SW / 2 + R, SH - R
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 + R, SH - R + KP, SW / 2 + KP, SH, SW / 2, SH
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 - KP, SH, SW / 2 - R, SH - R + KP, SW / 2 - R, SH - R
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW / 2 - R, SH / 2, SW * 7 / 16, SH / 2, SW / 2, 0
With ff.ConvertToShape
.Line.ForeColor.RGB = rgbOrange
.Line.Weight = 2
.Fill.Visible = msoFalse
.Name = "TearDrop 1"
End With
End Sub
화면을 16*9개의 블럭으로 나눴을 때 아래 원의 지름은 5칸(세로 길이의 5/9)으로 설정했습니다.
😎 둥근 네모 그리기:
Sub Sample_RoundedRectangle()
Dim sld As Slide
Dim ff As FreeformBuilder
Dim SW!, SH!, KP!, R!, BK!, BR!, BRs!
Set sld = ActiveWindow.Selection.SlideRange(1)
With ActivePresentation.PageSetup
SW = .SlideWidth: SH = .SlideHeight
End With
KP = 4 * (Sqr(2) - 1) / 3
R = SH / 9 / 2 '반지름
KP = KP * R 'kappa상수
BK = SW / 16 '블럭 한 칸
BR = BK * 9 / 16 '곡률
BRs = BK - BR
Set ff = sld.Shapes.BuildFreeform(msoEditingCorner, BK, 0)
ff.AddNodes msoSegmentLine, msoEditingCorner, SW - BK, 0
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW - BRs, 0, SW, BRs, SW, BK ' 우상
ff.AddNodes msoSegmentLine, msoEditingCorner, SW, SH - BK
ff.AddNodes msoSegmentCurve, msoEditingCorner, SW, SH - BRs, SW - BRs, SH, SW - BK, SH ' 우하
ff.AddNodes msoSegmentLine, msoEditingCorner, BK, SH
ff.AddNodes msoSegmentCurve, msoEditingCorner, BR, SH, 0, SH - BRs, 0, SH - BK ' 좌하
ff.AddNodes msoSegmentLine, msoEditingCorner, 0, BK
ff.AddNodes msoSegmentCurve, msoEditingCorner, 0, BRs, BRs, 0, BK, 0 ' 좌상
With ff.ConvertToShape
.Line.ForeColor.RGB = rgbOrange
.Line.Weight = 2
.Fill.Visible = msoFalse
.Name = "Rounded Rectangle 1"
End With
End Sub
둥근 곡률은 블럭 한칸으로 설정했고 조절점의 길이는 블럭 한 칸의 9/16로 설정했습니다.
마지막으로 현재 선택된 Freeform 도형의 모든 노드의 좌표를 알고 싶을 때
좌표값을 간단한 정수로 Ctrl-G 디버그창에 출력하는 코드입니다.
😎 Freeform 내부의 모든 노드 좌표 확인:
Sub ListFreeformNodes()
Dim oShape As Shape
Dim i As Integer
Dim j As Integer
' 현재 선택된 도형이 있는지 확인합니다.
On Error Resume Next
If ActiveWindow.Selection.Type = ppSelectionNone Then
MsgBox "자유형 도형을 선택해주세요.", vbExclamation
Exit Sub
End If
On Error GoTo 0
' 선택된 도형이 자유형 도형인지 확인합니다.
Set oShape = ActiveWindow.Selection.ShapeRange(1)
If oShape.Type <> msoFreeform Then
MsgBox "선택된 도형은 자유형 도형이 아닙니다.", vbExclamation
Exit Sub
End If
' 자유형 도형의 각 노드 정보를 출력합니다.
Debug.Print "도형 이름: " & oShape.Name
Debug.Print "총 노드 수: " & oShape.Nodes.Count
On Error Resume Next
For i = 1 To oShape.Nodes.Count
With oShape.Nodes.Item(i)
Dim editType$
If .EditingType = msoEditingAuto Then
editType = "Auto"
ElseIf .EditingType = msoEditingCorner Then
editType = "Corner"
ElseIf .EditingType = msoEditingSmooth Then
editType = "Smooth"
ElseIf .EditingType = msoEditingSymmetric Then
editType = "Symmetric"
End If
Debug.Print "--- 노드 " & i & " ---" _
; "NodeType: " & editType & " , SegmtType: "; .SegmentType & "(" & IIf(.SegmentType = msoSegmentLine, "Line", "Curv") & ")"
Debug.Print " Point " & ": X=" & Round(.Points(1, 1)) & ", Y=" & Round(.Points(1, 2))
End With
Next i
End Sub
예시: 위의 예시 중 물결 도형의 경우 출력 결과
슬라이드 크기 960* 480pt 에서 화면을 16*9 칸으로 나눠서 그린 상황입니다.
도형 이름: Wave 1 총 노드 수: 8 --- 노드 1 ---NodeType: Auto , SegmtType: 1(Curv) Point : X=0, Y=60 --- 노드 2 ---NodeType: Corner , SegmtType: 1(Curv) Point : X=360, Y=-120 --- 노드 3 ---NodeType: Corner , SegmtType: 1(Curv) Point : X=720, Y=270 --- 노드 4 ---NodeType: Corner , SegmtType: 1(Curv) Point : X=960, Y=60 --- 노드 5 ---NodeType: Corner , SegmtType: 0(Line) Point : X=960, Y=480 --- 노드 6 ---NodeType: Corner , SegmtType: 1(Curv) Point : X=720, Y=660 --- 노드 7 ---NodeType: Corner , SegmtType: 1(Curv) Point : X=360, Y=270 --- 노드 8 ---NodeType: Corner , SegmtType: 1(Curv) Point : X=0, Y=480 |
* 노드1이 왼쪽 상단 출발점.
* Curve를 그릴 경우 처음 설명에 나온 것처럼 조절점1, 조절점2, 끝 좌표 순으로 3가지 노드를 가집니다.
노드2가 새 세그먼트 시작점의 조절점, 노드3이 새 세그먼트 끝점의 조절점 그리고
노드4가 새 세그먼트 끝점의 좌표입니다.
* Line을 그릴 경우는 그전 세그먼트의 끝 좌표에서 출발하므로 노드 5 끝 지점 좌표 하나만 필요합니다.
(편집화면에는 직선의 양쪽 끝에도 조절점이 보이지만 직선을 그릴 때 조절점 노드를 추가할 필요는 없습니다.)
* 다시 노드 6부터 3개의 Curve 노드가 이어지고
마지막에 원점으로 돌아오게 됩니다. ( 마지막 Line Segment가 생략됨)
덧붙여, 필요할지 모르겠지만
화면상의 Freeform 도형를 .AddNodes 명령을 이용해서 화면에 그리도록 하는 VBA코드를 생성해주는 코드입니다.
😎 Freeform 도형의 Node좌표를 VBA 식 .AddNodes명령으로 변환하는 코드:
Sub DebugFreeformNodes()
Dim shp As Shape, sld As Slide
Dim x1!, y1!, c1x!, c1y!, c2x!, c2y!, x2!, y2!
Dim i As Long, j As Long, k As Long
Dim ff As FreeformBuilder
On Error Resume Next
Set shp = ActiveWindow.Selection.ShapeRange(1)
On Error GoTo 0
If shp Is Nothing Then MsgBox "Freeform 도형을 선택하세요.": Exit Sub
If shp.Type <> msoFreeform Then MsgBox "Freeform 도형을 선택하세요.": Exit Sub
Set sld = shp.Parent
Debug.Print "Sub Draw()"
Debug.Print "Dim shp as shape, sld as slide, ff as FreeformBuilder"
Debug.Print "Set sld = ActiveWindow.Selection.SlideRange(1)"
'Freeform 초기화
With shp.Nodes(1)
Debug.Print "Set ff = sld.Shapes.BuildFreeform(msoEditingAuto, " & .Points(1, 1) & "," & .Points(1, 2) & ")"
End With
i = 2
Do While i <= shp.Nodes.Count
If shp.Nodes(i).SegmentType = msoSegmentCurve Then
x1 = shp.Nodes(i - 1).Points(1, 1)
y1 = shp.Nodes(i - 1).Points(1, 2)
c1x = shp.Nodes(i).Points(1, 1)
c1y = shp.Nodes(i).Points(1, 2)
c2x = shp.Nodes(i + 1).Points(1, 1)
c2y = shp.Nodes(i + 1).Points(1, 2)
x2 = shp.Nodes(i + 2).Points(1, 1)
y2 = shp.Nodes(i + 2).Points(1, 2)
Debug.Print "ff.AddNodes msoSegmentCurve, msoEditingCorner, " & c1x & "," & c1y & "," & _
c2x & "," & c2y & "," & x2 & "," & y2
i = i + 3
'ElseIf shp.Nodes(i).SegmentType = msoSegmentLine
Else
' 직선 세그먼트의 끝점 추가
x1 = shp.Nodes(i - 1).Points(1, 1)
y1 = shp.Nodes(i - 1).Points(1, 2)
x2 = shp.Nodes(i).Points(1, 1)
y2 = shp.Nodes(i).Points(1, 2)
Debug.Print "ff.AddNodes msoSegmentLine, msoEditingAuto, " & x2 & "," & y2
i = i + 1
End If
k = k + 1
Loop
Debug.Print "With ff.ConvertToShape"
Debug.Print ".Line.Weight = 2"
Debug.Print ".Line.ForeColor.RGB = rgbTeal"
Debug.Print ".Name = ""Freeform " & k & """"
Debug.Print "End With"
Debug.Print "End Sub"
End Sub
예를 들어 나*키 로고 Freeform 도형을 선택하고 DebugFreeformNodes를 실행하면
아래처럼 직접 실행창에 VBA코드로 만들어줍니다.
좌표 숫자는 슬라이드 크기와 해상도에 따라 달라질 수 있습니다.
이 코드를 실행하면 화면에 해당 로고를 그려줍니다.
😎 배트맨 로고 예시:
😎 위의 모든 내용을 포함한 샘플 파일 첨부합니다.
다음에는 기존 곡선이나 직선 Freeform 도형을 지그재그 물결곡선으로 만드는 방법과
기존 Freeform 곡선을 일정한 길이로 연결된 직선으로 변환하는 방법을 다룰까 합니다.
'PPT+VBA' 카테고리의 다른 글
선택된 슬라이드 내 하이퍼링크 일괄 수정 (2) | 2025.08.07 |
---|---|
빈 슬라이드 일괄 추가하는 코드 (0) | 2025.03.26 |
오디오 재생바 책갈피트리거 애니메이션효과로 구현하기 (0) | 2025.03.25 |
매크로를 추가기능으로 만드는 방법 예시 (0) | 2025.02.18 |
텍스트를 여러 장의 자막 슬라이드로 일괄 생성 (0) | 2025.02.05 |
파워포인트 모든 도형 모양 종류 및 예약어 목록 (0) | 2025.01.31 |
목차슬라이드 페이지 정보 자동 업데이트 (0) | 2025.01.28 |
파워포인트 표의 기존 서식을 유지하면서 엑셀 표 붙여넣기 (0) | 2025.01.11 |
최근댓글