カスタム入力関数

リアルタイムユーザー入力

AutoLISP関数
(grread [track] [allkeys [curtype]])
track:nil、またはnil以外
allkeys:整数
curtype:整数
キーボード、あるいはポインティングディバイスからの入力値を読み取ります。
戻り値:リスト

grread 関数は、入力デバイスからユーザーの入力値をリアルタイムで読み取ります。関数呼び出し時にESCキーが押されていると「コンソールブレーク」というエラーが発生します。

track 引数は、nil 以外のときには allkeys 引数で 1 を指定したのと同じようにドラッグモードでマウスカーソルのリアルタイム読み取りを行います。

allkeys 引数は、以下の整数の合計で複数のオプションを表します。

allkeys 引数 説明
1 ドラッグモードを有効にし、マウスカーソル座標のリアルタイム読み取りを行います。有効でない場合は、AutoCADユーザーの入力待ち状態となり、マウスをクリックしたとき、キーを押したときといったイベントが発生した時に、マウス移動以外のイベントを返すモードとなります。
2 ファンクションキーやカーソル移動キーを含めたすべてのキーの読み取りをします。
4 curtype 引数によるマウスカーソルの形態の変更を有効にします。
このビットが無効の時は、クロスカーソルにターゲットカーソルを加えた通常の形状となります。
8 「コンソールブレーク」のメッセージを、ユーザーに表示しません。

curtype 引数は、マウスカーソルの形態を変更することができます。

curtype 引数 説明
0 クロスヘアカーソル(縦横の線で表されるカーソル)
1 非表示(文字通りカーソルは表示されません)
2 ターゲットカーソル(小さい四角)

grread 関数の戻り値は、第 1 要素にイベントの意味、第 2 要素にイベントに応じたデータが格納されたリストが返ります。リストの、おおよその意味は以下のとおりです。

第1要素 第2要素
2 キーボード入力の文字コード
3 左クリックされた UCS 3D 点
4 スクリーンメニュー、プルダウンメニューの項目番号
5 マウスカーソルのリアルタイム UCS 3D 座標
6 ボタンメニューの項目番号
7,8,9,10 タブレットメニューの項目番号
11 AUX メニューの項目番号
12 メニュー項目を選択した際の 3D 点
25 右クリックされた点の作図領域のピクセル X 座標

次の例は grread 関数のモードを変更しながら、動作を確認するプログラムです。AutoCAD にロードすると実行されます。

「t」「d」「c」キーを押すと、それぞれ track 引数、ドラッグモード、カーソルタイプのモードを変更します。grread 関数が返すリストは【モードステータスバー領域】に表示されます。イベントの返るタイミングや返り値の確認を行ってみてください。

(defun grreadTest:echoMode ()
  (prompt (strcat "¥n track ="
                  (vl-princ-to-string track)
                  " , dragmode = "
                  (vl-princ-to-string dragMode)
                  " , curtype = "
                  (vl-princ-to-string curtype)
          )
  )
  (prompt "\n [t : toggle track , d : toggle drag mode , c : change curtype]")
)

(setq track nil
      dragMode 0
      curtype 0
)
(prompt "¥ngrread 関数のサンプル(ESCキーで終了)\n")
(grreadTest:echoMode)
(while T
  (setq device (grread track (+ dragMode 2 4))
        code   (car device)
        data   (cadr device)
  )
  (grtext -1 (vl-princ-to-string device))
  (cond ((= code 2)
         (cond ((= data (ascii "t")) (setq track (if track nil T)))
               ((= data (ascii "d")) (setq dragMode (Boole 6 dragMode 1)))
               ((= data (ascii "c")) (setq curtype (rem (1+ curtype) 3)))
         )
         (prompt (strcat "\¥KEY PRESS : " (chr data) " (" (itoa data) ")"))
         (grreadTest:echoMode)
        )
  )
)

オブジェクトスナップ

AutoLISP関数
(osnap pt mode)
pt:リスト
mode:文字列
指定された点を、オブジェクトスナップモードを適用した点に変換します。
戻り値:リスト

osnap 関数は、指定したモードで点を【オブジェクトスナップ】させます。スナップする点が見つからない場合は nil を返します。

pt 引数はスナップさせる点を表すリストを与えます。AutoCADを使用していれば解っていることですが、スナップが有効になる距離は、画面表示とピックボックスのサイズに左右される相対的なものですので、osnap 関数から、あるケースではスナップされた座標が返ってきても、別のケースではスナップが効かない時があります。

mode 引数は【オブジェクトスナップ】モードを”,”(カンマ)でつなげた文字列を指定します。スナップモードを複数指定したものと、モードごとに個別にスナップさせたものと、当然ながら結果が異なってきます。また、「垂線」や「接線」といった二点によりスナップ先が決まるものは、システム変数 LASTPOINT の値も使われます。

