AutoCAD コマンド

AutoCAD コマンドの実行

AutoLISP関数
(command [arguments] ...)
arguments:式
AutoCAD コマンドを実行します。
戻り値:nil
AutoLISP関数
(vl-cmdf [arguments] ...)
arguments:式
AutoCAD コマンドを実行します。
戻り値:nil以外

command 関数と vl-cmdf 関数は、AutoCAD のコマンドを実行することで AutoCAD にアクセスします。これにより基本的な AutoCAD のモードコントロールや作図はできてしまいますので、簡単なカスタムコマンドの作成などにはこれで十分です。

引数は、通常ではユーザーが AutoCAD との対話で【コマンドライン】に応答する内容を模して、区切った文字列で並べます。それに加えて、AutoLISP の変数や座標を表すリストを指定することもできます。

戻り値は、command 関数は nil を、vl-cmdf 関数は nil 以外を必ず返します。

コマンド名の修飾

AutoCAD のシステムは非常に柔軟なので、既存のコマンドもプログラムによって上書きすることができます。そのため、既存のコマンドを呼んだつもりが、変更されたコマンドとなっていたというような事態を避けるため、コマンドの前に「.」(ピリオド)を付けると、必ず既存のコマンドを呼び出すことができます。

その他を含めて、コマンド名の先頭を修飾するものには以下のような意味があります。

修飾 説明
「.」ピリオド 既存のコマンドを呼び出します。
「‘」シングルクォーテーション 割り込みコマンドとして実行します。
「_」アンダーバー 多言語対応の中で、オリジナルの英語のコマンド名であることを意味します。

command 関数と vl-cmdf 関数の違いは、引数が評価される順番です。command 関数は、コマンドを実行してから、順番に引数の文字列や変数を評価してAutoCAD に渡していく、AutoCAD ユーザーにとっては自然ですが通常の LISP とは異なった順番です。対して vl-cmdf 関数はコマンドを実行する前に引数の評価をすべて行うという LISP 本来の順で評価を行います。vl-cmdf 関数の場合、引数の評価途中でエラーが発生した場合は指定されたコマンド自体の実行までたどり着きませんが、command 関数では引数の値が求まる過程で AutoCAD の別のコマンドを使用していると既に command 関数が実行を開始しているコマンドと干渉してエラーとなります。

経験的に command 関数より vl-cmdf 関数の方が安定しています。そして command 関数、vl-cmdf 関数とも、コードや引数に誤りは無くてもAutoCAD が内部エラーで終了してしまうことがあります。どのような条件で不安定になるのか分かりませんが、ユーザーからの入力待ちを行わないものならば、新しい command-s 関数が安定しています。

下の例は、斜めの直線を AutoCAD に作図させる例です。最後の””(空の文字列)は Enter キーと同じ意味になります。AutoCAD ユーザーが Enter キーを押すまで繰り返されるコマンドでは、最後に””を付加する必要があります。

_$ (command "._LINE" "0,0" "100,100" "")⏎
nil
_$ (vl-cmdf "._LINE" "0,100" "100,0" "")⏎
T

引数には、AutoLISP の適当な変数や座標を表すリストを渡すこともできます。

(setq pt1 '(0.0 0.0)
      pt2 '(100.0 100.0)
      pt3 '(0.0 100.0)
      pt4 '(100.0 0.0)
)
(command "._LINE" pt1 pt2 "")
(vl-cmdf "._LINE" pt3 pt4 "")

最後に command 関数と vl-cmdf 関数の引数の評価の順が異なる点がプログラミングスタイルに影響を及ぼすことを説明します。これは、いくつかの AutoCAD コマンドを組み合わせているケースで現れてきます。ここでは、二次元の円や閉じたポリラインをリージョンのように和をとる問題に取り組んでいるとします。円やポリラインは形の編集が可能ですが、リージョンは UNION コマンドで和をとることはできるのですが形の編集が行えません。それぞれ長短があるオブジェクトです。そのためここでは、円やポリラインをまずリージョンに変換して和をとった後に再びポリラインに変換するという方法をとります。ここでは引数として二つの図形を表す【図形名】をとる関数を作成することとし、引数の図形が二次元で閉じていることすなわちリージョンに変換可能なことは保障されているとします。戻り値は、和をとられたポリラインの【図形名】です。

command 関数を使うスタイルは次のようになります。

(defun union2D-command (ename1 ename2 / peditaccept)
  (command "._REGION" ename1 "")
  (setq ename1 (entlast))
  (command "._REGION" ename2 "")
  (setq ename2 (entlast))
  (command "._UNION" ename1 ename2 "")
  (command "._EXPLODE" (entlast))
  (setq peditaccept (getvar "PEDITACCEPT"))
  (setvar "PEDITACCEPT" 1)
  (command "._PEDIT" "_M" "_P" "" "_J" "" "")
  (setvar "PEDITACCEPT" peditaccept)
  (entlast)
)

