【実務・中級編】【中級者向け】ページ設定の「縮尺」を自動計算し、実寸と図面上の寸法の乖離を修正する監査ツール – Visio VBA解析バイブル

スポンサーリンク
スポンサーリンク

【極限の設計】Visioの「縮尺不整合」を根絶する:高精度監査エンジンの構築術

設計現場において、Visioの図面は単なる「絵」ではない。それは、実寸に基づいた「設計データ」であるべきだ。

しかし、現場では悲劇が日常的に起きている。ページ設定で「1:50」と謳いながら、シェイプのサイズが実寸計算に基づかず、適当なドラッグ&ドロップで配置されている。この「縮尺の乖離」は、後続の製造工程や施工工程において致命的なミスを誘発する。

多くの「ツール作成担当者」は、単にシェイプの幅を読み取るだけの稚拙なスクリプトを書く。だが、それではプロフェッショナルとは呼べない。我々が構築すべきは、Visioのオブジェクトモデルの深淵を理解し、数学的精度と堅牢なエラーハンドリングを備えた「監査エンジン」である。

本稿では、ページ設定の縮尺とシェイプの実寸を照合し、不整合を炙り出す、プロダクションレベルの監査ツールの設計思想を伝授する。

1. 陥りやすい「素人の設計」と、アーキテクトの視点

まず、避けるべき設計パターンを提示しよう。多くの開発者が以下のようなコードを書く。

' --- 避けるべき、脆弱な設計例 ---
Sub BadAudit()
    Dim shp As Visio.Shape
    For Each shp In ActivePage.Shapes
        ' ページスケールを無視して、単にサイズを表示するだけ
        Debug.Print shp.Name & " Width: " & shp.Width
    Next shp
End Sub

なぜこれが「ゴミ」なのか。理由は3つある。

1. 単位(Unit)の混同: Visioの`Shape.Width`が返す値は、ドキュメント単位(インチやミリメートル)である。ページ設定の「縮尺」が適用された後の「実寸(Real World Dimension)」を計算に含めていない。
2. 浮動小数点誤差の無視: 縮尺計算(1/50など)には割り算が伴う。`Double`型の比較において、`If a = b Then` といった単純比較を行うと、微小な誤差によって正解が「不整合」と判定される。
3. スケーラビリティの欠如: `MsgBox`でエラーを出す設計では、数百のシェイプがある図面を監査した瞬間にユーザーの作業が停止する。

プロフェッショナルは、「計算ロジック」「データ収集」「レポート出力」を完全に分離して設計する。

2. 監査エンジンの設計思想:数学的整合性の確保

高精度な監査ツールを作るためには、以下の数式を厳密に実装する必要がある。

$$ \text{RealWorldDimension} = \text{DocumentDimension} \times \text{PageScaleRatio} $$

ここで重要なのは、Visioの `Page.ScaleWidth` プロパティの扱いに注意することだ。これは「ドキュメントの1単位が、現実世界の何単位に相当するか」を示す係数である。

設計の3原則

1. Tolerance(許容誤差)の導入: `Abs(Calculated – Expected) < Tolerance` という形式で比較を行う。 2. Result Objectの構築: エラーを単に表示するのではなく、エラー内容(シェイプ名、期待値、実測値、乖離率)を構造化して保持する。
3. Decoupling(非結合): 監査ロジックはVisioのUIに依存させず、純粋な計算ロジックとして切り出す。

3. プロダクションコード:高精度監査エンジン

以下に、そのまま業務に投入可能なレベルの、堅牢な実装例を示す。このコードは、エラーをコレクションとして蓄積し、最後に一括して報告する設計思想に基づいている。

Option Explicit

' --- 監査結果を保持するための構造体 ---
Private Type AuditError
    ShapeName As String
    ExpectedWidth As Double
    ActualWidth As Double
    Deviation As Double
End Type

' --- 定数定義 ---
Private Const TOLERANCE As Double = 0.001 ' 許容誤差 (mm単位を想定)

