Visio VBAを掌握する極限の知見:Page.DrawNURBSを用いた高精度曲線の動的生成
開発プロジェクトの現場において、Visioを単なる「お絵描きツール」として扱っているうちは、業務自動化のポテンシャルの半分も引き出せていない。特に、外形図や配管ルート、あるいはCADからコンバートされた複雑な輪郭データを扱う際、直線や単純な円弧の組み合わせでそれを表現しようとすれば、コードは肥大化し、描画精度は崩壊し、メモリはリークする。
CAD連携や高度なレイアウト自動生成において、真に求められるのは「数学的に正確な自由曲線の動的生成」である。
今回は、Visio VBAの隠れた(そして最も強力な)描画APIの一つである `Page.DrawNURBS` メソッドを取り上げる。制御点(Control Points)と重み(Weights)、そしてノット(Knots)の概念を完全手中に収め、プロダクション環境で耐えうる堅牢なCAD連携基盤をどう構築するか、その極限の知見を伝授する。
—
1. なぜ「DrawNURBS」なのか? —— 非効率なアプローチとの決別
多くの初学者は、曲線を描画したいときに `DrawSpline` や無数の微小な `DrawLine` の集合体でそれを代替しようとする。これは実務の現場においては悪手である。
- `DrawLine` の連鎖: 頂点数が数千に及ぶ場合、Shapeの数が爆発的に増加し、Visioのドキュメントデータベース(Documentオプジェクト)の肥大化と描画パフォーマンスの致命的な劣化を招く。
- `DrawSpline` のブラックボックス性: Visio内部のアルゴリズムに依存するため、外部CAD(AutoCADやSolidWorksなど)からエクスポートされた正確な数式データ(NURBSパラメータ)と形状が一致しない。
NURBS(Non-Uniform Rational B-Spline)は、工業用CADのデファクトスタンダードである。これをVisioのネイティブシェイプとしてダイレクトに流し込むことで、データ構造を最小限(1つのShape)に抑えつつ、数学的な精度をミリ単位で完全再現できるのだ。
—
2. `Page.DrawNURBS` の仕様と致命的な罠
`Page.DrawNURBS` メソッドの構文は以下の通りだが、公式ドキュメントだけでは読み取れない「実務上の暗黙のルール」が存在する。
Set shp = Page.DrawNURBS(xyArray, weightArray, knotArray, degree)
引数の正確な構造と制約事項
1. `xyArray` (Double型1次元配列): 制御点のX, Y座標を交互に格納する。 `(x1, y1, x2, y2, … xn, yn)`
2. `weightArray` (Double型1次元配列): 各制御点の「重み」。すべての要素を `1.0` にすればB-Spline(非有理)になり、値を変化させることで円 錐曲線などの厳密な表現が可能になる。要素数は制御点の数と一致させる必要がある。
3. `knotArray` (Double型1次元配列): ノットベクトル。ここが最大の罠である。VisioのNURBS実装では、クランプされた(Clamped)ノットベクトルを要求することが多く、配列のインデックスと値の対応を間違えると、エラー 350(無効な引数)か、あるいは歪んだ形状が描画される。
4. `degree` (Long型): 次数(通常は3次=Cubic)。
—
3. 【プロダクションコード】CADデータ連携を想定したNURBS動的生成エンジン
以下のコードは、外部の設計データ(CSVやデータベース、あるいは外部APIからのJSON等)を想定し、数理座標からVisio上に高精度なNURBS曲線を一撃で生成する堅牢なプロシージャである。
エラーハンドリング、トランザクション処理(画面描画の抑制)、メモリ管理のベストプラクティスをすべて網羅している。
Option Explicit
Public Sub RenderNURBSCurveFromCADData()
‘ ————————————————————————-
‘ 処理名: RenderNURBSCurveFromCADData
‘ 概要 : 外部CAD等から取得した制御点データをもとに、Visio上にNURBS曲線を高精度描画する
‘ 備考 : 画面描画を停止し、Undoスコープを活用した堅牢な設計
‘ ————————————————————————-
Dim vsoPage As Visio.Page
Set vsoPage = ActivePage
‘ パフォーマンス向上のため画面描画とイベントを停止
Application.ScreenUpdating = False
Application.EventsEnabled = False
Dim lScopeID As Long
lScopeID = Application.BeginUndo(“CAD NURBS Import”)
On Error GoTo ErrorHandler
‘ — 1. データの準備(実務ではここでCSVやDBから動的に配列を構築する) —
‘ 今回はサンプルとして、緩やかなS字を描く4つの制御点を定義
Dim dblXY() As Double
ReDim dblXY(0 To 7) ‘ 4点 × 2座標 = 8要素 (0-7)
‘ 点1 (始点)
dblXY(0) = 1.0: dblXY(1) = 1.0
‘ 点2 (制御点1)
dblXY(2) = 2.0: dblXY(3) = 4.0
‘ 点3 (制御点2)
dblXY(4) = 5.0: dblXY(5) = 1.0
‘ 点4 (終点)
dblXY(6) = 6.0: dblXY(7) = 4.0
‘ — 2. 重み配列の構築 (Weights) —
‘ すべての制御点の重みを 1.0(標準)に設定
Dim dblWeights() As Double
ReDim dblWeights(0 To 3) ‘ 制御点の数と同数
Dim i As Long
For i = 0 To 3
dblWeights(i) = 1.0
Next i
‘ — 3. ノットベクトルの構築 (Knots) —
‘ 次数 (Degree) = 3, 制御点数 (n) = 4 の場合、
‘ ノットの総数は (n + degree + 1) = 8 となる。
‘ クランプされたNURBSの場合、両端の次数+1個の要素が重複する。
Dim dblKnots() As Double
ReDim dblKnots(0 To 7)
dblKnots(0) = 0.0
dblKnots(1) = 0.0
dblKnots(2) = 0.0
dblKnots(3) = 0.0
dblKnots(4) = 1.0
dblKnots(5) = 1.0
dblKnots(6) = 1.0
dblKnots(7) = 1.0
Dim lDegree As Long
lDegree = 3
‘ — 4. DrawNURBSによる描画実行 —
Dim vsoShape As Visio.Shape
Set vsoShape = vsoPage.DrawNURBS(dblXY, dblWeights, dblKnots, lDegree)
‘ — 5. メタデータ(カスタムプロパティ)の付与 —
‘ CAD連携では図形に元データのIDや属性を持たせることが必須
Call SetShapeProperty(vsoShape, “CAD_ID”, “CRV-2023-9901”)
Call SetShapeProperty(vsoShape, “Material”, “SUS304”)
‘ トランザクション正常終了
Application.EndUndo lScopeID, True
‘ 終了処理
Application.ScreenUpdating = True
Application.EventsEnabled = True
Exit Sub
ErrorHandler:
‘ 異常終了時はUndoをロールバック
Application.AbortUndo lScopeID
Application.ScreenUpdating = True
Application.EventsEnabled = True
MsgBox “NURBS曲線の生成に失敗しました。” & vbCrLf & _
“エラー番号: ” & Err.Number & vbCrLf & _
“説明: ” & Err.Description, vbCritical, “CAD連携エラー”
End Sub
Private Sub SetShapeProperty(ByRef vsoTargetShape As Visio.Shape, ByVal strPropName As String, ByVal strValue As String)
‘ 堅牢なプロパティ(ShapeSheet)設定ヘルパー
Dim strCellLabel As String
Dim strCellVal As String
On Error Resume Next
vsoTargetShape.AddRow visSectionProp, visRowLast, visTagDefault
Dim lRowIdx As Long
lRowIdx = vsoTargetShape.RowsCount(visSectionProp) – 1
vsoTargetShape.CellsSRC(visSectionProp, lRowIdx, visCustPropsLabel).FormulaU = “””” & strPropName & “”””
vsoTargetShape.CellsSRC(visSectionProp, lRowIdx, visCustPropsValue).FormulaU = “””” & strValue & “”””
On Error GoTo 0
End Sub
—
ジニアとして声を大にして言いたいのは、「VBAだからといって雑なコードを書いていい理由にはならない」ということだ。特に外部システム(CADやDB)と連携する自動化ツールにおいて、例外処理の欠落やトランザクション(Undo/Redoスコープ)の管理不足は、致命的なファイル破損を引き起こす。
今回解説した `Page.DrawNURBS` の実装パターンを武器にすれば、重たいCAD図面のインポートや、数式ベースの美しい配管・筐体レイアウト自動生成ツールを、圧倒的なパフォーマンスで実務に導入できるはずだ。泥臭いコードから脱却し、エレガントで堅牢なVisioソリューションを構築してほしい。
