今日は今までと趣向を変えて、AutoCAD というか、AutoLISP のネタです。
AutoLISP でオブジェクトの交点を求める方法
昔ながらのやり方 (2次元限定)
直線の交点は、(inters ~)
で求められます。
円弧は円の一部、ふくらみを持ったポリラインも直線と円弧の組み合わせと考えれば、円と直線、円と円の交点が求められれば、スプライン以外の交点が求められそうです。
円と円の交点を求めるルーチンは作ったことはないですが、円と直線の交点を求めるルーチンは作成したことがあります。
;;;***************************************************
;;; 円と直線の交点を求める
;;; 直線の方程式:ax+by+c = 0
;;; 円の方程式:(x-xp)^2 * (y-yp)^2 = r^2
;;;***************************************************
(defun line_circle_cross_point_sub (
a b c xp yp r
/
d e f
)
(setq
d (+ (* a xp) (* b yp) c)
e (+ (expt a 2.0) (expt b 2.0))
f (sqrt (- (* e (expt r 2.0)) (expt d 2.0)))
);setq
(if (equal (* e (expt r 2.0)) (expt d 2.0) (margin_distance))
(list
(list
(+ xp (/ (* -1.0 a d) e));x
(+ yp (/ (* -1.0 b d) e));y
);list
);list
(list
(list
(+ xp (/ (+ (* -1.0 a d) (* b f)) e));x1
(+ yp (/ (- (* -1.0 b d) (* a f)) e));y1
);list
(list
(+ xp (/ (- (* -1.0 a d) (* b f)) e));x2
(+ yp (/ (+ (* -1.0 b d) (* a f)) e));y2
);list
);list
);if
);defun
;;;***************************************************
;;; 直線の構成点(x1,y1)と(x2,y2)から、直線の方程式
;;; 「ax+by+c = 0」の a,b,c を求める
;;;***************************************************
(defun xy1_xy2_to_abc (
xy1 xy2
/
x1 x2 y1 y2
)
(setq
x1 (car xy1)
y1 (cadr xy1)
x2 (car xy2)
y2 (cadr xy2)
);setq
(list
(- y2 y1)
(- x1 x2)
(- (* y2 (- x2 x1)) (* x2 (- y2 y1)))
);list
);defun
(defun margin_distance() (eval 0.0000000001))
VLAオブジェクトを使用したやり方
VLA オブジェクトって、なんだかよく分からなかったので、今まであまり使っていなかったんですが、別件でExcelのデータを AutoLISP で扱う事があり、その際に
「なにやらvlax-invoke-method
を使って、色々出来そうらしい」
という事を体験して、ちょっと習得してみようと思った次第。
;;;***************************************************
;;; オブジェクトの交点を求める
;;; 引数 obj_1 と obj_2 はそれぞれ交点を求めるオブジェクトの図形名
;;;***************************************************
(defun get_inters_point (
obj_1 obj_2
/
vobj_1 vobj_2
intPoints
tempPoint
r_list
)
(setq r_list nil)
(if
(and obj_1 obj_2
(setq vobj_1 (vlax-ename->vla-object obj_1)) ;オブジェクト名を基にしてVLAオブジェクトを取得
(setq vobj_2 (vlax-ename->vla-object obj_2)) ;オブジェクト名を基にしてVLAオブジェクトを取得
(setq intPoints (vla-IntersectWith vobj_1 vobj_2 acExtendNone)) ;交点を取得(オブジェクトの延長はしない)
);and
(if (/= (type intPoints) vlax-vbEmpty) ;交点は有効?
(progn
(setq tempPoint (vlax-safearray->list (vlax-variant-value intPoints))) ;交点リストを取得
(while tempPoint
(setq
r_list (append r_list (list (list (car tempPoint) (cadr tempPoint) (caddr tempPoint))))
tempPoint (cdddr tempPoint)
);setq
);while
);progn
);if
);if
(progn r_list)
);defun
ObjectARX や VBA の intersectWith メソッドと同じです(というかそれを呼び出していると思われます)。
acExtendNone
の部分は、オブジェクトが実際に交差している交点のみ求める指定です。
ここを変更すると、下記の様になります。
-
acExtendThisEntity
:1つ目の引数(obj_1)のオブジェクトは延長、二つ目の引数(obj_2)のオブジェクトは延長しない場合の交点を求める -
acExtendOtherEntity
:1つ目の引数(obj_1)のオブジェクトは延長せず、二つ目の引数(obj_2)のオブジェクトは延長する場合の交点を求める -
acExtendBoth
:1つ目の引数(obj_1)のオブジェクトと二つ目の引数(obj_2)のオブジェクトの双方を延長する場合の交点を求める
という風になります。
今は改善されてる(と思いたい)のですが、古いバージョンの AutoCAD では、intersectWith に精度上の問題がある事が指摘されており、使用に対しては十分検証する事をお勧めいたします。
やっぱりLISPだね
AutoCADでちょっとしたカスタマイズや自動作図は、AutoLISPがやっぱり便利ですね。