vl-cmdf 関数を使うスタイルは次のようになります。

(defun union2D-cmdf (ename1 ename2 / peditaccept)
(vl-cmdf
"._EXPLODE"
(progn (vl-cmdf "._UNION"
(progn (vl-cmdf "._REGION" ename1 "") (entlast))
(progn (vl-cmdf "._REGION" ename2 "") (entlast))
""
)
(entlast)
)
)
(setq peditaccept (getvar "PEDITACCEPT"))
(setvar "PEDITACCEPT" 1)
(vl-cmdf "._PEDIT" "_M" "_P" "" "_J" "" "")
(setvar "PEDITACCEPT" peditaccept)
(entlast)
)

どちらのスタイルが優れているという話ではなく、コマンド的・スクリプト的の command 関数に対してプログラミング言語的なスタイルの vl-cmdf 関数となります。

AutoLISP関数
(command-s [arguments] ...)
arguments:式
AutoCAD コマンドを実行します。
戻り値:nil

command-s 関数は AutoCAD 2012 以降でサポートされた関数です。command 関数と基本的な扱い方は同じですが、arguments 引数には後述のユーザーから入力を待つ PAUSE は使用できません。また、一つの command-s 関数内で、AutoCAD コマンドの開始から終了までまとめて書く必要があります。もし、command-s 関数の開始時や終了時にAutoCAD コマンドが未了だった場合は、途中のコマンドはキャンセルされます。

command 関数の「コルーチン(co-routine)」的な動作に対して、command-s 関数の末尾の「-s」は「サブルーチン(subroutin)」の意味とされています。そして、command-s 関数は command 関数より高速であるとされています。

PAUSE

ユーザーからの入力を受け取りたい場合は、command 系関数内に以下のように簡単に文字列 ”¥¥” またはシンボル PAUSE を与えることでも書けます。PAUSE に当たると、 command 系関数はユーザーからの入力待ちになります。

_$ (command "._LINE" PAUSE PAUSE "")⏎
nil
_$ (vl-cmdf "._LINE" PAUSE PAUSE "")⏎
T

ただし、PAUSE で想定するユーザーからの入力は、点の指定や単一の図形の選択、また距離の入力といった、ひとつのものに関する入力に限ります。すなわち「オブジェクトを選択:」とプロンプトが出ていても、得たいのが単一の図形の場合と複数の図形(【選択セット】)の場合があり、前者の場合は PAUSE でも可能ですが、後者の場合はうまく動ききません。また、距離の数値を得たい場合でも、数値をキーボードから入力した場合は大丈夫ですが、ユーザーが二点を指定してその距離とした場合は、正しく動きません。

正しく動かない可能性のある例を次に挙げます。 単純な ROTATE コマンドの実行を想定しています。

(command "._ROTATE" PAUSE PAUSE PAUSE)

ROTATEコマンドのプロンプトは次のようなものです。

  1. オブジェクトを選択:
  2. 基点を指定:
  3. 回転角度を指定 または [コピー(C)/参照(R)] <0.00>:

上の例では、最初の PAUSE は複数の図形選択ですので PAUSE ではうまく動きません。正しくは ssget 関数を利用して【選択セット】をユーザーから受け取る形にします。最後の三つめの PAUSE は回転角度を受け取るものですが、ROTATE コマンドではコピーや参照のオプションも選択できるようになっており、オプションに対する動作は一つの PAUSE では対応できません。ここではオプションを排して getangle 関数を介して角度の入力のみを対象にします。【選択セット】や getangle 関数といったユーザーから入力を受け取る関数は、後ほど説明します。

正しく動くように書き直すと次のようになります。

(command "._ROTATE" (ssget) "" (setq center (getpoint)) (* 180.0 (/ (getangle center) PI)))

最初の PAUSE は「(ssget) ""」に置き換わりました。これはユーザーから複数の図形選択を受け取り【選択セット】として ROTATE コマンドに渡します。次の「 ””」 すなわち Enter は ROTATE コマンドのオブジェクト選択を終了させるものです。

二番目の PAUSE は「(setq center (getpoint))」に置き換わりました。基点だけなら PAUSE で対応可能ですが、三番目の角度指定のために getpoint 関数で座標を取得し、基点の座標を center に保存します。

三番目の PAUSE は「(* 180.0 (/ (getangle center) PI)))」に置き換え、getangle 関数で得られた数値を利用しています。この関数はラジアンで角度が返りますのでユーザーが入力する度の数値にあわせて再び変換しています。

