任意の点から関数グラフに接線を引く
任意の点を通る、関数グラフの接線を、すべて取得して、リストオブジェクトとして返す方法を紹介する。
GeoGebraで描けるオブジェクトの中でも、かなり設計が難しい部類に入ると思われる。
解説
はじめに
この記事は、GeoGebra バージョン 6.0.536.0-w を前提にしている。現時点では、接線を返すコマンド「Tangent」は、関数グラフ上にない点から、関数グラフへ接線を引く機能を持たない。
もっとも、
Tangent[ <点>, <陰関数曲線> ]
は、任意の点から陰関数曲線に引いた接線を、いくつか返してくれる。
この事実を知ったのは、Hydrophobic Hyperbola様「接線の本数」というアプレットである。ここに記し、感謝申し上げる。
したがって、ある関数fに対して、陰関数曲線
y - f = 0
を作成し、Tangentコマンドを実行すれば、任意の点から関数 f に、いくつかの接線を引くことができる。
3次関数くらいなら、こちらの方法で十分対応可能である。複雑な関数(たとえば、cos(2x)sin(x) )を扱うと、接線の返し漏れが生じる場合もあるようだ。
以下では、すべての接線を漏れなく返す方法を紹介していく。
構文
まずは(可読性はともかく)接線をどんな定義で描いているのかを紹介しよう。
関数f、点Aを所与として、点Aを通る関数fの接線のリストは、GeoGebraでは以下のように表せる。
Unique[Zip[Tangent[s, f], s, Unique[Join[{{Intersect[f(x) + f'(x) (x(A) - x) - y(A), x - x, x(Corner[1]), x(Corner[2])]}, KeepIf[f(x(s)) + f'(x(s)) (x(A) - x(s)) - y(A) ≟ 0, s, {Intersect[Derivative[f(x) + f'(x) (x(A) - x) - y(A)], x - x, x(Corner[1]), x(Corner[2])]}]}]]]]
基本設計
上記の定義を、順に説明しよう。
まず、新たな関数gを、以下の定義で作成する。
g(x) = f(x) + f'(x) (x(A) - x) - y(A)
すると、gの定義上、g(x) = 0 を満たすxの値は、点Aからfのグラフに接線を引いた場合の、(各)接点のx座標と一致する。
ところで、gのグラフとx軸との交点のリストは、GeoGebraでは以下のように表せる。
{Intersect[g, x - x, x(Corner[1]), x(Corner[2])]}
Intersectコマンドの構文のうち、
Intersect[ <オブジェクト>, <オブジェクト> ]
は、1つの交点しか返さない。
したがって、例えば
{Intersect[g, y = 0]}
と書いても、gのグラフとx軸との交点を、1つしか返してくれない。せめて画面(グラフィックスビュー)上に見えている交点は、すべて返してほしいものである。つまり、せいぜい
x(Corner[1]) <= x <= x(Corner[2])
の区間くらいは、全ての交点を返してほしい。
そこで、Intersectの別構文
Intersect[ <関数>, <関数>, <x開始値>, <x終了値> ]
を使う。これを使えば、区間内の全ての交点を返してくれる。問題は、第二引数で、「x軸」を、いかにしてxの関数としてGeoGebraに認識させるかである。
{Intersect[g, y=0, x(Corner[1]), x(Corner[2])]}
では、構文エラーとなる。GeoGebraが、第二引数y=0を、xの関数とは認識してくれないからである。うまくいくのは、
{Intersect[g, x - x, x(Corner[1]), x(Corner[2])]}
である。これによって、gのグラフとx軸との交点のリストを得られる。このリストをlistGとしよう。
あとは、
Zip[Tangent[s, f], s, listG]
で、目的の接線リストが得られる。これは、
Tangent[ <点P>, <関数f> ]
で、f上の点( x(P), f( x(P) ) )におけるfの接線を得られることを利用している。Zipコマンドについての解説は省く(公式マニュアル参照)。
細かい仕様への対応
以上が基本的なアイデアだが、話はこれだけでは済まない。GeoGebraの細かい仕様に対応しなければならない。
上記でlistGとして紹介した
{Intersect[g, x - x, x(Corner[1]), x(Corner[2])]}
は、関数gとx軸が(交わらず)接するだけのとき、その接点を返してくれない。しかし、これもg(x) = 0を満たす以上、無視できない。そこで、いったん、gの導関数g'と、x軸との交点リストlistG'を作る。その定義は以下のとおりである。
{Intersect[g', x - x, x(Corner[1]), x(Corner[2])]}
さらに、
KeepIf[g(x(s)) ≟ 0, s, listG']
によって、listG'の要素のうち、gとx軸との接点のみを抽出する。これで、Intersectコマンドが返し漏らした、gとx軸との接点のリストを得ることができた(このリストを、listGTangentとしよう)。
目的の接線リストを得るための数式として上述した、
Zip[Tangent[s, f], s, listG]
のうち、listGの部分を、Join[{listG, listGTangent}]に置き換える。これで、返し漏らしを回収できる。
Zip[Tangent[s, f], s, Join[{listG, listGTangent}]]
以上の処理をすべてネストしたものが、「構文」の項で紹介した定義である。なお、当該定義においては、重複を削除するUniqueコマンドを入れている。
※これでもまだ、Intersectのデリケートな仕様に完璧に対応できているわけではない。したがって、予期せず描画の厳密性を欠く場合があるかもしれない。あくまで参考程度の描画方法と考えて頂きたい。
オリジナルツール「PerfectTangent」
上記知見を用いて、オリジナルツールを作成した。
PerfectTangent[ <点>, <関数> ]
で、点から関数グラフに引いた接線のリストを返す。