オブジェクトスナップモードは以下の種類があります。osnap 関数で動作が確認できないものはグレーの網掛けをしておきます。

2Dオブジェクトスナップモード
END,ENDP 端点 INT 交点 GCE 図芯
MID 中点 INS 挿入基点 APP 仮想交点
CEN 中心 PER 垂線 EXT 延長
NOD TAN 接線 PAR 平行
QUA 四半円点 NEA 近接点    

点群へのスナップは、AutoCAD 2015 より登場して、2016 ではさらに数が増えていまが、未確認です。

3Dオブジェクトスナップ 3Dオブジェクトスナップ(点群)-未確認
ZVER 頂点、制御点 PNOD
ZMID エッジの中点 PNEA 近接平面
ZCEN 面の中心 PPER 面の垂線
ZKNO ノット PINT 交点
ZPER 面の垂線 PEDGE エッジ
ZNEA 近接面 PPEDGE エッジの垂線
    PCOR コーナー
    PCL 中心線

osnap 関数の一般的な使用例として、次の例では、端点と中点のスナップを有効にして、スナップが効くか検証しています。

_$ (osnap '(90 0 0) "END,MID")⏎
(100.0 -1.42109e-014 0.0)
_$ (osnap '(30 0 0) "END,MID")⏎
nil

osnap 関数は、どのモードでスナップしたのか不明です。また、AutoCAD ユーザーが設定している【オブジェクトスナップ】モードはシステム変数 OSMODE や 3DOSMODE から得られますが、これらは整数値で表されるため osnap 関数の【オブジェクトスナップ】モードを文字列で指定する方式とは使い勝手が悪い面があるのは否めません。そこで、AutoCAD ユーザーが設定している【オブジェクトスナップ】モードでスナップさせ、スナップしたモードと点を返す関数を作成してみます。

システム変数 OSMODE の値と【オブジェクトスナップ】モードの文字列との対応を記述した連想リストを用意します。

(setq *osmodeToken*
       (list (cons 1 "_END")
             (cons 2 "_MID")
             (cons 4 "_CEN")
             (cons 8 "_NOD")
             (cons 16 "_QUA")
             (cons 32 "_INT")
             (cons 64 "_INS")
             (cons 128 "_PER")
             (cons 256 "_TAN")
             (cons 512 "_NEA")
             (cons 1024 "_GCE")
             (cons 2048 "_APP")
             (cons 4096 "_EXT")
             (cons 8192 "_PAR")
       )
)

また、システム変数 OSMODE の整数値を、モードを表す整数値に分解する bitlist 関数を用意します。

(defun bitlist (value /)
  (vl-remove-if
    (function (lambda (i) (= (logand i value) 0)))
    '(1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536)
  )
)

bitlist 関数の使い方は次の通りです。

_$ (bitlist 5) ⏎
(1 4)
_$ (bitlist 1512) ⏎
(8 32 64 128 256 1024)
_$ (bitlist 7165) ⏎
(1 4 8 16 32 64 128 256 512 2048 4096)

これらを使って、システム変数 OSMODE から osnap 関数に渡すためのスナップモードの文字列のリストを取得します。

(defun OSnapInfomation:bit->token:sub (alist / token)
  (if alist
    (if (setq token (cdr (assoc (car alist) *osmodeToken*)))
      (append (list token) (OSnapInfomation:bit->token:sub (cdr alist)))
      (OSnapInfomation:bit->token:sub (cdr alist))
    )
  )
)

(defun OSnapInfomation:bit->token (/ osmode)
  (setq osmode (getvar "OSMODE"))
  (if (/= (logand osmode 16384) 16384)
    (OSnapInfomation:bit->token:sub (bitlist osmode))
  )
)

OSnapInfomation:bit->token 関数の動作は次のようになります。結果はシステム変数 OSMODE により異なります。

_$ (OSnapInfomation:bit->token) ⏎
("_END" "_MID" "_CEN" "_NOD" "_QUA" "_INT" "_INS")

このリストをもとに、osnap 関数で pt 点のスナップ先の座標を調べます。スナップしなかった場合のモードは結果から除外します。

(defun OSnapInfomation:byMode (pt tlist / spt)
  (if tlist
    (if (setq spt (osnap pt (car tlist)))
      (cons (cons (car tlist) spt) (OSnapInfomation:byMode pt (cdr tlist)))
      (OSnapInfomation:byMode pt (cdr tlist))
    )
  )
)

この関数を使用すると、状況によって変わりますが、次のようなリストが得られます。

( ("_END" 0.0 0.0 0.0)
  ("_MID" 2.84217e-014 148.625 0.0)
  ("_CEN" 2.63009 2.91415 0.0)
  ("_QUA" 2.63009 -0.561687 0.0)
  ("_INT" 0.0 0.0 0.0)
  ("_INS" 0.0 0.0 0.0)
)

これらを統合して、n 番目に近いスナップポイントを得るOSnapInfomation 関数を作成します。pt 引数がスナップする前の座標です。order 引数が 0 の時一番近いスナップ、1 の時に 2 番目に近い点にスナップを返します。

(defun OSnapInfomation (pt order / splist dlist)
  (if (setq splist (OSnapInfomation:byMode pt (OSnapInfomation:bit->token)))
    (progn
      (setq dlist (mapcar (function (lambda (spinfo) (distance pt (cdr spinfo)))) splist))
      (nth (vl-position (nth (rem order (length dlist)) (vl-sort dlist '<)) dlist) splist)
    )
  )
)

OSnapInfomation 関数の使用例は以下の通りです。

_$ (OSnapInfomation '(0.0 0.0) 0) ⏎
("_END" 0.0 0.0 0.0)
_$ (OSnapInfomation '(0.0 0.0) 1) ⏎
("_QUA" 2.63009 -0.561687 0.0)
_$ (OSnapInfomation '(0.0 0.0) 2) ⏎
("_CEN" 2.63009 2.91415 0.0)

次ぎにスナップマーカーを描画する関数を用意しておきます。ここでは二次元のオブジェクトスナップで動作が確認されているもののみ対応することととします。range 関数と PolarPolygon 関数はマーカーの描画データを作成するサポート関数です。他のマークに対応したい場合は、描画データを追加し、スナップモードの対応テーブルを更新します。

(setq *osnapMarkerColor* 92
      ;;
      *osnapENDMark*
       (grvecs:DrawData
         (PolarPolygon '(0 0) 1.0 (/ PI 4.0) 4)
         *osnapMarkerColor*
         T
       )
      *osnapMIDMark*
       (grvecs:DrawData
         (PolarPolygon '(0 0) 1.0 (/ PI 2.0) 3)
         *osnapMarkerColor*
         T
       )
      *osnapCENMark*
       (grvecs:DrawData (PolarPolygon '(0 0) 1.0 0.0 12) *osnapMarkerColor* T)
      *osnapINTMark*
       (append (grvecs:DrawData '((-1 -1) (1 1)) *osnapMarkerColor* nil)
               (grvecs:DrawData '((-1 1) (1 -1)) *osnapMarkerColor* nil)
       )
      *osnapNODMark*
       (append *osnapCENMark* *osnapINTMark*)
      *osnapQUAMark*
       (grvecs:DrawData (PolarPolygon '(0 0) 1.0 0.0 4) *osnapMarkerColor* T)
      *osnapINSMark*
       (grvecs:DrawData
         '((-1 1)
           (0.5 1)
           (0.5 0.5)
           (1 0.5)
           (1 -1)
           (-0.5 -1)
           (-0.5 -0.5)
           (-1 -0.5)
          )
         *osnapMarkerColor*
         T
       )
      *osnapPERMark*
       (append (grvecs:DrawData '((-1 1) (-1 -1) (1 -1)) *osnapMarkerColor* nil)
               (grvecs:DrawData '((-1 0) (0 0) (0 -1)) *osnapMarkerColor* nil)
       )
      *osnapTANMark*
       (append *osnapCENMark*
               (grvecs:DrawData '((-1 1) (1 1)) *osnapMarkerColor* nil)
       )
      *osnapNEAMark*
       (grvecs:DrawData '((1 1) (-1 1) (1 -1) (-1 -1)) *osnapMarkerColor* T)
      *osanpProvisional*
       (append *osnapCENMark*
               (grvecs:DrawData
                 (PolarPolygon '(0 0) 0.5 0.0 12)
                 *osnapMarkerColor*
                 T
               )
       )
      ;;
      *osnapMarkTable*
       (list (cons "_END" '*osnapENDMark*)
             (cons "_MID" '*osnapMIDMark*)
             (cons "_CEN" '*osnapCENMark*)
             (cons "_INT" '*osnapINTMark*)
             (cons "_NOD" '*osnapNODMark*)
             (cons "_QUA" '*osnapQUAMark*)
             (cons "_INS" '*osnapINSMark*)
             (cons "_PER" '*osnapPERMark*)
             (cons "_TAN" '*osnapTANMark*)
             (cons "_NEA" '*osnapNEAMark*)
       )
)

(defun OSnapInfomation:drawMarker (snapInfo / marker)
  (setq marker (cdr (assoc (car snapInfo) *osnapMarkTable*)))
  (grvecs (if marker
            (eval marker)
            *osanpProvisional*          ; In other cases
          )
          (grvecs:TransformMatrix
            (cdr snapInfo)
            (* 1.5
               (vla-get-AutoSnapMarkerSize
                 (vla-get-Drafting (vla-get-Preferences (vlax-get-acad-object)))
               )
            )
          )
  )
)

上で使用している定義が出てこない grvecs:TransformMatrix 関数や grvecs:DrawData 関数は、grvecs 関数のサンプルコードで使用したものです。