新規コマンド

AutoCAD のカスタマイズ

AutoCAD のカスタマイズといえば、画面の色の設定やAutoCAD のコマンドにアクセスしやすいようにリボンやツールバーの位置の設定といった、AutoCAD ユーザーの好みや事情といえるものがまず上げられます。

次のレベルとして、コマンドエイリアスの設定、繰り返しの決まった手順にはコマンドを羅列したスクリプトや【アクションレコーダー】でマクロを作成する方法もあります。多少の不便を解消するためならば、こういったカスタマイズ方法で比較的容易に対応できる場合があります。それから発展して、カスタムツールバーやツールパレットを利用してマクロのコマンド入力欄に固定のオプション文字を含めたカスタムコマンドといえるようなもの作成し、入力作業を減らして楽に作業できるようなものもあります。これには DIESEL 文という原始的なプログラミング言語を含めることで多少の柔軟性をもたせることができますが、LISP 式も【コマンドライン】は受け付けますので、LISP のプログラムをマクロのコマンド入力欄に書くこともできます。

次のマクロは AutoLISP のコードをコマンド入力欄に記述したもので、ROTATE コマンドのオプションをコピーモードで実行します。この程度のプログラムを書いたと言えないような簡易なものでも AutoLISP の知識は有用です。

^C^C(progn (command "._ROTATE" (ssget) "" (getpoint) "_C" (* 180.0 (/ (getangle) PI))) (princ))

ただし、このようなマクロで書ける量は見やすさのため制限があります。既存の複数のコマンドを組み合わせて新しいコマンドを作成したり、独自の幾何計算をもとに新しい図形を作図するコマンドを作成したりするのをマクロのコマンド欄で作成することは現実的ではありませんので、そのようなものはテキストファイルにプログラムを書くことになります。そのような規模のプログラムになると、マクロでは疎かにしていたエラーチェックを行う必要が出てきますので、輪をかけてプログラムがさらに複雑になって行きます。そして、そのような複雑なプログラムは AutoLISP の関数という形で実現されます。

AutoLISP によるマクロでは表現しきれない複雑な構造の本格的なカスタムコマンドは、そのアウトプットは最終的に AutoCAD の図形要素で表現できるものに限られますが、いくら人間が時間を使ってよいとしてもそれを実際に実行するのは現実的でない、新しいことが行えるようになります。

新しいコマンドとなる関数の形式

AutoLISP で AutoCAD を本格的にカスタマイズすることは、AutoCAD に新しいコマンドを追加することでした。そして新しいコマンドを追加することは、AutoCAD の内部で動いている AutoLISP 実行環境に新しい関数を追加することです。AutoCAD ユーザーが追加された新しいコマンドを実行しようとすると、AutoLISP 実行環境に追加された新しい関数が実行されます。

追加された関数がすべて AutoCAD ユーザーからコマンドとして直接呼び出されるわけではありません。コマンドとする関数を起点に他のサポート関数を呼び出すことは自由に行えます。

コマンドとして機能させる関数の指定の仕方は二つの方法があります。

一つ目は、コマンドの名前として使いたい関数のシンボル名に「c:」という接頭辞をつけます。この接頭辞をつけた関数は AutoCADユーザーから通常のコマンドと同じように呼び出されることができます。例えば「NEWCOMMAND」というコマンドを作りたければ、「c:NEWCOMMAND」という名前の関数を定義します。AutoCAD ユーザーは、【コマンドライン】に「NEWCOMMAND」とタイプすれば、c:NEWCOMMAND 関数が実行されます。

二つ目は、vlax-add-cmd 関数を用いてコマンドとして使う関数を登録する方法です。この方法でコマンドとして登録する関数名は「c:」という接頭辞は必要ありません。

AutoLISP関数
(vlax-add-cmd global-name func-sym [local-name cmd-flags])
global-name:文字列
func-sym:シンボル
local-name:文字列
cmd-flags:整数
指定した関数をAutoCADのコマンドとして登録します。
戻り値:文字列、又は nil
AutoLISP関数
(vlax-remove-cmd global-name)
global-name:文字列
指定されたコマンドを AutoCAD から登録解除します。
戻り値: nil、またはnil以外

vlax-add-cmd 関数は関数を AutoCAD のコマンドとして登録します。vlax-remove-cmd 関数は反対にコマンドを登録解除します。この方法は、他のコマンド実行中に使用できる【割り込みコマンド】を登録できる他、他の組み込みコマンドと同様に別のプログラムから command 関数で呼び出すことができるようになります。言い換えますと、一つ目の「c:」という接頭辞で登録したコマンドは、他のところから command 関数で実行することはできません。注意点としては、vlax-add-cmd 関数にはバグともいえる落とし穴があります。この点は後回しにして、関数の使い方は以下のとおりです。

global-name 引数は新しく登録するコマンド名を表す文字列です。

func-sym 引数はコマンドに関連付けられる関数です。引数は関数名を渡すので、関数シンボル名を「‘」(シングルクォーテーション)でクォートします。

local-name 引数は global-name 引数のコマンド名と平行して使用できる別名を使いたい場合に使用できます。この引数は、例えば英語以外のコマンド名を使いたいといった多言語対応という意味でのローカル(特定の地方)です。この別名は後述の getcname 関数で対応を確認できます。

cmd-flags で指定する値は次のとおりです。複数のオプションを選びたいときは該当する整数の和をとります。省略された場合は 4 、すなわち割り込み不可の通常のコマンドとなります。

