0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

円錐と2次曲線に関する数値計算

0
Posted at

はじめに

円錐を様々な角度で切断することを考える。この場合、切断面は円、楕円、放物線、双曲線になることが知られている。
これらの曲線を総称して2次曲線という。
そこで、今回はPythonを用いて円錐を描写し、様々な角度で切断するシミュレーションを実施する。

問題設定

今回用いる円錐の方程式を以下のように定義する。

z=r-\sqrt{x^2+y^2}

今回は、$r=1$とする。
この場合、円錐は以下のように図示する事ができる。

円錐.png

この円錐を3パターンの方法で切断することを考え、その際の断面をプロットするプログラムを作成した。

双曲線

縦に切断することを考える。

 双曲線.png

楕円

円錐に対して斜めに切断する。

楕円.png

放物線

円錐に対して母線と平行に切断する。

放物線.png

プログラム

python cone.py
"""
円錐(コーン)を色々な角度の平面で切断すると、切り口が
円・楕円・放物線・双曲線のいずれか(=2次曲線/円錐曲線)になる、
という古典的な事実を数値的に(点群として)確認・可視化するプログラム。

【円錐の作り方】
    z = r - sqrt(x^2 + y^2)
は、頂点 (0, 0, r) から下に向かって開いていく「円錐面」の式で、
両辺を整理すると
    x^2 + y^2 = (r - z)^2
という陰関数(円錐の標準形)になる。この円錐は
    半径方向に 1 進むと z が 1 下がる
という形なので、軸(z軸)と母線(斜面)のなす半頂角は 45° になる。
この「45°」という値が、後述する各切断面が
楕円/放物線/双曲線のどれになるかを決める基準値として効いてくる。

【切断面が何になるかの判定(一般論)】
    平面を z = A*x + B*y + C の形で表したとき(A, B は平面の傾き)、
    円錐 x^2+y^2=(1-z)^2 との交線の式を x, y について整理すると

        (1-A^2) x^2 - 2AB xy + (1-B^2) y^2 + (線形項) = 0

    という2次曲線の一般形になり、判別式 B^2-4AC に相当する量が
        4*(A^2 + B^2 - 1)
    となる。つまり平面の傾きの大きさ A^2+B^2 を
    円錐の傾き(45°、勾配の2乗で言うと 1)と比較すればよく、

        A^2 + B^2 < 1  → 判別式 < 0 → 楕円(母線より緩い傾きで切る)
        A^2 + B^2 = 1  → 判別式 = 0 → 放物線(母線と平行に切る)
        A^2 + B^2 > 1  → 判別式 > 0 → 双曲線(母線より急な傾きで切る)

    平面が軸(z軸)と平行/軸を含むような「垂直な平面」(x=定数 など)は
    A→∞ に相当する極端なケースで、これも双曲線になる。
"""

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib  # matplotlibで日本語(軸ラベル等)を文字化けさせずに表示するための設定
import math
from mpl_toolkits.mplot3d.axes3d import Axes3D  # 3D描画(Axes3D)を使うために必要


r = 1  # 円錐の「高さ方向のスケール」。頂点は (0, 0, r) = (0, 0, 1)

n = 1000  # x, y方向の格子点数(解像度)。大きいほど滑らかだが計算が重くなる

# x, y をそれぞれ -1〜1 の範囲で n 分割し、円錐を描くための格子(メッシュ)を作る
x_ary = np.linspace(-1, 1, n)
y_ary = x_ary

X, Y = np.meshgrid(x_ary, y_ary)

#Z=r-(X**2+Y**2)**0.5
Z = np.zeros((n, n))  # 円錐の高さ z を格子点ごとに計算して入れていく配列(後のループで埋める)


# 各切断面ごとに、切り口(交線)付近の点を集めておくためのリスト
# 1: 平面 x = 一定 で切った断面 → 双曲線になるはず
x1_ary = []
y1_ary = []
z1_ary = []

