二次曲線——放物線・楕円・双曲線
円錐曲線とは
「アイスクリームのコーンを斜めに切ると、断面が楕円になる」——知っていましたか?円錐(コーン)を平面で切ると、切り方によって 4 種類の曲線が現れます:円・楕円・放物線・双曲線。これらをまとめて円錐曲線(conic sections)と呼びます。
数式の形はどれも「 と の二次方程式」——つまり二次曲線です。これらは宇宙の軌道、衛星アンテナ、冷却塔など、あらゆる場所で登場します。
放物線(Parabola)
定義
「焦点」と「準線」という2つの要素を使って定義します——「焦点と準線から等距離にある点の集まり」が放物線です。
焦点 と準線 からの距離が等しい点の軌跡。
標準的な位置(頂点が原点、軸が 軸)での方程式で、
と書くと焦点は 、準線は です。
- ():上に開く——「お椀型」
- ():下に開く——「山型」
- が大きいほど細い放物線——「急な坂道のような形」
楕円(Ellipse)
定義
「2本の画鋲に輪ゴムをかけて、鉛筆で引っ張りながら一周する」——これで楕円が描けます。2本の画鋲が「焦点」です。
2 定点(焦点 )からの距離の和が一定の点の軌跡。
- 長軸: 軸方向、長さ ——「長い方向の直径」
- 短軸: 軸方向、長さ ——「短い方向の直径」
- 焦点:、ただし
- 離心率:(、0 に近いほど円に近い)
のとき → 円 (楕円の特殊ケース)——「2つの焦点が一つに重なると円になる」
双曲線(Hyperbola)
定義
「2点からの距離の差が一定」——楕円が「和」だったのに対して、双曲線は「差」です。
2 定点(焦点 )からの距離の差の絶対値が一定の点の軌跡。
- 頂点:——「2本の枝がx軸上で最も内側に来る点」
- 焦点:、ただし
- 漸近線:(双曲線が近づく直線)——「双曲線が限りなく近づくが届かない線」
- 離心率:()
インタラクティブ図解:3 曲線を切り替える
マウスを左右に動かすとパラメータが変わります。パネル右のボタン(左側 1/3 = 放物線、中央 = 楕円、右側 1/3 = 双曲線)で曲線を切り替えられます。
var OX = 300, OY = 200, SC = 40;
var t = 0;
function toS(x, y) { return [OX + x*SC, OY - y*SC]; }
function loop() {
ctx.clearRect(0, 0, W, H);
t += 0.02;
// 曲線選択
var zone = Math.floor(mx / W * 3);
if (zone < 0) zone = 0;
if (zone > 2) zone = 2;
// グリッド
ctx.strokeStyle = '#161b22'; ctx.lineWidth = 1;
for (var gx = -7; gx <= 7; gx++) {
ctx.beginPath(); ctx.moveTo(OX+gx*SC,0); ctx.lineTo(OX+gx*SC,H); ctx.stroke();
}
for (var gy = -4; gy <= 5; gy++) {
ctx.beginPath(); ctx.moveTo(0,OY-gy*SC); ctx.lineTo(W,OY-gy*SC); ctx.stroke();
}
ctx.strokeStyle = '#30363d'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(0,OY); ctx.lineTo(W,OY); ctx.stroke();
ctx.beginPath(); ctx.moveTo(OX,0); ctx.lineTo(OX,H); ctx.stroke();
ctx.fillStyle = '#8b949e'; ctx.font = '12px sans-serif';
ctx.fillText('x', W-14, OY-8); ctx.fillText('y', OX+6, 14);
var curveColor, label, eqLabel;
if (zone === 0) {
// 放物線 y = x²
curveColor = '#56d364';
label = '放物線';
eqLabel = 'y = x²';
ctx.beginPath();
var started = false;
for (var xi = -3.5; xi <= 3.5; xi += 0.05) {
var yi = xi * xi;
var pt = toS(xi, yi);
if (pt[1] < -20 || pt[1] > H+20) { started = false; continue; }
if (!started) { ctx.moveTo(pt[0], pt[1]); started = true; }
else ctx.lineTo(pt[0], pt[1]);
}
ctx.strokeStyle = curveColor; ctx.lineWidth = 2.5; ctx.stroke();
// 焦点 (0, 1/4)
var fp = toS(0, 0.25);
ctx.beginPath(); ctx.arc(fp[0], fp[1], 5, 0, Math.PI*2);
ctx.fillStyle = '#ffa657'; ctx.fill();
ctx.fillStyle = '#ffa657'; ctx.font = '11px sans-serif';
ctx.fillText('焦点F(0, 1/4)', fp[0]+8, fp[1]-6);
// 準線 y = -1/4
var lp = toS(-5, -0.25), lp2 = toS(5, -0.25);
ctx.beginPath(); ctx.moveTo(lp[0], lp[1]); ctx.lineTo(lp2[0], lp2[1]);
ctx.strokeStyle = '#ffa65780'; ctx.lineWidth = 1.5; ctx.setLineDash([4,3]);
ctx.stroke(); ctx.setLineDash([]);
ctx.fillStyle = '#ffa657'; ctx.font = '11px sans-serif';
ctx.fillText('準線 y = -1/4', OX+8, lp[1]-4);
// 動点
var px = Math.cos(t) * 2.5;
var py = px * px;
var pp = toS(px, py);
ctx.beginPath(); ctx.arc(pp[0], pp[1], 5, 0, Math.PI*2);
ctx.fillStyle = '#f0883e'; ctx.fill();
// 焦点への線
ctx.beginPath(); ctx.moveTo(pp[0], pp[1]); ctx.lineTo(fp[0], fp[1]);
ctx.strokeStyle = '#f0883e60'; ctx.lineWidth = 1; ctx.stroke();
// 準線への垂線
var lpp = toS(px, -0.25);
ctx.beginPath(); ctx.moveTo(pp[0], pp[1]); ctx.lineTo(lpp[0], lpp[1]);
ctx.strokeStyle = '#f0883e60'; ctx.lineWidth = 1; ctx.stroke();
} else if (zone === 1) {
// 楕円 x²/9 + y²/4 = 1
var ea = 3, eb = 2, ec = Math.sqrt(ea*ea - eb*eb);
curveColor = '#58a6ff';
label = '楕円';
eqLabel = 'x²/9 + y²/4 = 1';
ctx.beginPath();
for (var ang = 0; ang <= Math.PI*2+0.05; ang += 0.05) {
var ex = ea * Math.cos(ang), ey = eb * Math.sin(ang);
var ep = toS(ex, ey);
if (ang === 0) ctx.moveTo(ep[0], ep[1]); else ctx.lineTo(ep[0], ep[1]);
}
ctx.strokeStyle = curveColor; ctx.lineWidth = 2.5; ctx.stroke();
ctx.fillStyle = curveColor + '0a'; ctx.fill();
// 焦点
var ef1 = toS(-ec, 0), ef2 = toS(ec, 0);
[ef1, ef2].forEach(function(f) {
ctx.beginPath(); ctx.arc(f[0], f[1], 5, 0, Math.PI*2);
ctx.fillStyle = '#ffa657'; ctx.fill();
});
ctx.fillStyle = '#ffa657'; ctx.font = '11px sans-serif';
ctx.fillText('F₁(-√5,0)', ef1[0]-60, ef1[1]-10);
ctx.fillText('F₂(√5,0)', ef2[0]+4, ef2[1]-10);
// 動点
var et = t * 0.7;
var epx = ea * Math.cos(et), epy = eb * Math.sin(et);
var epp = toS(epx, epy);
ctx.beginPath(); ctx.arc(epp[0], epp[1], 5, 0, Math.PI*2);
ctx.fillStyle = '#f0883e'; ctx.fill();
ctx.beginPath(); ctx.moveTo(epp[0], epp[1]); ctx.lineTo(ef1[0], ef1[1]);
ctx.strokeStyle = '#f0883e60'; ctx.lineWidth = 1.5; ctx.stroke();
ctx.beginPath(); ctx.moveTo(epp[0], epp[1]); ctx.lineTo(ef2[0], ef2[1]);
ctx.strokeStyle = '#f0883e60'; ctx.lineWidth = 1.5; ctx.stroke();
var d1 = Math.sqrt(Math.pow(epx+ec,2)+epy*epy);
var d2 = Math.sqrt(Math.pow(epx-ec,2)+epy*epy);
ctx.fillStyle = '#f0883e'; ctx.font = '11px monospace';
ctx.fillText('d₁+d₂ = ' + (d1+d2).toFixed(2) + ' = 2a', 20, H-20);
} else {
// 双曲線 x²/4 - y²/1 = 1
var ha = 2, hb = 1, hc = Math.sqrt(ha*ha + hb*hb);
curveColor = '#bc8cff';
label = '双曲線';
eqLabel = 'x²/4 - y² = 1';
// 漸近線
ctx.beginPath();
var as1 = toS(-5, -5*hb/ha), as2 = toS(5, 5*hb/ha);
ctx.moveTo(as1[0], as1[1]); ctx.lineTo(as2[0], as2[1]);
ctx.strokeStyle = '#bc8cff40'; ctx.lineWidth = 1.5; ctx.setLineDash([6,4]);
ctx.stroke();
ctx.beginPath();
as1 = toS(-5, 5*hb/ha); as2 = toS(5, -5*hb/ha);
ctx.moveTo(as1[0], as1[1]); ctx.lineTo(as2[0], as2[1]);
ctx.stroke(); ctx.setLineDash([]);
// 双曲線
for (var side = -1; side <= 1; side += 2) {
ctx.beginPath();
var hstarted = false;
for (var hx = side * ha; hx * side <= 5; hx += side * 0.05) {
var hy = Math.sqrt(hx*hx/ha/ha - 1) * hb;
if (isNaN(hy)) continue;
for (var hsign = -1; hsign <= 1; hsign += 2) {
var hp = toS(hx, hy * hsign);
// 上側のみ先に書く
break;
}
var hp1 = toS(hx, hy), hp2 = toS(hx, -hy);
if (!hstarted) { ctx.moveTo(hp1[0], hp1[1]); hstarted = true; }
else ctx.lineTo(hp1[0], hp1[1]);
}
ctx.strokeStyle = curveColor; ctx.lineWidth = 2.5; ctx.stroke();
ctx.beginPath(); hstarted = false;
for (var hx2 = side * ha; hx2 * side <= 5; hx2 += side * 0.05) {
var hy2 = Math.sqrt(Math.max(0, hx2*hx2/ha/ha - 1)) * hb;
var hp3 = toS(hx2, -hy2);
if (!hstarted) { ctx.moveTo(hp3[0], hp3[1]); hstarted = true; }
else ctx.lineTo(hp3[0], hp3[1]);
}
ctx.strokeStyle = curveColor; ctx.lineWidth = 2.5; ctx.stroke();
}
// 焦点
var hf1 = toS(-hc, 0), hf2 = toS(hc, 0);
[hf1, hf2].forEach(function(f) {
ctx.beginPath(); ctx.arc(f[0], f[1], 5, 0, Math.PI*2);
ctx.fillStyle = '#ffa657'; ctx.fill();
});
ctx.fillStyle = '#ffa657'; ctx.font = '11px sans-serif';
ctx.fillText('F₁(-√5,0)', hf1[0]-60, hf1[1]-10);
ctx.fillText('F₂(√5,0)', hf2[0]+4, hf2[1]-10);
ctx.fillStyle = '#bc8cff80'; ctx.font = '11px sans-serif';
ctx.fillText('漸近線 y=±x/2', OX + 3*SC, OY - 1.5*SC);
}
// パネル
ctx.fillStyle = '#0d1117e0';
ctx.fillRect(8, 8, 220, 76);
ctx.strokeStyle = '#30363d'; ctx.lineWidth = 1;
ctx.strokeRect(8, 8, 220, 76);
ctx.font = 'bold 16px sans-serif';
ctx.fillStyle = curveColor;
ctx.fillText(label, 16, 32);
ctx.font = '13px monospace';
ctx.fillStyle = '#e6edf3';
ctx.fillText(eqLabel, 16, 54);
ctx.fillStyle = '#8b949e'; ctx.font = '11px sans-serif';
ctx.fillText('マウスで曲線切替(3ゾーン)', 16, 72);
requestAnimationFrame(loop);
}
loop();
3 曲線の共通点と違い
| 性質 | 放物線 | 楕円 | 双曲線 |
|---|---|---|---|
| 焦点の数 | 1 | 2 | 2 |
| 定義の距離条件 | 焦点と準線が等距離 | 焦点2つへの距離の和一定 | 焦点2つへの距離の差一定 |
| 離心率 | |||
| 漸近線 | なし | なし | あり |
離心率の統一的理解
実は 3 つの曲線すべてを「焦点と準線からの距離の比 = 離心率 」という条件で統一できます——「e というパラメータ一つで三つの曲線を区別できる」という美しい統一性です:
- :放物線——「等距離だから放物線」
- :楕円( は円)——「焦点に近い方が重視される」
- :双曲線——「準線から遠い方が重視される」
楕円の面積
楕円 の面積は:
円 の一般化です( で一致)——「長軸の半分 × 短軸の半分 × π」という覚え方です。
双曲線の漸近線
の漸近線 は、双曲線が近づく直線です——「双曲線の腕が限りなく近づくが決して届かない直線」。
直交双曲線()は で漸近線が ()という特殊ケースです——「反比例のグラフ が双曲線の一種」というのは知っていましたか?
まとめ
- 放物線 :焦点 + 準線から等距離の軌跡——「サテライトアンテナの断面形」
- 楕円 :2 焦点への距離の和が一定——「惑星の軌道」
- 双曲線 :2 焦点への距離の差の絶対値が一定——「双曲線航法」
- 離心率 によって 3 曲線が統一的に理解できる——「 が放物線の境界線」
次回は「軌跡」——条件を満たす点が描く図形——の求め方を学びます。