【テクニカル・上級編】【実務中級】AcadDocument.Utility.GetOrientationによる「回転角」の取得:ANGBASE設定に左右されない正確な角度入力 – AutoCAD VBA解析バイブル

スポンサーリンク

1. 序論:なぜ図面ごとに角度計算が破綻するのか?

AutoCADのVBA自動化プログラムを構築し、いざ運用環境へ投入した直後、特定の図面セットでのみ「ブロックの回転角が狂う」「注記テキストが明後日の方向を向く」といった不具合に遭遇したことはないでしょうか。

その原因の9割は、CADオペレーターや図面種別(土木、建築、機械など)ごとに異なるシステム変数 `ANGBASE`(角度基準方向)および `ANGDIR`(角度回転方向)の非標準化にあります。

  • 機械・一般図面: 3時方向(東)が `0` 度、反時計回りが正 (`ANGBASE=0`, `ANGDIR=0`)
  • 測量・土木図面: 12時方向(北)が `0` 度、時計回りが正 (`ANGBASE=90`, `ANGDIR=1`)

多くのVBAエンジニアは、ユーザーから角度入力を得る際に安直に `AcadDocument.Utility.GetAngle` を使用します。しかし、`GetAngle` が返す値は現在の `ANGBASE` / `ANGDIR` に相関した「ローカルオフセット値」です。これをそのままオブジェクトの `Rotate` メソッドや `Rotation` プロパティに与えると、二重に角度補正が適用されたり、基準がずれて壊滅的な幾何学的エラーを引き起こします。

本稿では、AutoCAD VBAにおけるインタラクティブ入力の核心である `AcadDocument.Utility.GetOrientation` を徹底解剖し、図面環境に依存しない堅牢な幾何計算アーキテクチャの構築手法を解説します。

2. メカニズムの徹底比較:`GetAngle` VS `GetOrientation`

両者の違いを決定づけるのは、入力プロンプト時の挙動ではなく、「最終的に返却されるラジアン値の絶対的定義」です。

【数学的絶対座標系(UCS 0度軸 = 3時方向 / 反時計回り(+))】
90° (π/2)
|
180° (π) —+— 0° (0 rad) <-- オブジェクトのRotate() / Rotationプロパティが要求する基準 | 270° (3π/2) | 機能 / 仕様 | `GetAngle` | `GetOrientation` | | :--- | :--- | :--- | | ユーザー操作時の見た目 | `ANGBASE` / `ANGDIR` に従う | `ANGBASE` / `ANGDIR` に従う |
| 返却値の基準点 (0 rad) | 現在の `ANGBASE` の方向 | 常に数学的ゼロ軸(3時方向/東) |
| 返却値の回転方向 | 現在の `ANGDIR` の方向 | 常に反時計回り (Counter-Clockwise) |
| `AcadEntity.Rotate` への直接投入 | 不可(手動で `ANGBASE`/`ANGDIR` 補正が必要) | 可能(無加工で直接代入可能) |

なぜ `GetAngle` は `Rotate` メソッドを破壊するのか

AutoCADのオブジェクトモデルにおける `.Rotate(BasePoint, RotationAngle)` や `AcadBlockReference.Rotation` プロパティは、内部的に絶対世界座標系のX軸(東向き=0ラジアン)からの反時計回りのラジアン角を要求します。

仮に `ANGBASE = 90`(北が0度)の図面で、ユーザーが「真北(上向き)」をクリック指定した場合:

  • `GetAngle` は `0.0` ラジアン を返します(北が0度だからです)。
  • この `0.0` を `BlockRef.Rotation` に代入すると、ブロックは「東向き」に配置されます。ユーザーの意図(北向き)と90度の乖離が発生します。

対して `GetOrientation` は、同じ操作に対して `1.57079…` (π/2 rad = 90度) を返します。これをそのまま代入することで、図面設定がどうであれ、オブジェクトは正確に「真北」を向きます。

3. 実務標準VBA実装パターン

以下に、エンタープライズ環境での運用に耐えうる堅牢な実装を示します。
ユーザーによる `ESC` キーキャンセル処理(COMエラー `0x800401E0` / `-2145320928` の捕捉)、ゼロ長ベクトルの防護、および取得した絶対角度を用いたオブジェクト配置の一連の流れをカプセル化しています。

Option Explicit

‘===============================================================================
‘ 機能: ANGBASE/ANGDIR設定に依存せず、絶対幾何角度を取得してエンティティを回転させる
‘ 適用領域: レガシーVBAモジュール / AutoCAD ActiveX API
‘===============================================================================
Public Sub InsertAndOrientBlockStrict()
On Error GoTo ErrorHandler

Dim doc As AcadDocument
Set doc = ThisDrawing.Application.ActiveDocument

‘ 1. 挿入点の取得
Dim insertPoint As Variant
insertPoint = doc.Utility.GetPoint(, vbCr & “配置位置を指定してください: “)

‘ 2. 絶対回転角の取得 (GetOrientationを使用)
‘ ※ GetOrientationはANGBASEに関わらず、常に東向き=0rad、反時計回りの絶対ラジアンを返す
Dim absAngle As Double
absAngle = doc.Utility.GetOrientation(insertPoint, vbCr & “回転方向を指定してください: “)

‘ 3. トランザクション的エンティティ生成 (例: 簡易的に矢印代わりのラインを生成)
Dim endPoint(0 To 2) As Double
Dim lineLength As Double: lineLength = 100.0

