うしブログ

うしブログ

趣味で運営する、GeoGebraの専門ブログ。

(作業メモ)StartPoint要検証(2行の場合;テキスト変更時未定義問題)

楕円反射_うしver

このアプレットは、miyamath84様「楕円反射」に触発されて作りました。

 

楕円反射_うしver – GeoGebra

楕円形のビリヤードです。焦点から白い球を打つと、必ずもう一つの焦点を通過し、もとの焦点に帰ってくる様子が観察でき、楕円の性質を視覚的に確認することができます。

主な設計

前提オブジェクト

自由な点オブジェクト:F1, F2(楕円の焦点として使用)、P(楕円の周上の1点として使用)

楕円:ellipseAsPolyLine = PolyLine[Sequence[Point[Ellipse[F1, F2, P], α], α, 0, 1, 0.001]] ・・・後ほどIntersectコマンドを使う際に、交点の返し漏れを防ぐために、PolyLineによって作成する。

点Direction:Point[Circle[F1, 1]] ・・・球を打つ方向を決定するためのもの

数値n(1〜36):球の数

数値t:球が進んだ長さ(なお、摩擦による減速を再現するため、tのアニメーション速度は一定ではない)

数値constLength = 2 (Distance[F1, P] + Distance[P, F2]) ・・・F1〜P〜F2の長さの2倍(これがPの位置によらず一定であるのが、楕円の性質である)

f:id:usiblog:20190814050616p:plain

球(のリスト)のつくりかた

n個の球を、リストとしてまとめて作ってしまう(以下の図は、n=6の場合である)。そのために、SequenceやZipといったコマンドを活用していく。

toFirstRay = Sequence[Rotate[Direction, α, F1], α, 2π / n, 2π, 2π / n] ・・・F1を始点とする半直線を確定するための点。

f:id:usiblog:20190814050813p:plain

firstRayList = Zip[Ray[F1, β], β, toFirstRay] ・・・この半直線が楕円の周に届くまでが、球の最初の軌道となる。

f:id:usiblog:20190814051004p:plain

firstRef = Zip[Intersect[γ, ellipseAsPolyLine], γ, firstRayList] ・・・球が最初に楕円の周にぶつかる点。

f:id:usiblog:20190814051241p:plain

toSecondRay = Zip[Dilate[δ, (SemiMajorAxisLength[Ellipse[F1, F2, P]] - Distance[F1, F2] / 2) / 2 / Distance[δ, F2], F2], δ, firstRef] ・・・firstRefからF2を通り、ふたたび楕円の周にぶつかるまでの軌道を、半直線で表すための、当該半直線の始点。始点が楕円の外に作られないようにするために(もし外に作ってしまうと、半直線と楕円の交点が2つになってしまい、都合が悪い)、始点は、かならずF2から、「F2〜楕円の最短距離÷2」の位置に作られるよう、Dilateの比率を調整してある。

f:id:usiblog:20190814051452p:plain

secondRayList = Zip[Ray[ε, F2], ε, toSecondRay] ・・・firstRefからF2を通り、ふたたび楕円の周にぶつかるまでの軌道を、半直線で表したもの。

f:id:usiblog:20190814051701p:plain

secondRef = Zip[Intersect[ζ, ellipseAsPolyLine], ζ, secondRayList] ・・・球が2回目に楕円の周にぶつかる点。

f:id:usiblog:20190814051843p:plain

球は、F1→firstRef(の各要素)→F2→secondRef(の各要素)→F1という軌道をたどる。

f:id:usiblog:20190814052345p:plain

finalPointList = Zip[If[t < Distance[F1, α], Dilate[α, t / Distance[F1, α], F1], Distance[F1, α] ≤ t < Distance[F1, α] + Distance[α, β], Dilate[β, (t - Distance[F1, α]) / Distance[α, β], α], Dilate[F1, (t - Distance[F1, α] - Distance[α, β]) / Distance[β, F1], β]], α, firstRef, β, secondRef] ・・・これが球を表す。tに対応するように、球の位置を設定している。

 