''' <summary>
''' ページ内のシェイプの縮尺不整合を監査するメインルーチン
''' </summary>
Public Sub RunScaleAuditEngine()
    Dim pg As Visio.Page
    Set pg = ActivePage
    
    Dim errorList() As AuditError
    Dim errorCount As Long
    errorCount = 0
    
    ' ページスケール係数の取得
    ' ScaleWidthは「1ドキュメント単位あたりの現実世界の単位数」
    Dim scaleRatio As Double
    scaleRatio = pg.ScaleWidth
    
    Dim shp As Visio.Shape
    Dim expectedRealWidth As Double
    Dim actualRealWidth As Double
    Dim deviation As Double
    
    On Error GoTo ErrorHandler
    
    ' 高速化のための最適化
    Application.ScreenUpdating = False
    
    For Each shp In pg.Shapes
        ' ユーザー定義の「実寸属性」を持っているシェイプのみを対象とする設計
        ' (全てのシェイプを対象にすると、装飾用ライン等でノイズが出るため)
        If shp.CellExists("Prop.RealWorldWidth", 0) Then
            
            ' 1. 属性から「本来あるべき実寸」を取得
            expectedRealWidth = shp.Cells("Prop.RealWorldWidth").ResultIU
            
            ' 2. 現在のドキュメント上の幅から「現在の実寸」を計算
            ' Shape.Width はドキュメント単位。これにScaleWidthを掛けて実寸に変換
            actualRealWidth = shp.Width * scaleRatio
            
            ' 3. 乖離の計算
            deviation = Abs(expectedRealWidth - actualRealWidth)
            
            ' 4. 許容誤差判定
            If deviation > TOLERANCE Then
                errorCount = errorCount + 1
                ReDim Preserve errorList(1 To errorCount)
                
                With errorList(errorCount)
                    .ShapeName = shp.Name
                    .ExpectedWidth = expectedRealWidth
                    .ActualWidth = actualRealWidth
                    .Deviation = deviation
                End With
            End If
        End If
    Next shp
    
    Application.ScreenUpdating = True
    
    ' --- 結果のレポート出力 ---
    If errorCount > 0 Then
        ReportErrors errorList, errorCount
    Else
        MsgBox "監査完了: 縮尺の不整合は見つかりませんでした。", vbInformation, "Audit Success"
    End If
    
    Exit Sub

ErrorHandler:
    Application.ScreenUpdating = True
    MsgBox "致命的なエラーが発生しました: " & Err.Description, vbCritical, "System Error"
End Sub

''' <summary>
''' 監査結果をログ出力(実務ではExcel出力やDB保存へ拡張可能)
''' </summary>
Private Sub ReportErrors(ByRef errors() As AuditError, count As Long)
    Dim i As Long
    Dim reportMsg As String
    reportMsg = "【警告】" & count & " 件の縮尺不整合を検出しました。" & vbCrLf & vbCrLf
    
    ' 簡易的なメッセージ表示(件数が多い場合はExcel出力に切り替える設計にする)
    If count > 10 Then
        ' 10件を超える場合はExcelへ書き出すロジックへ分岐させるのがプロの設計
        ExportToExcel errors, count
    Else
        For i = 1 To count
            reportMsg = reportMsg & "■ " & errors(i).ShapeName & vbCrLf & _
                        "   期待値: " & Round(errors(i).ExpectedWidth, 2) & " mm" & vbCrLf & _
                        "   現在値: " & Round(errors(i).ActualWidth, 2) & " mm" & vbCrLf & _
                        "   誤差  : " & Round(errors(i).Deviation, 3) & " mm" & vbCrLf & vbCrLf
        Next i
        MsgBox reportMsg, vbExclamation, "Audit Alert"
    End If
End Sub

''' <summary>
''' 監査結果をExcelへエクスポートする(実務用拡張メソッド)
''' </summary>
Private Sub ExportToExcel(ByRef errors() As AuditError, count As Long)
    Dim xlApp As Object
    Dim xlWB As Object
    Dim i As Long
    
    On Error Resume Next
    Set xlApp = GetObject(, "Excel.Application")
    If xlApp Is Nothing Then
        Set xlApp = CreateObject("Excel.Application")
    End If
    On Error GoTo 0
    
    Set xlWB = xlApp.Workbooks.Add
    xlApp.Visible = True
    
    With xlWB.Sheets(1)
        .Cells(1, 1).Value = "Shape Name"
        .Cells(1, 2).Value = "Expected (mm)"
        .Cells(1, 3).Value = "Actual (mm)"
        .Cells(1, 4).Value = "Deviation (mm)"
        
        For i = 1 To count
            .Cells(i + 1, 1).Value = errors(i).ShapeName
            .Cells(i + 1, 2).Value = errors(i).ExpectedWidth
            .Cells(i + 1, 3).Value = errors(i).ActualWidth
            .Cells(i + 1, 4).Value = errors(i).Deviation
        Next i
    End With
    
    MsgBox "詳細な監査レポートをExcelで生成しました。", vbInformation
End Sub

4. 実務への統合:データベース・外部連携の注意点

このツールを単なるスクリプトから「業務基盤」へと昇華させるには、以下の点に留意せよ。

シェイプへのメタデータ埋め込み

上記のコードでは `shp.CellExists(“Prop.RealWorldWidth”, 0)` を使用している。これは、シェイプの「ShapeSheet」に、設計上の正しい実寸を保持するユーザー定義セル(`Prop.RealWorldWidth`)を持たせることを前提としている。
単に「図面の見た目」をチェックするのではなく、「正しい設計値」というマスターデータをシェイプ自体に持たせる。これが、データの一貫性を保つための鉄則である。

外部連携(Excel/DB)のパフォーマンス

大量の図面を監査する場合、Excelへの書き出しは「一セルずつ」行ってはならない。
1. メモリ上の配列(`errorList`)に一度すべて格納する。
2. Excelの `Range.Value = Array` を用いて、一括でセルへ流し込む。
この「バルク・インサート」の概念がないコードは、大規模プロジェクトではパフォーマンス・ボトルネックとなり、使い物にならない。

結論

Visio VBAにおける自動化とは、単に「操作を代行すること」ではない。「設計の品質を数学的に担保すること」である。

オブジェクトのライフサイクル、単位変換の精度、そしてエラーの構造化。これらを意識して設計されたコードこそが、エンジニアリングの現場で真に信頼される「ツール」となる。

君が次に書くコードは、単なるスクリプトか? それとも、設計品質を守るための堅牢なエンジンか? その答えは、君の設計思想に委ねられている。

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