座標系と図面データベース

押し出し方向と高度を使った図形配置

【押し出し方向】と「高度」を使った図形配置は、ライトウェイトポリラインや 2D ポリラインといった、三次元空間内の任意の平面上であるが、一つの平面上に載った図形で使われます。具体的には DXF グループコード 30 または 38 等や VLA オブジェクトのプロパティ Elevation をもつものです。

図面データベース内で、ライトウェイトポリラインは DXF グループコードと VLA オブジェクトのプロパティでは次のように表されます。

DXF グループコード プロパティ 意味
90   頂点の数
10(複数個) Cordinates 頂点の座標 (OCS)
38 Elevation 高度
210 Normal 【押し出し方向】ベクトル
autolisp elevation group

WCS 上で (0.0 0.0) と (100.0 50.0) を対角頂点とする長方形のライトウェイトポリラインを、Z 軸方向に 25.0 移動し、Y 軸を中心に45度回転させた図形を作成してみます。この課題を言い換えますと Z 軸方向に 25.0 移動し、Y 軸を中心に 45 度回転させたある任意の座標系を基準に(0.0 0.0) と (100.0 50.0) を対角頂点とする長方形を描くことになります。同じ計算であっても、視点の取り方で思考の表現が変わることを認識してください。

この時、軸の回転から【押し出し方向】ベクトルは頭でイメージすると分かるとおり (1.0 0.0 1.0) となります。しかし話は難しくなります。次のようにすると期待したものと異なったものとなるでしょう。そして仮に X 軸を中心に 45 度回転させたものとして【押し出し方向】ベクトルが (0.0 -1.0 1.0) とした場合は期待したような図形になります。理解していないと、うまくいったり、いかなかったり、どこが悪いのかわからなくて頭を抱えることになります。

(entmake '((0 . "LWPOLYLINE")
           (100 . "AcDbEntity")
           (100 . "AcDbPolyline")
           (90 . 4) ; 頂点数
           (10 0.0 0.0)
           (10 100.0 0.0)
           (10 100.0 50.0)
           (10 0.0 50.0)
           (70 . 1) ; 閉じている
           (38 . 25.0)
           (210 1.0 0.0 1.0)
          )
)

これは、【任意の軸のアルゴリズム】によって決まる OCS の X 軸 Y 軸の向きが、【押し出し方向】によってダイナミックに変化してしまうことに起因します。そのため OCS で指定する頂点の座標は【押し出し方向】によって変化させなければなりません。

いくつか方法があるかと思いますが、イメージしやすい方法として、頂点の座標を自前で WCS 内で目的の位置へ座標変換します。それを【押し出し方向】ベクトルによって決まる OCS 上の座標に変換して図面データベースに書き込みます。

Z 軸方向に 25.0 移動し、Y 軸を中心に45度回転させる変換マトリックスは次のとおりです。

(setq amatrix (matrix:Product
                (rotate-matrix:Y-axis (/ PI 4))
                (translation-Matrix '(0.0 0.0 25.0))
              )
)

この変換マトリックスで表される Z 軸の向きが【押し出し方向】ベクトルになります。表示させてみると単位ベクトルに丸められていますが、イメージしているものと同じ方向を向いています。

_$ (transformation-matrix:element amatrix 'Z) ⏎
(0.707107 0.0 0.707107)

この【押し出し方向】ベクトルを使って WCS 上の座標を OCS 上の座標に変換します。

ここまでの一連の計算まとめると次のように書けます。

(setq amatrix (matrix:Product
                (rotate-matrix:Y-axis (/ PI 4))
                (translation-Matrix '(0.0 0.0 25.0))
              )
      normal  (transformation-matrix:element amatrix 'Z)
      plist   (mapcar
                (function (lambda (point)
                            (trans (transform amatrix point) acWorld normal)
                          )
                )
                '((0.0 0.0 0.0) (100.0 0.0 0.0) (100.0 50.0 0.0) (0.0 50.0 0.0))
              )
)

最後の plist に図形にセットすべき OCS の座標が代入されます。表示させると以下のようなものです。このように OCS が介入すると図面データベースに設定する値は予測しにくいものになります。

_$ plist⏎
((0.0 0.0 25.0) (0.0 -100.0 25.0) (50.0 -100.0 25.0) (50.0 0.0 25.0))

上の Z 座標の値 25.0 は「高度」に設定しますので、XY 座標だけの値にして頂点の座標として図形を作成します。まとめますと、今回のライトウェイトポリラインの作成は DXF グループコードと entmake 関数を使う場合は次のように書けます。

(setq amatrix   (matrix:Product
                  (rotate-matrix:Y-axis (/ PI 4))
                  (translation-Matrix '(0.0 0.0 25.0))
                )
      normal    (transformation-matrix:element amatrix 'Z)
      plist     (mapcar
                  (function (lambda (point)
                              (trans (transform amatrix point nil) acWorld normal)
                            )
                  )
                  '((0.0 0.0 0.0) (100.0 0.0 0.0) (100.0 50.0 0.0) (0.0 50.0 0.0))
                )
      elevation (3DVector:ref (car plist) 'Z)
)
(entmake
  (append
    '((0 . "LWPOLYLINE")
      (100 . "AcDbEntity")
      (100 . "AcDbPolyline")
      (90 . 4)                          ; 頂点数
     )
    (mapcar (function (lambda (point) (cons 10 (3DVector:~ref point 'Z))))
            plist
    )
    (list '(70 . 1)                     ; 閉じている
          (cons 38 elevation)           ; 高度
          (cons 210 normal)             ; 押し出し方向
    )
  )
)

ActiveX 対応関数を使った場合も座標についての考えは同じです。

(setq amatrix   (matrix:Product
                  (rotate-matrix:Y-axis (/ PI 4))
                  (translation-Matrix '(0.0 0.0 25.0))
                )
      normal    (transformation-matrix:element amatrix 'Z)
      plist     (mapcar
                  (function (lambda (point)
                              (trans (transform amatrix point nil) acWorld normal)
                            )
                  )
                  '((0.0 0.0 0.0) (100.0 0.0 0.0) (100.0 50.0 0.0) (0.0 50.0 0.0))
                )
      elevation (3DVector:ref (car plist) 'Z)
)
(setq lwpline-obj
       (vla-AddLightWeightPolyline
         *ModelSpace*
         (pointList->xyPointArray plist)
       )
)
(vla-put-Normal lwpline-obj (vlax-3D-point normal))
(vla-put-Elevation lwpline-obj elevation)
(vla-put-Closed lwpline-obj :vlax-true)

上の中で pointList->xyPointArray 関数は三次元の頂点のリストを XY の二次元に変換した後、浮動小数点のセーフ配列のバリアント型に変換する関数です。詳しくは、別稿の「AutoLISP の ActiveX」を参照してください。