このように結局 PAUSE は他の関数に置き換えられました。PAUSE は一行マクロなどで簡易に使うためには便利ですが、エラーチェックなどユーザーの想定外の行動には対応できません。そのため、本格的なカスタムコマンドの中で使うことはお勧めできません。カスタムコマンドの関数では command 系関数のコマンド実行時に PAUSE を使ってユーザーの入力を得るより、コマンドを実行する前に AutoLISP 備え付けのユーザー入力関数を使ってユーザー入力をひととおり受けとり、その入力が想定内の正しいものであるか確認の上、コマンドを実行するような次のような構成とするべきです。

(defun c:NEWCOMMAND (/ local01 local02)
    (if (ユーザー入力と値のチェック)
      <コマンドの実行>          ; then 節
    )
    (princ)
)

ここで扱っている ROTATE コマンドの単純な実行をカスタムコマンドの形で書き表すと、次のようになります。

(defun c:MyRotate (/ ss center radian)
  (if (and (setq ss (ssget))
           (setq center (getpoint))
           (setq radian (getangle pt))
      )
    (command "._ROTATE"
             ss
             ""
             center
             (* 180.0 (/ radian PI))
    )
  )
  (princ)
)

とりあえずここではユーザー入力関数からの戻り値が nil で無いことを確認しています。どこかの時点でユーザーが空入力をして入力関数が nil となった場合、and 関数で次の入力関数には行かず、このカスタムコマンドの関数は終了します。

システム変数へのアクセス

次の関数は、AutoCADのシステム変数にアクセスします。システム変数は大変多くの種類があるため、それぞれの説明はヘルプを参照してください。

AutoLISP関数
(getvar varname)
varname:文字列
AutoCADのシステム変数の値を取得します。
戻り値:アトム、またはリスト

getvar 関数はシステム変数の値を取得します。

varname 引数には、取得するシステム変数の名前を文字列で指定します。

戻り値はシステム変数の値ですが、値のデータタイプは変数の種類によります。varname 引数の名前が不適切だった場合は nil が返ります。

次の例は、現在のレイヤー名を保持している CLAYER の値を取得しています。

_$ (getvar "CLAYER")⏎
"0"
AutoLISP関数
(setvar varname value)
varname:文字列
value:アトム、またはリスト
指定された値をAutoCADシステム変数に代入します。
戻り値:アトム、またはリスト

setvar 関数はシステム変数の値を設定します。

varname 引数には、設定するシステム変数の名前を文字列で指定します。

value 引数は設定する値を指定します。

戻り値は、設定が正常に行われた場合は設定した値が、varname 引数の名前が不適切だったなど失敗した場合はnilが返ります。

次の例は、CLAYER の値を変更することで現在のレイヤーを変更しています。

_$ (setvar "CLAYER" "mylayer")⏎
"mylayer"

AutoCAD コマンド実行時のシステム変数

command 関数系を使って AutoCAD のコマンドを呼び出すにあたって、ユーザーにどのように表示されるか考慮しておく必要があります。

システム変数 CMDECHO が 1 の場合は、【コマンドライン】にプロンプトがエコーされます。

システム変数 CMDECHO

タイプ: 整数型 保存先: なし 初期値: 1

プログラムの command 関数から実行される AutoCAD のコマンドで、プロンプトの表示はシステム変数 CMDECHO で制御されています。

0 エコーバック表示しません。
1 エコーバック表示します。

AutoCAD のユーザーによってはクリックした点の跡が残るシステム変数 BLIMPMODE を 1 にしている場合も考えられます。

システム変数 BLIPMODE

タイプ: 整数型 保存先: レジストリ 初期値: 0

BLIPMODE が有効の場合、選択された点にマーカーが表示されるようになります。マーカーはただの目印なので、REDRAW コマンドで画面を再描画すると消えます。

0 マーカーの表示モードをオフにします。
1 マーカーの表示モードをオンにします。

また、プログラムで指定した点が、確実にその点と認識されるために、オブジェクトスナップの機能をオフにする必要も出てきます。

システム変数 OSMODE

タイプ: 整数型 保存先: レジストリ 初期値: 4133

定常オブジェクトスナップを設定します。設定値は次の数値の和として表されます。

0 NON(解除)
1 END(端点)
2 MID(中点)
4 CEN(中心)
8 NOD(点)
16 QUA(四半円点)
32 INT(交点)
64 INS(挿入基点)
128 PER(垂線)
256 TAN(接線)
512 NEA(近接点)
1024 オブジェクトスナップ有効/無効。NON とは異なり、設定を温存したままスナップの有効/無効を切り替えます
2048 APP(仮想交点)
4096 EXT(延長)
8192 PAR(平行)

具体的な例として、中心と半径を指定して星形のポリラインを描き内側をハッチで塗りつぶすコマンドを次のように作成しました。

c:star 関数がコマンドの本体です。ユーザーからの入力を受け描いたポリラインを、entlast 関数で取得して HATCH コマンドで使用しています。後述しますが entlast 関数は直近に作成した図形を返します。コマンドの核の部分は次の二行です。