1つ目の条件(t < Distance[F1, α]、ただしαはfirstRefの各要素)は、球がF1〜firstRef(の各要素)の間にある場合である。このとき、球の位置は、Dilate[α, t / Distance[F1, α], F1] 、すなわち、F1から、firstRefの各要素に向かって、長さtだけ進んだ場所とする。

 

2つ目の条件(Distance[F1, α] ≤ t < Distance[F1, α] + Distance[α, β]、αはfirstRefの各要素、βはsecondRefの各要素)は、球がfirstRef(の各要素)〜secondRef(の各要素)の間にある場合である。このとき、球の位置は、Dilate[β, (t - Distance[F1, α]) / Distance[α, β], α]、すなわち、firstRefの各要素から、secondRefの対応する要素に向かって、長さt - Distance[F1, α]だけ進んだ場所とする。

 

3つ目の条件(1つ目の条件も2つ目の条件も満たさない場合)は、球がsecondRef(の各要素)〜F1の間にある場合である。このとき、球の位置は、Dilate[F1, (t - Distance[F1, α] - Distance[α, β]) / Distance[β, F1], β]、すなわち、secondRedの各要素から、F1に向かって、長さt - Distance[F1, α] - Distance[α, β]だけ進んだ場所とする。

 

PointLineへの憧れ

はじめに

本記事の内容は、動的幾何学ソフト「PointLine」に触発されて得られた知見に基づいています。下記にPointLineへのリンクを掲載し、謝意を表します。

aharalab.sakura.ne.jp

PointLineにおける点オブジェクトは、すべてがGeoGebraでいう「自由オブジェクト」であり、原則としてどの点でも動かすことができる。そして、点を動かした際の、他の点の挙動は、とても独特であり、しかしながら不規則という訳でもなく、非常に魅力的な動きをする。

本記事は、PointLineにおける点の挙動を、GeoGebraの視点から理解・説明しようという試みである。

※長期企画になります。分かるところから書き、随時増やしていきます。

 

円の中心と、円上の点

補助オブジェクト:C,D(自由な点)

 

AのOn Update スクリプト

SetValue[B,B+(UnitVector[Vector[C, B]] x(ExtendedAffineRatio[C, B, A] Distance[C, B]))/2]
SetValue[C,A]
SetValue[D,B]

 

BのOn Update スクリプト

SetValue[A,A+(UnitVector[Vector[D, A]] x(ExtendedAffineRatio[D, A, B] Distance[D, A]))/2]
SetValue[C,A]
SetValue[D,B]

※直感的説明:差分のベクトルのうち、「相手の点」成分の1/2のみで、相手の点を押す。 

 

なお、

UnitVector[Vector[C, B]] x(ExtendedAffineRatio[C, B, A] Distance[C, B])

は冗長なので、以下ではこれを

Push[A,B,C]

というオリジナルツールとして標記する。

Push[<始点>, <目標>, <補助点>]

で、「始点が補助点からどれだけ動いたか」を表すベクトルのうち、「補助点→目標」方向の成分のみを抽出する。

 

外接する2つの円の中心

 

補助オブジェクト:C,D(自由な点)

前提オブジェクト:diff(2つの円の半径の差分;固定値)

 

円Aの定義

Circle[A, (Distance[A, B] + diff) / 2]

 

円Bの定義

Circle[B, (Distance[A, B] - diff) / 2]

 

Aのスクリプト

If[Distance[A,B]>diff,SetValue[B,B+Push[A,B,C]/3],SetValue[B,B+Push[A,B,C]]]
SetValue[C,A]
SetValue[D,B]

 

Bのスクリプト

If[Distance[A,B]>diff,SetValue[A,A+Push[B,A,D]/3],SetValue[A,A+Push[B,A,D]]]
SetValue[C,A]
SetValue[D,B]

 

※直感的説明:AB間の距離がdiffより大きい場合→差分のベクトルのうち、「相手の点」成分の1/3倍のみで、相手の点を押す。

AB間の距離がdiff以下になった場合→差分のベクトルのうち、「相手の点」成分の1倍で、相手の点を押す。