【テクニカル・上級編】図形の回転と反転:FlipやRotateメソッド、およびAngleセルのVBA制御による正確な姿勢変更 – Visio VBA解析バイブル

スポンサーリンク

Visio VBAを掌握する極限の知見:図形の回転・反転と姿勢制御の完全調停

図形自動生成の現場において、最も開発者を苦しめる要素の一つが「図形の姿勢制御」である。
フローチャートのルーティング、ネットワーク機器の向きの補正、あるいはCAD図面からの自動コンバート。これらにおいて、`Flip`メソッド、`Rotate`メソッド、そしてShapeSheetの`Angle`セル操作を場当たり的に使い分けているうちは、プロフェッショナルな自動化エンジニアとは言えない。

本稿では、Visioの描画エンジン(Visio Core)が抱える座標系の呪縛を解き明かし、プログラムから「狂いなく」図形を回転・反転させるための極限の知見を共有する。

1. Visio座標系の本質:なぜ単純な回転は破綻するのか?

多くのVBAプログラマブルな初学者は、`Shape.Rotate`メソッドを呼び出せば万事解決すると錯覚する。しかし、Visioの図形には「ピン(Pin)」という概念が存在する。

Visioの図形は、ローカル座標系(図形自身の中心や左下を基準とした座標)と、ページ座標系(Pageの左下を原点とする絶対座標)の二重構造で成り立っている。
さらに厄介なことに、`FlipHorizontal` や `FlipVertical` を実行した際、Visioは内部的にピンの位置やLocPin(ローカルピン)のオフセットを動的に再計算する。この挙動を理解せずにコードを書くと、図形が意図しない方向へワープしたり、アスペクト比が崩壊する現象に直面する。

究極の原則

  • 絶対角度の指定には `Angle` セルの直接代入を用いる。
  • 相対的な回転には `Rotate` メソッドを用いるが、回転中心(LocPinX / LocPinY)のバインディングを事前に固定していなければならない。
  • 反転(Flip)は、ShapeSheetの行列計算の反転を伴うため、グループ化された図形(Group)に対して実行する際は再帰的な考慮が不可欠である。

2. ShapeSheet制御による完全な角度指定(Angleセル)

メソッドによる回転は、現在の状態に依存するため、マクロを二重実行した際に予期せぬ角度に倒れ込むリスクがある。システム間連携やバッチ処理において「何度であれ、最終的に指定角度に向かわせる」ためには、ShapeSheetの `Angle` セルを直接叩くのが唯一にして最上のアプローチである。

以下に、ラジアン変換の罠を回避しつつ、任意の図形を指定角度(度数法)で正確に静止させる実用コードを提示する。

‘ ==============================================================================
‘ 処理名 : SetShapeAbsoluteAngle
‘ 概要 : 指定したShapeを指定された絶対角度(度数法)に正確に回転させる
‘ 備考 : ShapeSheetのAngleセルを直接操作することで、状態に依存しない確定的な姿勢変更を実現
‘ ==============================================================================
Public Sub SetShapeAbsoluteAngle(ByVal targetShape As Visio.Shape, ByVal targetAngleDegrees As Double)
Const PI As Double = 3.14159265358979
Dim radAngle As Double

‘ 入力値のガード(オブジェクトの生存確認)
If targetShape Is Nothing Then
Err.Raise 1000, “SetShapeAbsoluteAngle”, “対象のShapeオブジェクトが取得できません。”
End If

‘ 孤立した図形か、グループの子要素かを判定(必要に応じた保護)
If targetShape.ContainingShape.Type = visTypeGroup Then
‘ グループ内の子図形に対する回転はローカル座標系に依存するため注意が必要
‘ ここでは簡易的に例外処理、または上位ロジックへ委譲
End If

