Chapter 60

万有引力

miku
miku
2021.11.17に更新
このチャプターの目次

地球が人間やりんごを引っ張っているように、逆に人間やりんごも地球を引っ張っている。このような互いを引っ張り合う力のことを万有引力と呼ぶ。

F = G\frac{m_{1}m_{2}}{r^2}

万有引力の大きさを求める式は上記の通りで、m1, m2 が質量、r が物体同士の2点間の距離である。G が万有引力定数というもので、質量や距離にかかわらず固定にかかる定数になる。式から見るに、質量が大きいか、あるいは距離が縮まるほど力が大きくなる。

今までは質量が無いものとして力の計算をしてきたが、万有引力の式には質量が入っているので、この章では質量を扱うことにする。つまり F = aF = ma として扱う。

人間やりんごから地球を引っ張っているようには感じられないが、F = mam を移行して、F/m = a にすると、加速度は力を質量で割ったものになる。地球の質量はりんごや人間に比べて遥かに大きいので、得られる加速度の影響はほとんどない。

この章で実装するのは、万有引力の見た目が最もはっきりとわかる、太陽の周りを惑星がぐるぐる回っているものである。

地球が人間やりんごからの万有引力がほとんど無いように、太陽も惑星からの影響が殆どないものだとここでは考えて、太陽の位置は固定にする。そしてその周りを惑星がぐるぐる回っている物を作りたい。

作例

const mass = 100000; // 太陽の質量
const mass2 = 10; // 惑星の質量
const maxF = 10; // 力の大きさの上限
let p, v, a;

function setup() {
  createCanvas(windowWidth, windowHeight);

  // 惑星の初期位置、初期速度、初期加速度
  p = createVector(200, 0);
  v = createVector(0, 10);
  a = createVector(0, 0);
}

function draw() {
  clear();

  // 太陽(0, 0)から惑星までの距離
  const r = p.mag();
  // 万有引力の大きさの計算
  const f = min((mass * mass2) / (r * r), maxF);
  // 惑星から太陽までの向き
  const angle = atan2(0 - p.y, 0 - p.x);
  // 万有引力の大きさと向きから力を求める
  const fv = p5.Vector.fromAngle(angle, f);
  // 力のベクトルを質量で割り、加速度を求める
  const a = fv.div(mass2);
  v.add(a);
  p.add(v);

  translate(width / 2, height / 2);
  circle(0, 0, 100);
  circle(p.x, p.y, 10);
  resetMatrix();
}

万有引力の式には距離の二乗で割っている部分があるが、画面内に表示を収めようとすると距離が小さくなり、非常に大きい力が発生するので、そこから求まる加速度で惑星を動かすとすぐに画面からはみ出てしまう。なので、力の上限である maxF を超えないように調整している。太陽と惑星の質量は適当に設定しているので万有引力定数を定義して掛け合わせなくても問題はない。

作例 その2

const mass = 100000;
const maxF = 10;
const n = 10;
let planets;

function setup() {
  createCanvas(windowWidth, windowHeight);

  planets = [];
  for (let i = 0; i < n; i++) {
    planets.push(Planet.create());
  }
}

function draw() {
  clear();
  translate(width / 2, height / 2);
  circle(0, 0, 200);

  for (const p of planets) {
    Planet.update(p);
  }

  resetMatrix();
}

const Planet = {
  create: function () {
    const pos = createVector(200, 0);
    const vel = p5.Vector.random2D().mult(5);
    const mass = random(10, 100);

    return { pos, vel, mass };
  },

  update: function (p) {
    const d = p.pos.mag();
    const f = min((mass * p.mass) / (d * d), maxF);
    const angle = atan2(0 - p.pos.y, 0 - p.pos.x);
    const fv = p5.Vector.fromAngle(angle, f);
    const a = fv.div(p.mass);
    p.vel.add(a);
    p.pos.add(p.vel);

    circle(p.pos.x, p.pos.y, p.mass / 5);
  },
};