# 2: 平面 x + y + 10z = 一定(ほぼ水平に近い平面)で切った断面 → 楕円になるはず
x2_ary = []
y2_ary = []
z2_ary = []

# 3: 平面 z = (y-x)/√2 - 定数 で切った断面 → 放物線になる
x3_ary = []
y3_ary = []
z3_ary = []

for i in range(n):
    for k in range(n):
        x = X[i][k]
        y = Y[i][k]
        z = r - (x**2 + y**2) ** 0.5  # 円錐面の高さ z = r - (原点からの距離)
        Z[i][k] = z

        # --- 切断面1: x ≈ 0.555 の「垂直な平面」(z軸と平行)で円錐を切る ---
        # ちょうどの等式では格子点がほぼヒットしないので、薄い帯(0.55<x<0.56)で
        # 「その平面付近を通る点」を代わりに拾い、切り口の形を点群として近似する
        if 0.55 < x < 0.56:
            y1_ary.append(y)
            z1_ary.append(z)

        # --- 切断面2: x + y + 10z ≈ 一定 という、ほとんど水平に近い平面で切る ---
        # z の係数(10)が x, y の係数(1)よりずっと大きい = 傾き A,B が小さい
        # → A^2+B^2 < 1 なので楕円になる
        if 0.1 < y + x - 0.5 + 10 * z < 0.2:
            x2_ary.append(x)
            y2_ary.append(y)
            z2_ary.append(z)

        # --- 切断面3: (y-x)/√2 - z ≈ 一定、つまり z = (y-x)/√2 - 定数 という平面で切る ---
        # 傾きは A=-1/√2, B=1/√2 なので A^2+B^2 = 1/2+1/2 = 1 となり、
        # ちょうど円錐の母線(45°)と平行な平面 → 放物線になる
        if 0.1 < (y - x) / math.sqrt(2) - z < 0.2:
            x3_ary.append(x)
            y3_ary.append(y)
            z3_ary.append(z)


# --- 円錐そのものを3Dで描画 ---
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap='bwr', linewidth=0)  # 高さzに応じて色が変わる曲面プロット
fig.colorbar(surf)  # 高さと色の対応を示すカラーバー
plt.savefig("円錐.png")
plt.show()


# --- 切断面1(x≈一定)による切り口を (y, z) 平面上の散布図として描画 ---
# 前述の通り、この切り口は理論上「双曲線」になる
# ※直前が3D軸(ax)なので、新しくFigureを作ってから2D散布図を描く必要がある
plt.figure()
plt.scatter(y1_ary, z1_ary)
plt.savefig("双曲線.png")
plt.show()
plt.close()

# 図の作成
fig = plt.figure()
# 3次元の座標軸
ax2 = fig.add_subplot(projection="3d")

# --- 切断面2(x+y+10z≈一定)による切り口を3D散布図として描画 ---
# 傾きが緩やか(A^2+B^2<1)なので、理論上「楕円」になる
ax2.scatter(x2_ary, y2_ary, z2_ary)
plt.savefig("楕円.png")
plt.show()


# 図の作成
fig = plt.figure()
# 3次元の座標軸
ax3 = fig.add_subplot(projection="3d")
# --- 切断面3((y-x)/√2-z≈一定)による切り口を3D散布図として描画 ---
# A^2+B^2=1(母線と平行)なので、理論上「放物線」になる
ax3.scatter(x3_ary, y3_ary, z3_ary)
plt.savefig("放物線.png")
plt.show()

まとめ

今回は、円錐の切断面が2次曲線になることを視覚的に確かめた。
ただし、証明についてはかなり難しいので省略した。
数値計算ではこのように、証明が難しい命題の真偽を確認する際の最初のステップ(実験)としては、
有効である。
ただし、あくまで扱えるのは有限のパターンのみであることに注意したい。

参考文献

0
2
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
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?