楕円反射_うしver
このアプレットは、miyamath84様「楕円反射」に触発されて作りました。
楕円形のビリヤードです。焦点から白い球を打つと、必ずもう一つの焦点を通過し、もとの焦点に帰ってくる様子が観察でき、楕円の性質を視覚的に確認することができます。
主な設計
前提オブジェクト
自由な点オブジェクト: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の位置によらず一定であるのが、楕円の性質である)
球(のリスト)のつくりかた
n個の球を、リストとしてまとめて作ってしまう(以下の図は、n=6の場合である)。そのために、SequenceやZipといったコマンドを活用していく。
toFirstRay = Sequence[Rotate[Direction, α, F1], α, 2π / n, 2π, 2π / n] ・・・F1を始点とする半直線を確定するための点。
firstRayList = Zip[Ray[F1, β], β, toFirstRay] ・・・この半直線が楕円の周に届くまでが、球の最初の軌道となる。
firstRef = Zip[Intersect[γ, ellipseAsPolyLine], γ, firstRayList] ・・・球が最初に楕円の周にぶつかる点。
toSecondRay = Zip[Dilate[δ, (SemiMajorAxisLength[Ellipse[F1, F2, P]] - Distance[F1, F2] / 2) / 2 / Distance[δ, F2], F2], δ, firstRef] ・・・firstRefからF2を通り、ふたたび楕円の周にぶつかるまでの軌道を、半直線で表すための、当該半直線の始点。始点が楕円の外に作られないようにするために(もし外に作ってしまうと、半直線と楕円の交点が2つになってしまい、都合が悪い)、始点は、かならずF2から、「F2〜楕円の最短距離÷2」の位置に作られるよう、Dilateの比率を調整してある。
secondRayList = Zip[Ray[ε, F2], ε, toSecondRay] ・・・firstRefからF2を通り、ふたたび楕円の周にぶつかるまでの軌道を、半直線で表したもの。
secondRef = Zip[Intersect[ζ, ellipseAsPolyLine], ζ, secondRayList] ・・・球が2回目に楕円の周にぶつかる点。
球は、F1→firstRef(の各要素)→F2→secondRef(の各要素)→F1という軌道をたどる。
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[α, β]だけ進んだ場所とする。