‘ 度数法から弧度法(ラジアン)への厳密な変換
radAngle = targetAngleDegrees (PI / 180#)

‘ トランザクションの開始(パフォーマンス向上と一括Undoの保証)
Dim undoScopeID As Long
undoScopeID = Application.BeginUndoScope(“図形の角度変更”)

On Error GoTo ErrorHandler

‘ ShapeSheetのCellsUプロパティを使用し、ローカライズ(言語依存)の影響を排除
targetShape.CellsU(“Angle”).FormulaU = radAngle & ” rad”

Application.EndUndoScope undoScopeID, True
Exit Sub

ErrorHandler:
Application.EndUndoScope undoScopeID, False
MsgBox “角度の設定に失敗しました: ” & Err.Description, vbCritical, “VBA Runtime Error”
End Sub

3. 垂直・水平反転(Flip)の罠とマトリックス制御

`Flip` メソッド(`visFlipHorizontal` / `visFlipVertical`)は非常に強力だが、実行するたびに図形の「ピン」を軸とした反転が行われるため、意図した位置からずれることが多い。特に、テキスト付きの図形を反転させると、テキストまで逆さになり視認性が完全に失われる。

プロフェッショナルな環境では、テキストの向きを保ったまま図形形状のみを反転させる、あるいは反転後の座標ズレをミリ単位で補正するロジックが求められる。

以下のコードは、水平反転を安全に実行し、必要に応じて位置のオフセットを強制補正するエンジンである。

‘ ==============================================================================
‘ 処理名 : SafeFlipShape
‘ 概要 : 図形の中心を維持したまま、安全に水平/垂直反転を実行する
‘ ==============================================================================
Public Sub SafeFlipShape(ByVal targetShape As Visio.Shape, ByVal isHorizontal As Boolean)
Dim pinXBefore As Double, pinYBefore As Double
Dim pinXAfter As Double, pinYAfter As Double

If targetShape Is Nothing Then Exit Sub

‘ 反転前のピン座標(ページ基準)を退避
pinXBefore = targetShape.CellsU(“PinX”).ResultIU
pinYBefore = targetShape.CellsU(“PinY”).ResultIU

‘ 実行
If isHorizontal Then
targetShape.Flip visFlipHorizontal
Else
targetShape.Flip visFlipVertical
End If

‘ Visioのバグ・仕様によるピンのズレを強制的に巻き戻す(ピン留め維持)
pinXAfter = targetShape.CellsU(“PinX”).ResultIU
pinYAfter = targetShape.CellsU(“PinY”).ResultIU

If (pinXBefore <> pinXAfter) Or (pinYBefore <> pinYAfter) Then
targetShape.CellsU(“PinX”).FormulaU = pinXBefore & ” in”
targetShape.CellsU(“PinY”).FormulaU = pinYBefore & ” in”
End If
End Sub

4. 大規模図面におけるメモリ最適化とパフォーマンスの極意

数千個の図形が配置された大規模なP&ID(配管計装図)やネットワーク図を一括制御する場合、毎回の画面描画(ScreenUpdating)やイベント発火がボトルネックとなり、VBAの実行速度は劇的に低下する。

極限のパフォーマンスを引き出すためには、以下の「三種の神器」を必ずコードに組み込むこと。

1. 画面描画の完全停止: `Application.ScreenUpdating = False`
2. イベントの無効化: `Application.EventsEnabled = False`
3. オブジェクトの明示的解放: ループ内での変数再利用と、処理終了時の `Nothing` 代入によるメモリリーク防止。

実践:一括姿勢変更バッチ処理のテンプレート

Public Sub BatchOptimizeShapeOrientations()
Dim doc As Visio.Document
Dim page As Visio.Page
Dim shp As Visio.Shape
Dim shpEnum As Visio.Shapes

Set doc = ActiveDocument
Set page = ActivePage

‘ 【極限最適化】描画とイベントを停止し、CPUリソースをVBA演算に全振りする
Application.ScreenUpdating = False
Application.EventsEnabled = False

On Error GoTo CleanUp

Set shpEnum = page.Shapes
Dim i As Long

‘ 逆順ループ(コレクション操作の鉄則:要素削除やインデックスシフトを防ぐ)
For i = shpEnum.Count To 1 Step -1
Set shp = shpEnum(i)

‘ 特定のマスターや条件に合致する場合のみ角度を0にリセットする例
If shp.Master <> Nothing Then
If shp.Master.Name = “TargetMasterName” Then
‘ 独自関数による安全な角度設定
SetShapeAbsoluteAngle shp, 0#
End If
End If

‘ メモリ解放の徹底
Set shp = Nothing
Next i

CleanUp:
‘ 【極限最適化の解除】必ずエラーハンドラや終了時に復元する
Application.EventsEnabled = True
Application.ScreenUpdating = True

‘ オブジェクト変数の完全解放
Set shpEnum = Nothing
Set page = Nothing
Set doc = Nothing

If Err.Number <> 0 Then
MsgBox “バッチ処理中にエラーが発生しました: ” & Err.Description, vbCritical
End If
End Sub

5. チーフアーキテクトからの提言

Visio VBAによる自動化は、単なる「マクロの記録」の延長ではない。背後にあるShapeSheetという強固な数理モデルを理解し、COMコンポーネントとしてのライフサイクルを完全に制御下におくことで初めて、実用に耐えうる堅牢なエンタープライズシステムが構築できる。

回転や反転という一見プリミティブな操作であっても、その内部挙動(ピンの挙動、ラジアン変換、トランザクション管理、画面描画の抑制)を極めた者だけが、巨大な図面を自在に操る権利を持つ。現場のコードに妥協を持ち込んではならない。

タイトルとURLをコピーしました