‘ 極座標計算による終点の算出(返却されたラジアンを直接使用可能)
endPoint(0) = insertPoint(0) + lineLength Cos(absAngle)
endPoint(1) = insertPoint(1) + lineLength Sin(absAngle)
endPoint(2) = insertPoint(2)

Dim guideLine As AcadLine
Set guideLine = doc.ModelSpace.AddLine(insertPoint, endPoint)
guideLine.Update

‘ 4. ブロック参照などのプロパティへ適用する場合の検証用ログ
doc.Utility.Prompt vbCr & “[成功] 絶対取得角度: ” & _
Format$(absAngle (180 / 3.14159265358979), “0.00”) & ” 度 (rad: ” & CStr(absAngle) & “)” & vbCr

ExitPoint:
‘ 明示的オブジェクト解放(COM参照カウントの制御)
Set guideLine = Nothing
Set doc = Nothing
Exit Sub

ErrorHandler:
Dim errNum As Long
errNum = Err.Number

‘ ユーザーによるESCキーキャンセルの判定 (AcadError: UserBreak)
If errNum = -2145320928 Or errNum = &H800401E0 Then
doc.Utility.Prompt vbCr & “[中断] ユーザーによって操作がキャンセルされました。” & vbCr
Else
MsgBox “予期せぬエラーが発生しました: ” & Err.Description & ” (ErrCode: ” & Hex(errNum) & “)”, _
vbCritical, “CADシステムエラー”
End If
Resume ExitPoint
End Sub

4. アーキテクチャの深化:メモリ・COM層と例外系ハンドリング

1. COMオブジェクトのライフサイクルとパフォーマンス

AutoCAD VBAは内部的にActiveX Automation(COM Bridge)を介してC++コア(ObjectARX)と通信しています。
`AcadDocument.Utility` オブジェクト群のメソッド呼出は同期プロセスであり、ユーザーの入力を待機している間、メッセージループがフックされます。

大量の作図要素をループ処理で更新する中で `GetOrientation` を呼び出す場合、画面の再描画(`AcadApplication.Zoom` や `AcadDocument.Regen`)が走ると極端にパフォーマンスが低下します。入力前後の描画制御が必要な場合は、必ず描画更新を一時停止してください。

‘ 高速化のための描画停止パターン(必要に応じて使用)
ThisDrawing.Application.ScreenUpdating = False
‘ … 大量の幾何要素更新処理 …
ThisDrawing.Application.ScreenUpdating = True
ThisDrawing.Regen acActiveViewport

2. キャンセル処理とエラーコードの完全制御

AutoCAD ActiveX APIにおいて、ユーザーがプロンプト表示中に `ESC` キーを押下した場合、C++層からCOM HRESULT `0x800401E0` (`ACAD_E_USERBREAK`) が返されます。VBA側ではこれが符号付き32ビット整数としてパースされ、`-2145320928` となります。

このエラーを大域的なエラーハンドラに投げずに適切にキャッチ&リバース処理を行うことは、システム管理者レベルのVBAコードにおいて必須の標準作法です。

5. 次世代技術への架け橋:.NET (C# / VB.NET) Interopへの移植性

将来的にレガシーVBAから .NET API (C# / VB.NET) や ObjectARX へ移行する場合でも、本概念の理解は極めて重要です。

オートデスクの .NET API における `Editor.GetAngle()` メソッドは、デフォルトで `PromptAngleOptions` の設定に依存します。VBAの `GetOrientation` と同等の挙動を .NET で実現するには、`UseAngleBase` プロパティの明示的制御が必要です。

.NET (C#) での同等ロジック実装例

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

public class AngleUtility
{
[CommandMethod(“GET_EXACT_ORIENTATION”)]
public void GetExactOrientation()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;

PromptAngleOptions pAo = new PromptAngleOptions(“\n回転方向を指定してください: “);

// VBAの GetOrientation と同等にするため、ANGBASEの無効化(絶対角取得)を指示
pAo.UseAngleBase = false;

PromptDoubleResult pDr = ed.GetAngle(pAo);

if (pDr.Status == PromptStatus.OK)
{
// 返却値は絶対ラジアン(0 rad = X軸正方向)
double absRadian = pDr.Value;
ed.WriteMessage($”\n絶対取得角度: {absRadian} rad”);
}
}
}

6. 結論:堅牢なCAD自動化のための設計指針

1. 図面設定 (`ANGBASE` / `ANGDIR`) を絶対の前提条件としない。 多角的な拠点・外注先から集まる図面は、設定が完全にバラバラであると定義せよ。
2. オブジェクトの回転操作には `GetOrientation` 一択。 ユーザーへの対話プロンプトで取得した角度をそのまま `Rotate()` メソッドや `.Rotation` プロパティに投入する場合、`GetAngle` を使用してはならない。
3. ユーザー入力のキャンセル(`ESC`)は正常系フローとして設計する。 COMエラー `-2145320928` をハンドリングし、呼び出し元の不整合(不完全なオブジェクト生成など)を防ぐロールバックを実装せよ。

単なる「動くコード」から「いかなる環境でも破綻しない決定論的なシステム」へ。この極限の細部へのこだわりこそが、レガシーシステムを真のエンタープライズ品質へと高める絶対的鍵となります。

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