(drawPolyline (StarData center radius) T)
(command "._HATCH" "_S" "_S" (entlast) "")
(defun StarData (center radius / offset step)
  (setq offset (/ PI 2.0)
        step   (/ (* 2 PI) 5.0)
  )
  (apply
    'append
    (mapcar (function
              (lambda (index)
                (list (polar center (+ offset (* step index)) radius)
                      (polar center (+ offset (* step index) (/ step 2.0)) (/ radius 2.0))
                )
              )
            )
            '(0 1 2 3 4)
    )
  )
)

(defun drawPolyline:sub (plist closed /)
  (if plist
    (progn (command (car plist)) (drawPolyline:sub (cdr plist) closed))
    (if closed
      (command "_C")
      (command "")
    )
  )
)

(defun drawPolyline (plist closed /)
  (command "._PLINE")
  (drawPolyline:sub plist closed)
)

(defun c:star (/ radius center)
  (if (and (setq center (progn (initget (+ 1 2 4))
                               (getpoint "\n中心を指定 : ")
                        )
           )
           (setq radius (progn (initget (+ 1 2 4 64))
                               (getdist center "\n半径を入力 : ")
                        )
           )
      )
    (progn (drawPolyline (StarData center radius) T)
           (command "._HATCH" "_S" "_S" (entlast) "")
    )
  )
  (princ)
)

コマンド本体以外のサポート関数では、StarData 関数は、中心と半径を与えることで描く星形の頂点をおさめたリストを生成します。使い方と返すリストの形式は以下の通りです。

_$ (StarData '(0.0 0.0) 100.0)⏎
((6.12323e-015 100.0) (-29.3893 40.4508)<中略>(95.1057 30.9017) (29.3893 40.4508))

drawPolyline 関数は、StarData 関数から得られた点のリストにしたがってライトウェイトポリラインを描きます。最後の closed 引数をnil 以外にすることで、閉じたポリラインを描きます。

ひとまずこれで目的のコマンドは作成できました。しかし、状況によっては下のように望み通りには動きません。まず、オブジェクトスナップが背景の線に働いて、星の形が崩れています。次に BLIPMODE の白色のマーカーはユーザーにとっては不要のものでしょう。

AutoLISP Sample 01

また【コマンドライン】のヒストリーにも、AutoCAD ユーザーにとっては必要のない情報が表示されます。

AutoLISP Sample 01

これらを改良した、システム変数を操作する新しい c:star2 関数は次の通りです。まず、システム変数 CMDECHO、BLIPMODE、OSMODE の値を退避させたうえでこれらの効力を無効化します。そして目的の図形を描いた後でシステム変数の値を元に戻します。ついでに、UNDO コマンドで戻るときに、ハッチを消す、ポリラインを消す、と一つずつ戻るのはわずらわしいので、UNDO コマンドからコマンドのグループ化を行っています。

また、このような短いプログラムの場合にエラーが発生することはあまり考えにくいですが、システム変数を操作するので、エラー関数を定義して確実にシステム変数が元の状態に戻るようにします。

(defun star:error (msg)
  (if command-s
    (progn (command-s "._undo" "_e") (command-s "._U"))
    (progn (command "._undo" "_e") (command "._U"))
  )
  (setvar "CMDECHO" CMDECHO)
  (setvar "BLIPMODE" BLIPMODE)
  (setvar "OSMODE" OSMODE)
  (princ)
)

(defun c:star2
       (/ radius center CMDECHO BLIPMODE OSMODE *error*)
  (if (and (setq center (progn (initget (+ 1 2 4))
                               (getpoint "\n中心を指定 : ")
                        )
           )
           (setq
             radius (progn (initget (+ 1 2 4 64))
                           (getdist center "\n半径を入力 : ")
                    )
           )
      )
    (progn (setq CMDECHO  (getvar "CMDECHO")
                 BLIPMODE (getvar "BLIPMODE")
                 OSMODE   (getvar "OSMODE")
                 *error*  star:error
           )
           (setvar "CMDECHO" 0)
           (setvar "BLIPMODE" 0)
           (setvar "OSMODE" 0)
           (command "._undo" "_be")
           ;;
           (drawPolyline (StarData center radius) T)
           (command "._HATCH" "_S" "_S" (entlast) "")
           ;;
           (command "._undo" "_e")
           (setvar "CMDECHO" CMDECHO)
           (setvar "BLIPMODE" BLIPMODE)
           (setvar "OSMODE" OSMODE)
    )
  )
  (princ)
)

正しい星形が描かれるようになり、【コマンドライン】にも必要以上の情報は表示されなくなりました。

AutoLISP Sample 02
AutoLISP Sample 02

ここで作成したサンプルコマンドは、以降でも取り上げ、部分的に改良していきます。