1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

直線に垂直な円の接線の方程式を求める

Last updated at Posted at 2020-04-17

直線に垂直な円の接線の方程式を求める

直線 $ax+by+c=0$ に垂直な、中心が $(x_0,y_0)$ 半径が $r$ の円 $(x-x_0)^2+(y-y_0)^2=r^2$ の2つの接線の方程式を求める。

求める接線は、直線 $ax+by+c=0$ に垂直なのでその方向ベクトルは、直線の法線ベクトルになる。
直線 $ax+by+c=0$ の法線ベクトルは、
$$\vec{n}=(a,b)$$
よって接線の傾き $m$ は、
$$m=\frac{b}{a}$$
となる。

接点 $A$ は、円の中心 $(x_0,y_0)$ から直線の方向ベクトル $\vec{d}$ 方向に 距離 $r$ の点と考えられる。
点 $C(x_0,y_0)$ に、直線の方向ベクトル $\vec{d}$ の単位ベクトルを $r$ 倍したベクトルをたすことで求めることができる。
接点 $B$ は、点 $C(x_0,y_0)$ に、直線の方向ベクトル $\vec{d}$ の単位ベクトルに $-r$ 倍したベクトルをたすことで求めることができる。

直線 $ax+by+c=0$ の方向ベクトルは、
$$\vec{d}=(-b,a)$$
$\vec{d}$ の単位ベクトルを $\vec{k}$ とすると、
$$\vec{k}=(-b,a)\cdot\frac{1}{\sqrt{a^2+b^2}}=\left(-\frac{b}{\sqrt{a^2+b^2}},\frac{a}{\sqrt{a^2+b^2}}\right)$$
となり接点 $A,B$ の座標は、
$$A=(x_0,y_0)+\left(-\frac{b}{\sqrt{a^2+b^2}}\cdot r,\frac{a}{\sqrt{a^2+b^2}}\cdot r\right)=\left(-\frac{br}{\sqrt{a^2+b^2}}+x_0,\frac{ar}{\sqrt{a^2+b^2}}+y_0\right)$$
$$B=(x_0,y_0)+\left(-\frac{b}{\sqrt{a^2+b^2}}\cdot -r,\frac{a}{\sqrt{a^2+b^2}}\cdot -r\right)=\left(\frac{br}{\sqrt{a^2+b^2}}+x_0,-\frac{ar}{\sqrt{a^2+b^2}}+y_0\right)$$
となる。
接点 $A$ 側の接線は、点 $A$ を通る傾きが $\dfrac{b}{a}$ の直線と考えられるので、直線の方程式の1点と傾きが与えられた直線の公式より、
$$y-\left(\frac{ar}{\sqrt{a^2+b^2}}+y_0\right)=\frac{b}{a}\Biggl\{x-\left(-\frac{br}{\sqrt{a^2+b^2}}+x_0\right)\Biggr\}$$
この式の両辺に $a$ を掛けて、
$$a\left(y-\frac{ar}{\sqrt{a^2+b^2}}-y_0\right)=b\left(x+\frac{br}{\sqrt{a^2+b^2}}-x_0\right)$$
両辺を展開して、
$$ay-\frac{a^2r}{\sqrt{a^2+b^2}}-ay_0=bx+\frac{b^2r}{\sqrt{a^2+b^2}}-bx_0$$
右辺を左辺に移項すると、
$$-bx+ay+bx_0-ay_0-\left(\frac{a^2r}{\sqrt{a^2+b^2}}+\frac{b^2r}{\sqrt{a^2+b^2}}\right)=0$$
ここで、
$$\left(\frac{a^2r}{\sqrt{a^2+b^2}}+\frac{b^2r}{\sqrt{a^2+b^2}}\right)=\frac{a^2r+b^2r}{\sqrt{a^2+b^2}}=\frac{(a^2+b^2)r}{\sqrt{a^2+b^2}}=\frac{(a^2+b^2)\sqrt{a^2+b^2}}{a^2+b^2}r=r\sqrt{a^2+b^2}$$
よって、
$$-bx+ay+bx_0-ay_0-r\sqrt{a^2+b^2}=0$$
両辺に $-1$ を掛けて、
$$bx-ay-(bx_0-ay_0-r\sqrt{a^2+b^2})=0$$
となる。これが接点 $A$ 側の接線の方程式です。
同様に接点 $B$ 側の接線の方程式を計算すると、
$$bx-ay-(bx_0-ay_0+r\sqrt{a^2+b^2})=0$$
となる。

