【入門編】【上級】Shape.SpatialRelationを活用した空間検索エンジン:指定範囲内の図形を高速抽出する – Visio VBA解析バイブル

スポンサーリンク

こんにちは!Visio VBAの世界へようこそ。
マクロの記録ボタンを押して、生成されたコードをただ眺める日々から、そろそろ本当の意味でVisioを「意のままに操る」ステージへ進んでみませんか?

今回は、Visio VBAの真骨頂とも言える「空間検索エンジン(SpatialRelationメソッド)」をテーマにお話しします。

「特定のエリアにある図形を全部拾いたい」「ある図形に触れている(あるいは内包されている)図形だけを瞬時に見つけたい」――そんな時、自前で泥臭い座標計算(`PinX`や`PinY`、`Width`、`Height`を使った複雑なIf判定)を書いていませんか?

実はそれ、Visioに備わっている超高速なネイティブの空間認識エンジンを使えば、たった1行のメソッド呼び出しで、しかも正確に解決できてしまうのです。ここをクリアすれば、あなたのVBAスキルは間違いなく中級者から「上級エンジニア」の領域へとシフトしますよ。さあ、一緒に扉を開けていきましょう!

—

1. なぜ自前の座標計算をしてはいけないのか?

Visioで図形を配置していると、「この四角形エリア(あるいは別の大きな図形)の中に重なっている図形をリストアップしたい」という要件に必ず直面します。

ここでプログラミング初学者がやりがちなのが、次のようなアプローチです。

‘ 【アンチパターン】自前で座標計算をする泥臭いコード
Dim shp As Shape
For Each shp In ActivePage.Shapes
‘ PinX, PinY, 幅, 高さを取得して、範囲内に入っているか数学的に判定…
If shp.PinX >= x1 And shp.PinX <= x2 And shp.PinY >= y1 And shp.PinY <= y2 Then ' 処理... End If Next shp この方法、図形が単純な点や、中心座標だけで判定できる簡易的なものなら動きます。しかし、図形が回転していたら? 線の太さや矢印の先端はどう扱いますか? グループ化されたネスト構造の中の図形はどうしますか?

これらを自前のVBAコードで完全に網羅しようとすると、コードは複雑怪奇になり、実行速度もガタ落ちします。

救世主:`Shape.SpatialRelation` メソッド

Visioのアプリケーションコアには、長年ブラッシュアップされてきた強力な空間検索エンジンが組み込まれています。それをVBAから呼び出すのが `SpatialRelation` メソッドです。

これを使えば、VisioのC++ネイティブ層が瞬時に図形同士の位置関係(包含、接触、重なりなど)を計算し、正確な結果を返してくれます。私たちはその結果を受け取るだけでいいのです。

—

2. SpatialRelationの仕組みと基本構文

まずは、このメソッドのシグネチャ(定義)を確認しておきましょう。

Result = TargetShape.SpatialRelation(OtherShape, Tolerance, Flags)

  • `TargetShape`: 基準となる図形(または「検索エリア」に見立てた一時的な四角形など)。
  • `OtherShape`: 比較対象となる図形。
  • `Tolerance`: 許容値(通常は `0` または `VisSpatialTolerance.visSpatialDefault`)。ミリ単位などの微小な隙間をどう扱うかを指定します。
  • `Result`: 2つの図形がどのような関係性にあるかを示す定数(`VisSpatialRelationCodes`)が返ってきます。

主な判定フラグ(返り値の例)

  • `visSpatialContained` (1): TargetShapeの中に OtherShapeが完全に含まれている
  • `visSpatialContain` (4): TargetShapeが OtherShapeを完全に含んでいる
  • `visSpatialOverlap` (8): 両者が部分的に重なり合っている
  • `visSpatialTouching` (16): 境界線が接している(触れている)

これらを組み合わせることで、「指定したエリア(矩形)に接触、または内包されているすべての図形を抽出する」という高度な空間検索が可能になります。

—

3. 実践!指定範囲内の図形を高速抽出するVBAコード

それでは、現場で即戦力として使える実用的なコードをご紹介します。

このコードでは、ページ上に配置した「検索エリアを表す四角形(仮に `SearchBox` という名前、または一番手前にある四角形とします)」を基準にして、そのエリア内に含まれる、あるいは重なっている他の図形をすべてスキャンし、イミディエイトウィンドウにその名前を出力します。

Sub FindShapesInArea()
‘ =========================================================================
‘ 処理名: 指定されたエリア(矩形図形)と重なる/内包される図形を高速抽出する
‘ 著者: チーフアーキテクト
‘ =========================================================================

Dim vsoPage As Visio.Page
Set vsoPage = ActivePage

Dim targetBox As Visio.Shape
On Error Resume Next
‘ 検索エリアとなる図形をあらかじめ「SearchArea」と名前づけておいたと仮定
Set targetBox = vsoPage.Shapes.Item(“SearchArea”)
On Error GoTo 0

