ふくらみを持ったポリラインとは?
AutoCAD では、ポリラインに円弧の曲線を含ませることができます。
「ポリラインって通常は連続直線の事でしょ?」
と思われるかもしれませんが、そういう事が出来る仕組みなのです。
ふくらみを持ったポリラインの実物
ふくらみを持ったポリラインで作図された図形の例は、下図の通り。
このふくらみを持ったポリラインのエンティティ情報は、下記の通りです。
(0 . "LWPOLYLINE")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbPolyline")
(90 . 4)
(70 . 0)
(43 . 0.0)
(38 . 0.0)
(39 . 0.0)
(10 8.45388 11.8955); 1点目座標
(40 . 0.0)
(41 . 0.0); ↑
(42 . 0.0); ← ふくらみ(bulge)がゼロなので、この間は直線
(91 . 0); ↓
(10 15.2163 13.7794); 2点目座標
(40 . 0.0)
(41 . 0.0); ↑
(42 . -0.279508); ← ふくらみ(bulge)がゼロではないので、この間は円弧
(91 . 0); ↓
(10 21.081 12.1347); 3点目座標
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(91 . 0)
(10 26.1977 5.88499); 4点目座標
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(91 . 0)
(210 0.0 0.0 1.0)
エンティティ名やハンドル等の、オブジェクト固有のエンティティは、削除しています。
ふくらみを持ったポリラインの円弧部分の情報は
- 始点座標
- 終点座標
- ふくらみ
の3つです。
この始終点とふくらみの情報を元に、円弧のエンティティを生成したいのです。
円弧のエンティティ情報
対する円弧オブジェクトの情報について。
実際にarc
コマンドで円弧を作図する際は
- 始点、中間点、終点の3点を指定する方法
- 中心点、始点、終点の3点を指定する方法(終点の代りに角度や弦長で指定も可能)
等がありますが、作図方法に関わらず実際の図形のエンティティ情報は、下記の様になっています。
(0 . "ARC")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbCircle")
(10 36.4711 12.3291 0.0); 中心点
(40 . 3.64553); 半径
(210 0.0 0.0 1.0)
(100 . "AcDbArc")
(50 . 2.72348); 中心点から見た円弧始点の角度(ラジアン)
(51 . 6.22984); 中心点から見た円弧終点の角度(ラジアン)
始点から終点に向けて、反時計回りで作図されます。
円弧を作図するうえで必要なデータは
- 中心点
- 半径
- 始点角度
- 終点角度
の4つです。
ふくらみとは?
ふくらみとは何ぞや? という問いに答えられるほど、私の知識は豊富ではありません。
算数を少しかじった程度です。
ですので、下記の情報が非常に参考になりました。
ふくらみとは何ぞや?はこのサイトで理解して頂ければと思います(無責任ですみません)。
少なくとも私が理解できたのは
ふくらみがマイナスの場合は時計回りの円弧になるから、始終点を入れ替えないと正しい円弧情報にならない
ということぐらいです。
実際に円弧情報を取得してみよう
最初に考えた、頭悪いやり方
という訳で、いきなり LISP のコードです。
引数として
- 始点座標
- 終点座標
- ふくらみ
を渡すことで
- 中心座標
- 半径
- 始点角度
- 終点角度
をリストで返します。
;始終点とふくらみから円弧情報(中心座標、半径、開始角度、終了角度)を取得
(defun bulge_to_arc (
s_point ;始点座標
e_point ;終点座標
bulge ;ふくらみ
/
s_temp
e_temp
ang_temp
dist_temp
r_dist
d_point
c_point
)
(if (minusp bulge)
(setq s_temp e_point e_temp s_point)
(setq s_temp s_point e_temp e_point)
);if
(setq
ang_temp (atan (abs bulge))
dist_temp (/ (distance s_temp e_temp) 2.0)
r_dist (/ (* dist_temp (+ 1.0 (expt bulge 2.0))) (* 2.0 (abs bulge)))
);setq
;円弧の中心座標取得
(setq
d_point (inters s_temp (polar s_temp (- (angle s_temp e_temp) ang_temp) 1.0) e_temp (polar e_temp (+ (angle e_temp s_temp) ang_temp) 1.0) nil)
c_point (polar d_point (+ (angle s_temp e_temp) (/ PI 2.0)) r_dist)
);setq
(list c_point r_dist (angle c_point s_temp) (angle c_point e_temp))
);defun
なんかもっとスマートに算出できる方法がありそうですが、私の頭ではこれが限界でした・・・
半径「r」の算出は、先の参考サイトの式をそのまま流用しています。
面倒だったのは中心座標を求める所。参考サイトの「D点」を求めてから、始終点角度に垂直な「r」の距離の点を求める方法で算出しています。
ここはもっと上手いやり方が有りそうです。
始終点角度は中心座標が分かれば簡単です。
もっと良いやり方
先に紹介したサイトにもっとスマートに算出するヒントがあったのに、私が理解していませんでした。
反省も込めて、解説。
図1
先ず、大前提として「ふくらみ(bulge 以下 b)」の定義ですが
b = tan ( θ / 4 ) ・・・①
となります。
半径 r は先の参考サイトにある通りなので省略します。
先の頭の悪いやり方は AD 方向の長さが適当な線分と、BD 方向の長さが適当な線分の交点座標をinters
で求め、そこからpolar
で中心座標を求めるやり方でしたが、交点を求めるというのが如何にも頭が悪いやり方だと思ったのです。
しかし、DE の距離が分かれば、EC の距離もわかるので、その方法で中心座標を求めた方がスマートです。
で、DE 間の距離は既に参考サイトに s として記載されているんですが
tan ( θ / 4 ) = DE / AE ・・・②
①と②から
b = DE / AE
DE = b * AE
AE の長さは、AB の長さの半分、E の座標は A と B の中点
どちらも A と B の座標が分かっていれば簡単に求められます。
距離は三平方の定理を使わずとも、AutoLISP ならdistance
で簡単に求められます。
EC 間の距離は
EC = r - DE
ですから、ここまでわかればpolar
で中心座標が求められます。
という訳で、改修したコードです。
;始終点とふくらみから円弧情報(中心座標、半径、開始角度、終了角度)を取得
(defun bulge_to_arc (
s_point ;始点座標
e_point ;終点座標
bulge ;ふくらみ
/
s_temp
e_temp
ang_temp
dist_temp
r_dist
d_point
d_dist
c_point
)
(if (minusp bulge) ;ふくらみがマイナスの場合、時計回りなので始点と終点を入れ替える
(setq s_temp e_point e_temp s_point)
(setq s_temp s_point e_temp e_point)
);if
(setq
ang_temp (atan (abs bulge)) ; θ/4 を求める
dist_temp (/ (distance s_temp e_temp) 2.0) ; AE 間の距離を求める
r_dist (/ (* dist_temp (+ 1.0 (expt bulge 2.0))) (* 2.0 (abs bulge))) ; 半径を求める
);setq
;円弧の中心座標取得
(setq
d_dist (* (abs bulge) dist_temp) ; DE 間の距離を求める
; E の座標を求める
d_point (list (/ (+ (car s_temp) (car e_temp)) 2.0) (/ (+ (cadr s_temp) (cadr e_temp)) 2.0))
c_point (polar d_point (+ (angle s_temp e_temp) (/ PI 2.0)) (- r_dist d_dist)) ;中心点座標を求める
);setq
(list c_point r_dist (angle c_point s_temp) (angle c_point e_temp))
);defun
もやもやしてた部分が、ようやくスッキリしました。
終わりに
今までふくらみってよく分からないな、と思っていたのですが、今回なんとなく理解できてよかったです。
まだ完全に理解しきれていないので、もっと精進しないといけないと思いました。