直線方程式 $ax+by+c=0$ が正規化されている場合、(直線の方程式を正規化する 参照)
接線の方程式は、
$$bx-ay-(bx_0-ay_0-r)=0$$
$$bx-ay-(bx_0-ay_0+r)=0$$
となる。

【例】中心(3,2) 半径 5 の円に対して、直線 3x+4y-50=0 に垂直な接線の方程式を求める。

上記公式 $bx-ay-(bx_0-ay_0-r\sqrt{a^2+b^2})=0$ より、
$4x-3y-(4\cdot3-3\cdot2-5\sqrt{3^2+4^2})=0$ よって接線の方程式は、
$$4x-3y+19=0$$
公式 $bx-ay-(bx_0-ay_0+r\sqrt{a^2+b^2})=0$ より、
$4x-3y-(4\cdot3-3\cdot2+5\sqrt{3^2+4^2})=0$ よって、
$$4x-3y-31=0$$
となる。

サンプルプログラム

円図形を選択して、その次に直線(LINE,XLINE,RAY)を選択。選択した直線に垂直な円の接線を作成する。

;; 直線に垂直な円の接線を作成
(defun c:CreateTangentOfPerpendicularLine (/ circle line tangents)
    ;; 円を選択
    (while (null circle)
        (setvar 'ERRNO 0)
        (setq circle (car (entsel "円を選択: ")))
        (cond
            ;; 空振り
            ((= 7 (getvar 'ERRNO))
             (princ "\n**空振り!!再選択**\n")
             (setq circle nil)
            )
            ;; 空Enter
            ((= 52 (getvar 'ERRNO))
             (princ "\n**空Enter!!再選択**\n")
             (setq circle nil)
            )
            ;; 図形が選択された
            (circle
             (if (/= "CIRCLE" (entity:GetType circle))
                 (progn
                     (princ "\n**円ではありません!!再選択**\n")
                     (setq circle nil)
                 )
                 (princ "\n**円が選択されました。**\n")
             )
            )
        )
    )
    ;; 直線を選択
    (while (null line)
        (setvar 'ERRNO 0)
        (setq line (car (entsel "直線を選択: ")))
        (cond
            ;; 空振り
            ((= 7 (getvar 'ERRNO))
             (princ "\n**空振り!!再選択**\n")
             (setq line nil)
            )
            ;; 空Enter
            ((= 52 (getvar 'ERRNO))
             (princ "\n**空Enter!!再選択**\n")
             (setq line nil)
            )
            ;; 図形が選択された
            (line
             (setq e (entity:GetType line))
             (if (and (/= "LINE" e) (/= "RAY" e) (/= "XLINE" e))
                 (progn
                     (princ "\n**直線ではありません!!再選択**\n")
                     (setq line nil)
                 )
                 (princ "\n**直線が選択されました。**\n")
             )
            )
         )
    )
    ;; 接線の方程式を取得
    (setq tangents (circle:GetEquationOfTangentPerpendicularToLine circle line))
    ;; 構築線を作成
    (mapcar
        (function
            (lambda (f)
                (entmake:XlineFromEquation (car f) (cadr f) (caddr f))
            )
        )
        tangents
    )
)

;; == sub functions ==
;; 図形のDXF定義データの値を取得
(defun entity:GetDxf (g e)
    (cond
        ((= (type e) 'ENAME) (cdr (assoc g (entget e))))
        ((listp e) (cdr (assoc g e))) 
    )
)
;; 図形のタイプを取得
(defun entity:GetType (e) (entity:GetDxf 0 e))
;; 2点から直線の方程式を求める ax + by + c = 0
;; 正規化された (a b c) のリストを返す
(defun geometric:GetLineEquation (p1 p2 / x1 y1 x2 y2 l)
    (setq x1 (car p1) y1 (cadr p1)
          x2 (car p2) y2 (cadr p2)
          len (distance p1 p2) ;; p1-p2の距離
    )
    (if (> len 1.0e-08)
        (mapcar
            (function
                (lambda (x) (/ x len))
	    )
	    (list (- y2 y1) (- x1 x2) (- (* x2 y1) (* x1 y2)))
        )
    )
)
;; 図形が線分かどうか調べる
(defun entity:IsLine (e) (= "LINE" (entity:GetType e)))
;; 図形が構築線かどうか調べる
(defun entity:IsXline (e) (= "XLINE" (entity:GetType e)))
;; 図形が放射線かどうか調べる
(defun entity:IsRay (e) (= "RAY" (entity:GetType e)))
;; 円の中心を取得
(defun circle:GetCenter (e) (entity:GetDxf 10 e))
;; 円の半径を取得
(defun circle:GetRadius (e) (entity:GetDxf 40 e))
;; 線分の始点を取得
(defun line:GetStartPoint (e) (entity:GetDxf 10 e))
;; 線分の終点を取得
(defun line:GetEndPoint (e) (entity:GetDxf 11 e))
;; 線分の始点-終点のリストを取得
(defun line:GetStartAndEndPoints (e)
    (list (line:GetStartPoint e) (line:GetEndPoint e))
)
;; 構築線の基点を取得
(defun xline:GetFirstPoint (e) (entity:GetDxf 10 e))
;; 構築線の単位方向ベクトルを取得
(defun xline:GetUnitVector (e) (entity:GetDxf 11 e))
;; 構築線の基点から単位方向ベクトルの点を計算
(defun xline:GetSecondPoint (e)
    (mapcar '+ (xline:GetFirstPoint e) (xline:GetUnitVector e))
)
;; 構築線上の2点をを取得
(defun xline:GetFirstAndSecondPoints (e)
    (list (xline:GetFirstPoint e) (xline:GetSecondPoint e))
)
;; 放射線の始点を取得
(defun ray:GetFirstPoint (e) (entity:GetDxf 10 e))
;; 放射線の単位方向ベクトルを取得
(defun ray:GetUnitVector (e) (entity:GetDxf 11 e))
;; 放射線の基点から単位方向ベクトルの点を計算
(defun ray:GetSecondPoint (e)
    (mapcar '+ (ray:GetFirstPoint e) (ray:GetUnitVector e))
)
;; 放射線上の2点をを取得
(defun ray:GetFirstAndSecondPoints (e)
    (list (ray:GetFirstPoint e) (ray:GetSecondPoint e))
)
;; 線状図形上の2点を取得
(defun entity:Get2PointsOfLinear (e)
    (cond
        ((entity:IsLine e) (line:GetStartAndEndPoints e))
        ((entity:IsXline e) (xline:GetFirstAndSecondPoints e))
        ((entity:IsRay e) (ray:GetFirstAndSecondPoints e))
    )
)
;; 線状図形上の2点から直線の方程式を求める
(defun geometric:GetLineEquationFromLinear (linear / points)
    (setq points (entity:Get2PointsOfLinear linear))
    (geometric:GetLineEquation (car points) (cadr points))
)
;; 直線に垂直な接線の方程式
(defun circle:GetEquationOfTangentPerpendicularToLine (circle line / a b c d r o)
    (setq f (geometric:GetLineEquationFromLinear line))
    (setq r (circle:GetRadius circle)
          o (circle:GetCenterPoint circle)
          a (car f)
          b (cadr f)
          ;;c (caddr f)
    )
    (list
        (list b (- a) (+ (- (* b (car o))) (* a (cadr o)) r))
        (list b (- a) (- (+ (- (* b (car o))) (* a (cadr o))) r))
    )
)
;; 構築線を定義
(defun entmake:XlineBase (p u)
    (list '(000 . "XLINE")
	  '(100 . "AcDbEntity")
	  '(100 . "AcDbXline")
	  (cons 010 p)
	  (cons 011 u)
    )
)
;; 基点と単位方向ベクトルから構築線を作成
(defun entmake:Xline (p u) (entmake (entmake:XlineBase p u)) (entlast))
;; 直線の方程式から構築線を作成
(defun entmake:XlineFromEquation (a b c)
    (entmake:Xline (list (- (/ c a)) 0. 0.) (list (- b) a 0.))
)
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?