定義済みのシンボル ユーザーの入力
0 ACRX_CMD_MODAL 【割り込みコマンド】として使用不可
1 ACRX_CMD_TRANSPARENT 【割り込みコマンド】として使用可
2 ACRX_CMD_USEPICKSET プログラムがコマンド実行以前に選択されていた図形を取得すると、選択がクリアされます。
4 ACRX_CMD_REDRAW プログラムがコマンド実行以前に選択されていた図形を取得しても、選択がクリアされるようなことはありません。

これらの関数の戻り値は vlax-add-cmd 関数がコマンド登録に成功した場合は global-name 引数の文字列、失敗した場合は nil を、vlax-remove-cmd 関数が登録解除に成功した場合は nil 以外を、既に登録が解除されているなど失敗した場合は nil を返します。

vlax-add-cmd 関数でコマンドを登録する方法にはバグではないかと思われる二重の落とし穴があります。それは、この関数の影響は現在開いている図面や名前空間内でおさまらず AutoCAD アプリケーション全体に及びます。そのため、vlax-add-cmd 関数を使っているプログラムをロードしている図面に加えて、新たに図面を開き同じプログラムをロードして vlax-add-cmd 関数を使うと改めてのコマンド登録に失敗します。これが一つ目の落とし穴です。これの回避方法は、vlax-add-cmd 関数を使う前に、vlax-remove-cmd 関数でコマンドの登録を念のため解除しておきます。ところが、今度は登録解除した際に既に開いていた図面の方でコマンドが使えなくなります。これが二つ目の落とし穴です。これの回避策は、現在の図面が AutoCAD ユーザーによって切り替わるたびに、リアクタという AutoLISP の機能を使って最初に述べたコマンドの登録解除と登録を自動で行います。

以上のような vlax-add-cmd 関数のバグを回避するために以下のような add-command 関数とリアクタを登録するコードを使ってください。

add-command 関数の引数は vlax-add-cmd 関数と同じですが省略はできないので、その場合は nil を指定します。戻り値も vlax-add-cmd 関数と同じです。グローバル変数 *list-of-command* は一度登録されたコマンドの情報を保持し、再登録の際に使用されます。

(vl-load-com)

(setq *list-of-command* nil)

;;;
;;; Alternative to vlax-add-cmd function
;;;

(defun add-command (global-name func-sym local-name cmd-flags / result add-args)
  (vlax-remove-cmd global-name)
  (if (setq result (apply 'vlax-add-cmd
                          (setq add-args (list global-name
                                               func-sym
                                               (if local-name
                                                 local-name
                                                 global-name
                                               )
                                               (if cmd-flags
                                                 cmd-flags
                                                 4
                                               )
                                         )
                          )
                   )
      )
    (setq *list-of-command* (cons add-args *list-of-command*))
  )
  result
)

;;;
;;; add-command reactor
;;;

(defun add-command-callback (reactor_object args)
  (foreach add-args *list-of-command*
    (vlax-remove-cmd (car add-args))
    (apply 'vlax-add-cmd add-args)
  )
)

(vlr-docmanager-reactor
  nil
  '((:vlr-documentBecameCurrent . add-command-callback))
)

以上、二つの方法で関数をコマンドとして使用することができるようになりますが、コマンドとなる関数には引数を与えることができません。ローカル変数は通常通り使えます。

また、コマンドの関数として必須のことではありませんが、AutoLISP の関数は必ず戻り値があります。戻り値は、何もしなければコマンド実行の後に【コマンドライン】に表示されます。多くの場合、戻り値の表示はユーザーにとって必要のないことですから、最後に「(princ)」という空の戻り値を返す式を書きます。

まとめますと、コマンドとなる関数の指定方法の一つは次のような形で宣言します。

(defun c:NEWCOMMAND (/ local01 local02)
    <コマンドの内容>
    (princ)
)

また、vlax-add-cmd 関数のバグを回避した add-command 関数を使用する場合は次のような形式となります。

(defun myNewCommand (/ local01 local02)
    <コマンドの内容>
    (princ)
)

(add-command "NEWCOMMAND" 'myNewCommand nil nil)

add-command 関数で間接的に vlax-add-cmd 関数を使用して登録したコマンドは、command 関数から呼び出すこともできます。

(command "NEWCOMMAND")

このようにコマンドとした関数を【独自の名前空間 VLX アプリケーション】内で使用した場合、関数を vl-doc-export ステートメントで公開すると宣言しなくてもコマンドとして呼び出すことができるようになります。

多言語対応されたコマンド名

AutoLISP関数
(getcname cname)
cname:文字列
AutoCAD コマンド名から英語以外の言語に翻訳された AutoCAD コマンド名を、または翻訳されたコマンド名から元の AutoCAD コマンド名を取得します。
戻り値:文字列、またはnil

getcname関数は、英語以外にコマンド名が翻訳されている各国語バージョンで、本来の英語名を取得したり、翻訳されたコマンド名の別名を取得したりできます。また、vlax-add-cmd 関数で登録したオリジナルのコマンド名と別名の対応関係を確認することができます。

別名を得るには、オリジナルのコマンド名に「_」(アンダーバー)を付けて実行します。また、別名を指定して実行するとオリジナルのコマンド名が得られます。

_$ (vlax-add-cmd "my-command" 'my-command01 "私のコマンド")⏎   ; add-command 関数でも同じ
"my-command"
_$ (getcname "_my-command")⏎
"私のコマンド"
_$ (getcname "私のコマンド")⏎
"_MY-COMMAND"