距離入力の極致:AcadDocument.Utility.GetDistanceによるラバーバンドの実装とUXの掌握
かつて、AutoCAD VBAは「いつ廃止されてもおかしくない遺物」と呼ばれた。しかし、現場の最前線で数万行のコードを保守し、複雑な自動設計システムを構築してきた我々シニアエンジニアは知っている。VBAほど、AutoCADのオブジェクトモデルに直感的、かつ高速にアクセスできる軽量な環境は他にないということを。
本稿では、対話型ツールの品質を決定づける「視覚的フィードバック」に焦点を当てる。具体的には `AcadDocument.Utility.GetDistance` を使い、単なる数値入力ではない、プロフェッショナルな「ラバーバンド(伸縮線)」を伴う距離取得の実装について、その深淵を解説する。
—
1. 「距離」という概念の再定義
単に距離が欲しいだけであれば、テキストボックスに数値を打ち込ませれば済む。しかし、CADにおける「距離」とは、空間上の二点間の相関関係である。
`GetDistance` メソッドの真骨頂は、第一引数に BasePoint(基準点) を渡した瞬間に発揮される。基準点を指定することで、ユーザーのカーソル移動に合わせて「今、どこまでの距離を測ろうとしているのか」が視覚的な線(ラバーバンド)として表示される。このわずかなUXの差が、大規模な図面編集における操作ミスを劇的に減らす。
2. 【実戦コード】ラバーバンドを伴う堅牢な距離取得
以下のコードは、単なるサンプルではない。エラーハンドリング、座標変換、そしてCOMオブジェクトの挙動を考慮した、プロダクション環境に耐えうる実装である。
”
‘ @description 基準点からラバーバンドを表示し、ユーザーから距離を取得する
‘ @param basePointVariant 基準点の座標 (Variant配列: Double(0 To 2))
‘ @param prompt プロンプト文字列
‘ @return 取得した距離。キャンセル時は -1 を返す
”
Public Function InteractiveGetDistance(ByRef basePointVariant As Variant, ByVal prompt As String) As Double
On Error Resume Next ‘ AutoCADの対話型メソッドはキャンセル時にエラーを投げるため制御が必要
Dim dist As Double
‘ AutoCADアプリケーションの最前面確保(Windows APIを使わずともUtility経由で制御可能だが、
‘ フォーカスが外れていると入力を受け付けない場合があるため、明示的なAppの活性化が望ましい)
ThisDrawing.Activate
‘ GetDistanceメソッドの呼び出し
‘ 第一引数にBasePointを渡すことで、ラバーバンドが有効化される
dist = ThisDrawing.Utility.GetDistance(basePointVariant, vbCrLf & prompt)
‘ エラーハンドリング(ユーザーがESCキーを押下した場合など)
If Err.Number <> 0 Then
If Err.Description Like “ユーザーによるキャンセル” Or Err.Number = -2147352567 Then
‘ ユーザーキャンセルは正常系として扱う
InteractiveGetDistance = -1
Else
‘ 想定外のエラーはログ出力または上位へ委譲
Debug.Print “Error in GetDistance: ” & Err.Description
InteractiveGetDistance = -1
End If
Err.Clear
Exit Function
End If
InteractiveGetDistance = dist
End Function
”
‘ 実装例:メインルーチン
”
Sub ExecuteDistanceTool()
Dim startPt As Variant
Dim distance As Double
‘ 1. 基準点を取得
On Error Resume Next
startPt = ThisDrawing.Utility.GetPoint(, “基準点を選択してください: “)
If Err.Number <> 0 Then Exit Sub
On Error GoTo 0
‘ 2. ラバーバンドを伴う距離取得
distance = InteractiveGetDistance(startPt, “オフセット距離を指定、または画面上をクリック: “)
If distance > 0 Then
MsgBox “取得された距離: ” & Format(distance, “0.000”), vbInformation, “計測完了”
Else
ThisDrawing.Utility.Prompt vbCrLf & “操作がキャンセルされました。”
End If
End Sub
—
3. アーキテクトが語る、実装の急所
3.1. 座標系の「罠」を回避する
`GetDistance` が返す値は、現在の UCS(ユーザ座標系) に依存した `Double` 型のスカラ値である。しかし、内部で保持している座標が WCS(ワールド座標系)である場合、`Utility.TranslateCoordinates` を介さずに値を混合させると、3次元空間上での計算が破綻する。
「常にUCSで考え、必要に応じてWCSへ変換する」という原則を徹底せよ。
3.2. Windows APIによる「フォーカス」の制御
VBAからExcelや他の業務システムを操作している際、AutoCADのウィンドウが背後に隠れてしまうことがある。この状態で `GetDistance` を呼び出すと、ユーザーは何が起きたか分からずフリーズしたと錯覚する。
確実性を期すなら、`SetForegroundWindow` APIを使用して、AutoCADの `HWND` を強制的に前面へ持ってくるべきだ。
‘ Windows API 宣言(64bit環境用)
Declare PtrSafe Function SetForegroundWindow Lib “user32” (ByVal hwnd As LongPtr) As Long
‘ 使用例
SetForegroundWindow ThisDrawing.Application.hwnd
3.3. メモリとオブジェクトのライフサイクル
VBAは参照カウンタ方式でメモリを管理している。`AcadDocument.Utility` へのアクセスは、一見プロパティアクセスに見えるが、実際にはCOMオブジェクトの取得である。ループ内で数万回呼び出すような設計であれば、変数に `Set utility = ThisDrawing.Utility` とキャッシュすることで、微細ではあるがオーバーヘッドを削ることができる。
4. レガシーの保守と未来へのブリッジ
現在、多くの企業が .NET API (C#) への移行を進めている。しかし、C# の `Editor.GetDistance` メソッドも、本質的なロジックはこのVBAの `GetDistance` と変わらない。
VBAで「ラバーバンドの制御」や「エラーハンドリングの勘所」を理解しているエンジニアは、.NETへ移行しても即戦力として通用する。なぜなら、CADエンジンとの対話プロトコルの本質を理解しているからだ。
結論
`AcadDocument.Utility.GetDistance` に基準点を与える。ただそれだけのコードに、ユーザーインターフェースへの深い洞察が込められている。
プロフェッショナルなツールとは、ユーザーの思考を止めないツールだ。ラバーバンドによる視覚的フィードバックは、その第一歩に過ぎない。
現場のコードを美しく、そして強靭に保て。我々が書く一行のコードが、設計者の生産性を左右することを忘れてはならない。