If targetBox Is Nothing Then
MsgBox “ページ内に ‘SearchArea’ という名前の図形が見つかりません。” & vbCrLf & _
“検索範囲となる四角形を配置し、[開発]タブの[図形名]で名前を設定してください。”, vbExclamation
Exit Sub
End If

Dim shp As Visio.Shape
Dim relation As Integer
Dim hitCount As Long
hitCount = 0

Debug.Print “=== 空間検索エンジンによるスキャン開始 ===”

‘ ページ内の全図形を走査
For Each shp In vsoPage.Shapes
‘ 検索エリア自身は比較対象外とする
If shp.ID <> targetBox.ID Then

‘ SpatialRelationメソッドの呼び出し
‘ visSpatialContained (内包) または visSpatialOverlap (重複) などをチェック
‘ ここでは「エリアに少しでも触れている、または含まれている」ものを対象とするため、
‘ ビット演算フラグを組み合わせるか、主要なコードを判定します。

relation = targetBox.SpatialRelation(shp, 0.0001, visSpatialRelationFireUp)

‘ 判定結果のマスク処理(重なり、包含、接触のいずれかに該当するか)
‘ visSpatialContained または visSpatialOverlap または visSpatialContain 等
If (relation And (visSpatialContained + visSpatialOverlap + visSpatialContain + visSpatialTouching)) <> 0 Then
Debug.Print “ヒット! 図形名: ” & shp.Name & ” (ID: ” & shp.ID & “)”

‘ 例として、ヒットした図形の色を赤色に変える演出
shp.CellsSRC(visSectionObject, visRowShapeFill, visFillForegnd).ResultIU = RGB(255, 0, 0)

hitCount = hitCount + 1
End If
End If
Next shp

Debug.Print “=== スキャン終了 (ヒット数: ” & hitCount & “件) ===”
MsgBox hitCount & ” 件の図形を検出しました。”, vbInformation
End Sub

コードのポイントとエンジニアの知見

1. `targetBox.SpatialRelation(shp, 0.0001, …)`
第2引数(Tolerance)に微小な値(`0.0001` inchなど)を指定することで、浮動小数点演算の誤差による「わずかに隙間がある判定ミス」を防ぎ、実用上極めて堅牢な判定が可能になります。
2. ビット演算子(`And`)による柔軟な条件判定
`SpatialRelation` は複数の状態を同時に返すことがあります。そのため、単なる `= visSpatialContained` ではなく、ビットマスク(`And`演算)を使って「何らかの形で空間的にリレーションを持っているか」を判定するのが、プロフェッショナルな実装です。
3. 視覚的なフィードバック
バックグラウンドで処理が走るだけでなく、見つかった図形の色を変える(`ResultIU = RGB(…)`)ことで、ユーザーが「正しく空間検索が行われたこと」を目で見て直感的に理解できるようにしています。

—

4. 陥りやすい罠とエラー回避の極意

この `SpatialRelation` を使いこなす上で、シニアエンジニアとして知っておくべき「罠」がいくつかあります。

罠1: 単位系の罠(インチとミリメートル)

Visioの内部データはすべて「インチ(Inches)」で保持されています。Toleranceにうっかり `1`(1ミリのつもりで)を指定すると、Visioにとっては「1インチ(25.4mm)の許容誤差」という巨大なガバガバ判定になってしまいます。
細かな制御をしたい場合は、Visioが提供する単位変換関数(`Visio.Application.ConvertUnits`)を使うか、内部単位(インチ)ベースで値を設定する習慣をつけましょう。

罠2: グループ図形(Group Shapes)の扱い

Visioのページ(`Page.Shapes`)をループするだけでは、グループ化された「子図形(Sub-shapes)」の内部まで空間検索の網が届かないことがあります。
もしグループの内部材までくまなく検索したい場合は、再帰処理(Recursive Function)を組んで、サブシェイプの階層を潜り抜ける設計にする必要があります。ここが、初級者が中級者へステップアップする際の最初の壁になります。

—

最後に:ここをクリアすれば、Visio VBAはあなたの武器になる

いかがでしたでしょうか?
今回は、Visioの隠れた名機能である空間検索エンジン `SpatialRelation` を用いて、座標計算地獄から脱却する方法を解説しました。

マクロの記録が吐き出す「選択して移動する」だけのコードから卒業し、「図形同士の論理的・空間的な関係性をプログラムに計算させる」ことができるようになると、自動化できる業務の幅が何倍にも広がります。

レイアウトの自動検証ツール、配線図の自動ルーティング支援、特定エリア内の設備管理システムなど、アイデア次第でどんなプロフェッショナルなソリューションも構築可能です。

「ここをクリアすれば、Visio VBAの基本はバッチリですよ!」
ぜひ、あなたの開発現場でもこの空間検索エンジンを組み込んで、圧倒的な処理速度とスマートなコードを体感してみてください。それでは、次のステージでお会いしましょう!

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