こんにちは!いつもAutoCADのカスタマイズや業務効率化、本当にお疲れ様です。
AutoCAD VBAの世界へようこそ。マクロの自動記録を卒業し、「自分でゼロから思い通りの図形を描きたい!」と思い始めたあなた。素晴らしい一歩を踏み出しましたね。
しかし、多くの開発者が最初にぶつかり、そして心折れそうになる「巨大な壁」があります。それが「座標系(UCSとWCS)のズレ」です。
- 「VBAで座標を指定して円を描いたのに、なぜか全然違う場所に配置される……」
- 「図面が傾いている(UCSが設定されている)と、マクロが正しく動かない!」
こうした現象に悩まされたことはありませんか?
実は、AutoCAD VBAの作図メソッドの多くは、私たちが普段見ている画面の座標系(UCS)ではなく、図面の絶対的な原点である「WCS(ワールド座標系)」を基準に動作します。
ここをクリアすれば、AutoCAD VBAの基本はバッチリですよ。今回は、この座標のズレを完璧に解決する魔法のメソッド`AcadDocument.Utility.TranslateCoordinates`をマスターして、どんなに傾いた図面でも狙った場所にピタッと図形を配置するプロの手法を伝授します。
優しく、かつプロの現場で即戦力となる深いところまで、一緒に紐解いていきましょう!
—
1. なぜズレる?WCSとUCSの「決定的な違い」
まずは、頭の中のモヤモヤをスッキリさせるために、AutoCADの2つの座標系をおさらいしましょう。
【WCS(ワールド座標系)】 = 宇宙の不変の真理(絶対座標)
↓ ↑ (ここを繋ぐのが TranslateCoordinates !)
【UCS(ユーザー座標系)】 = ユーザーが見ている現在の視点(傾いたローカル座標)
- WCS (World Coordinate System)
図面が持つ「絶対に動かない、不変の原点と軸」です。VBAの内部処理や、図面データベースの多くはこのWCSを基準に作図命令を受け取ります。
- UCS (User Coordinate System)
設計者が作業しやすいように、原点を移動したり、軸を傾けたりした「一時的な座標系」です。私たちが画面上でクリックして取得する座標は、このUCSに基づいています。
ズレが発生するメカニズム
例えば、ユーザーが画面上で「ここ(UCSでの `X=100, Y=100`)」をクリックしたとします。
しかし、VBAの `AddCircle` メソッドにそのまま `(100, 100)` を渡すと、VBAは「WCSの `X=100, Y=100`」に円を描いてしまいます。
UCSが傾いていればいるほど、原点がズレていればいるほど、完成した図形は「遥か彼方の意図しない場所」へ飛んでいってしまうのです。
—
2. 救世主 `TranslateCoordinates` メソッドの仕様
この「UCSでの座標」を「WCSでの座標」へ、あるいはその逆へと、一瞬で正しく翻訳(変換)してくれるのが、`AcadDocument.Utility.TranslateCoordinates` メソッドです。
まずはその基本構文を見てみましょう。
構文
ReturnValue = Document.Utility.TranslateCoordinates(Point, From, To, Disp [, OCSNormal])
引数の意味(ここが超重要!)
| 引数名 | データ型 | 役割 |
| :— | :— | :— |
| `Point` | `Variant` (Doubleの3要素配列) | 変換したい「元の座標」(X, Y, Z)です。 |
| `From` | `AcCoordinateSystem` (定数) | 変換前の座標系を指定します(※下記参照)。 |
| `To` | `AcCoordinateSystem` (定数) | 変換後の座標系を指定します(※下記参照)。 |
| `Disp` | `Boolean` (Long型でも可) | 位置として変換するか、方向(ベクトル)として変換するか。
・`False` (0): 位置座標(原点の移動を考慮する)
・`True` (1): ベクトル(原点を無視し、純粋な距離・方向のみ) |
| `OCSNormal` | `Variant` (Doubleの3要素配列・省略可) | OCS(オブジェクト座標系)を扱う際の「法線ベクトル」を指定します。 |
座標系を指定する定数(`From` と `To` に使うもの)
- `acWorld` (0): WCS(ワールド座標系)
- `acUCS` (1): 現在アクティブなUCS(ユーザー座標系)
- `acOCS` (2): OCS(オブジェクト座標系。ポリラインや円などを描く際に重要)
—
3. 【実践コード】傾いたUCSに完全対応する頑丈なVBAマクロ
それでは、実際に動くコードを見てみましょう。
このマクロは、以下のステップを正確に実行します。
1. ユーザーに画面上で「円の中心点」をクリックしてもらう(UCS座標の取得)。
2. その座標を `TranslateCoordinates` で WCS座標に変換 する。
3. 変換後のWCS座標を使って、図面に正確に円(Circle)を作図する。
Sub DrawCircleInCurrentUCS()
Dim acadApp As AcadApplication
Dim doc As AcadDocument
‘ 1. 現在のAutoCADインスタンスとドキュメントを取得
On Error Resume Next
Set acadApp = ThisDrawing.Application
Set doc = acadApp.ActiveDocument
On Error GoTo ErrorHandler
‘ 2. ユーザーから画面上で「中心点」を取得(これは現在のUCS座標で返されます)
Dim promptPoint As Variant
promptPoint = doc.Utility.GetPoint(, vbCrLf & “円の中心点をクリックしてください: “)
‘ 3. 半径を入力してもらう
Dim radius As Double
radius = doc.Utility.GetReal(“円の半径を入力してください: “)
‘ ==========================================
‘ 【核心部】UCS座標をWCS座標に変換する
‘ ==========================================
Dim wcsPoint As Variant
‘ From: acUCS (現在のUCS)
‘ To: acWorld (WCS)
‘ Disp: False (「位置」として変換するため、原点のズレを考慮する)
wcsPoint = doc.Utility.TranslateCoordinates(promptPoint, acUCS, acWorld, False)
‘ 4. WCSに変換された座標を使って、モデル空間に円を作図
Dim circleObj As AcadCircle
Set circleObj = doc.ModelSpace.AddCircle(wcsPoint, radius)
‘ 作図した円の色を赤にして、分かりやすくする
circleObj.Color = acRed
circleObj.Update
MsgBox “現在のUCSに対応した正確な位置(WCS: ” & _
Format(wcsPoint(0), “0.0”) & “, ” & _
Format(wcsPoint(1), “0.0”) & “)に作図しました!”, vbInformation, “成功”
Exit Sub
ErrorHandler:
MsgBox “エラーが発生しました: ” & Err.Description, vbCritical, “エラー”
End Sub
コードの解説:なぜこれでズレないのか?
`GetPoint` で取得した `promptPoint` は、ユーザーが見ている画面(UCS)の座標です。
これをそのまま `AddCircle` に渡すと、UCSが傾いている場合に位置がズレます。
しかし、上記のコードでは作図の直前に `TranslateCoordinates` を挟み、「ユーザーがクリックした『あの場所』は、WCS(宇宙の絶対座標)で言うとどこにあたるのか?」を計算し、その結果(`wcsPoint`)を作図メソッドに渡しています。
これにより、UCSがどれほど傾いていても、原点がどこに移動していても、ユーザーがクリックしたその場所に1mmの狂いもなく円が配置されるのです。
—
4. 中級者へのステップアップ:OCS(オブジェクト座標系)と「法線」の壁
円は比較的簡単ですが、ポリライン(LightweightPolyline)やハッチングを扱う場合、もう一つの座標系である OCS (Object Coordinate System) と向き合う必要があります。
軽量ポリライン(`AddLightweightPolyline`)は、2Dの座標(X, Y)しか受け付けません。そのため、「そのポリラインが乗っている平面(法線ベクトル:Normal)」の情報と、その平面上でのローカル座標(OCS)が必要になります。
これを解決するための、少し高度ですが実務で絶大な威力を発揮するコードパターンを紹介します。
傾いたUCS上に「ポリライン」を正しく描くコード
Sub DrawPolylineInUCS()
Dim doc As AcadDocument
Set doc = ThisDrawing.Application.ActiveDocument
‘ 1. 現在のUCSの「法線ベクトル(Z軸の向き)」を取得する
‘ UCSの Z軸 (0, 0, 1) が、WCSから見てどの方向を向いているかを変換
Dim ucsNormal(0 To 2) As Double
ucsNormal(0) = 0#: ucsNormal(1) = 0#: ucsNormal(2) = 1#
Dim wcsNormal As Variant
‘ 向き(ベクトル)を変換するため、第4引数 Disp は「True」にします!
wcsNormal = doc.Utility.TranslateCoordinates(ucsNormal, acUCS, acWorld, True)
‘ 2. ユーザーから3つの点を取得(現在のUCS上)
Dim p1 As Variant, p2 As Variant, p3 As Variant
p1 = doc.Utility.GetPoint(, “1点目を選択: “)
p2 = doc.Utility.GetPoint(p1, “2点目を選択: “)
p3 = doc.Utility.GetPoint(p2, “3点目を選択: “)
‘ 3. UCS座標を、この平面の「OCS座標」に変換する
Dim ocsP1 As Variant, ocsP2 As Variant, ocsP3 As Variant
ocsP1 = doc.Utility.TranslateCoordinates(p1, acUCS, acOCS, False, wcsNormal)
ocsP2 = doc.Utility.TranslateCoordinates(p2, acUCS, acOCS, False, wcsNormal)
ocsP3 = doc.Utility.TranslateCoordinates(p3, acUCS, acOCS, False, wcsNormal)
‘ 4. 軽量ポリライン用の頂点配列を作成 (2D座標なので X, Y のみ)
Dim vertices(0 To 5) As Double
vertices(0) = ocsP1(0): vertices(1) = ocsP1(1)
vertices(2) = ocsP2(0): vertices(3) = ocsP2(1)
vertices(4) = ocsP3(0): vertices(5) = ocsP3(1)
‘ 5. ポリラインを作図
Dim plineObj As AcadLWPolyline
Set plineObj = doc.ModelSpace.AddLightweightPolyline(vertices)
‘ 6. ポリラインに「法線ベクトル」をセットして、傾きを現在のUCSに合わせる
plineObj.Normal = wcsNormal
‘ 7. 高度(Elevation:Z方向の高さ)を調整
‘ OCS座標系のZ値をポリラインのElevationに代入
plineObj.Elevation = ocsP1(2)
plineObj.Update
End Sub
プロの解説:第4引数 `Disp` の `True` と `False` の使い分け
このコードでは、`TranslateCoordinates` を2回、異なる目的で使っています。
1. 法線ベクトルの変換(方向の変換)
wcsNormal = doc.Utility.TranslateCoordinates(ucsNormal, acUCS, acWorld, True)
ここでは、UCSの「Z軸の向き」をWCS基準に変換しています。これは「位置」ではなく「方向(矢印の向き)」なので、`Disp = True` を指定します。もし `False` にすると、UCSの原点位置のズレが加算されてしまい、異常な方向を指すベクトルになってしまいます。
2. 頂点座標の変換(位置の変換)
ocsP1 = doc.Utility.TranslateCoordinates(p1, acUCS, acOCS, False, wcsNormal)
こちらは「具体的なクリック位置」を変換しているため、原点の位置ズレを考慮する `Disp = False` を指定します。
—
5. 陥りやすいエラーと回避策
① 戻り値の型エラー(Type Mismatch)
`TranslateCoordinates` の戻り値は `Variant` ですが、内部には Double型の要素数3の配列(`Double(0 To 2)`) が入っています。
以下のような代入はエラーになります。
Dim myPoint(0 To 2) As Double
‘ エラー! Variantを固定長配列に直接代入することはできません。
myPoint = doc.Utility.TranslateCoordinates(promptPoint, acUCS, acWorld, False)
【対策】
受け取る変数は必ず `Variant` として宣言してください。
Dim myPoint As Variant ‘ OK!
myPoint = doc.Utility.TranslateCoordinates(promptPoint, acUCS, acWorld, False)
② パフォーマンスの考慮(ループ内での注意)
大量の点群(数千〜数万点)をループ処理の中で変換する場合、毎回 `TranslateCoordinates` を呼び出すとAPIの呼び出しオーバーヘッドが蓄積し、処理が重くなります。
変換行列(マトリクス)を自前で計算して配列一括で処理する手法もありますが、通常の数千点レベルであれば、VBAの実行速度でも十分に実用範囲内です。まずは「正しく変換できること」を最優先に実装しましょう。
—
まとめ:これで座標系はあなたの支配下に!
今回のポイントを整理しましょう。
1. AutoCAD VBAの作図メソッドは基本的に「WCS(世界座標)」で命令を待っている。
2. ユーザーが画面を操作して得る座標は「UCS(ユーザー座標)」。
3. その架け橋となるのが `TranslateCoordinates` メソッド。
4. 「位置」の変換なら `Disp = False`、「方向(ベクトル)」の変換なら `Disp = True`。
この座標変換さえマスターしてしまえば、「図面が傾いているからマクロが使えない」といったユーザーからのクレームは一切なくなります。どんな図面、どんなUCSが設定されていても、あなたのマクロは常に「狙ったその場所」に美しく図形を描画してくれるでしょう。
一歩一歩、コードを書いて試してみてください。これをクリアしたあなたのAutoCAD VBA開発スキルは、確実に「プロの実務レベル」へと到達しています。
素晴らしい開発ライフを応援しています!
