
strange behaviour with velocity.mag() sometimes it is unbounded, sometimes it remains bounded the issue is `project_onto_plane` mutates its first argument (1) mutating fn yyyynnnn (2) call fn yynnyynn (3) use fn retval ynynynyn (1) & (2) yynnnnnn [(1) & (2)] | (3) yyynynyn bounded? yy-nyn-n the case that we want is (1) yes (2) yes (3) no or this one (1) no (2) yes (3) yes
177 lines
3.9 KiB
JavaScript
177 lines
3.9 KiB
JavaScript
let charges = [];
|
|
|
|
let sphere_mode = 'circles';
|
|
let sphere_radius = 200;
|
|
|
|
let physics = false;
|
|
|
|
function preload() {
|
|
earth = loadImage("atlas1.jpg");
|
|
}
|
|
|
|
function setup() {
|
|
createCanvas(600, 600, WEBGL);
|
|
}
|
|
|
|
function draw() {
|
|
orbitControl();
|
|
background(50);
|
|
|
|
make_lights();
|
|
if (physics) {
|
|
move_charges();
|
|
}
|
|
draw_charges(sphere_radius);
|
|
draw_sphere(sphere_radius, 25);
|
|
}
|
|
|
|
function move_charges() {
|
|
for (charge of charges) {
|
|
charge.acceleration.setMag(0);
|
|
}
|
|
for (let i = 0; i < charges.length; i += 1) {
|
|
for (let j = 0; j < i; j += 1) {
|
|
const displacement = p5.Vector.sub(
|
|
charges[i].position,
|
|
charges[j].position,
|
|
);
|
|
const acceleration_mag = 1 / displacement.mag() * 0.005;
|
|
let ai = displacement.copy().normalize().mult(acceleration_mag);
|
|
let aj = p5.Vector.mult(ai, -1);
|
|
project_onto_plane(ai, charges[i].position);
|
|
project_onto_plane(aj, charges[j].position);
|
|
charges[i].acceleration.add(ai);
|
|
charges[j].acceleration.add(aj);
|
|
}
|
|
}
|
|
for (let i = 0; i < charges.length; i += 1) {
|
|
let charge = charges[i];
|
|
charge.velocity = charge.velocity.add(charge.acceleration);
|
|
//project_onto_plane(charge.velocity, charge.position);
|
|
charge.position = charge.position.add(charge.velocity);
|
|
charge.position.normalize();
|
|
}
|
|
}
|
|
|
|
function project_onto_unit_vector(v, unit_vector) {
|
|
let size = p5.Vector.dot(v, unit_vector);
|
|
return p5.Vector.mult(unit_vector, size);
|
|
}
|
|
|
|
/// Project `v` onto the plane normal to `unit_vector`
|
|
/// Mutates `v`
|
|
function project_onto_plane(v, unit_vector) {
|
|
let v_proj = project_onto_unit_vector(v, unit_vector);
|
|
v.sub(v_proj)
|
|
}
|
|
|
|
function make_charges(n) {
|
|
charges = [];
|
|
for (let i = 0; i < n; i += 1) {
|
|
let position;
|
|
if (i === 0) {
|
|
position = createVector(0, -1, 0);
|
|
} else {
|
|
const lat = random(-TAU / 4, TAU / 4);
|
|
const lon = random(0, TAU);
|
|
position = createVector(
|
|
cos(lat) * cos(lon),
|
|
sin(lat),
|
|
cos(lat) * sin(lon),
|
|
);
|
|
}
|
|
charges.push({
|
|
position: position,
|
|
velocity: createVector(),
|
|
acceleration: createVector(),
|
|
});
|
|
}
|
|
}
|
|
|
|
function draw_charges(radius) {
|
|
push();
|
|
noStroke();
|
|
ambientMaterial(0xbf, 0x00, 0x00);
|
|
for (let charge of charges.values()) {
|
|
let position = charge.position.copy();
|
|
position.mult(radius);
|
|
push();
|
|
translate(position.x, position.y, position.z);
|
|
sphere(15);
|
|
pop();
|
|
}
|
|
pop();
|
|
}
|
|
|
|
function draw_sphere(radius, n_axis_circles) {
|
|
stroke(0x3f);
|
|
noFill();
|
|
|
|
push();
|
|
rotateX(TAU / 4);
|
|
draw_circles(
|
|
radius,
|
|
sphere_mode === 'earth' ? 2 : n_axis_circles,
|
|
color(0x00, 0x9f, 0xff),
|
|
color(0xff, 0x9f, 0x00),
|
|
);
|
|
pop();
|
|
push();
|
|
rotateY(TAU / 4);
|
|
draw_circles(
|
|
radius,
|
|
sphere_mode === 'earth' ? 2 : n_axis_circles,
|
|
color(0xff, 0x00, 0xff),
|
|
color(0x00, 0xff, 0x00),
|
|
);
|
|
pop();
|
|
|
|
if (sphere_mode === 'earth') {
|
|
noStroke();
|
|
noFill();
|
|
tint(0xff, 0x9f);
|
|
texture(earth);
|
|
push();
|
|
rotateY(TAU / 4);
|
|
sphere(radius);
|
|
pop();
|
|
}
|
|
}
|
|
|
|
function draw_circles(radius, n_circles, pole_1_color, pole_2_color) {
|
|
push();
|
|
stroke(pole_1_color);
|
|
translate(0, 0, -radius);
|
|
point(0, 0);
|
|
pop();
|
|
for (let i = 1; i < n_circles; i += 1) {
|
|
const angle = map(i, 0, n_circles - 1, -TAU / 4, TAU / 4);
|
|
const circle_radius = radius * cos(angle);
|
|
push();
|
|
translate(0, 0, radius * sin(angle));
|
|
circle(0, 0, circle_radius * 2);
|
|
pop();
|
|
}
|
|
push();
|
|
stroke(pole_2_color);
|
|
translate(0, 0, radius);
|
|
point(0, 0);
|
|
pop();
|
|
}
|
|
|
|
function make_lights() {
|
|
let light = createVector(0, 1, -1);
|
|
light.normalize();
|
|
directionalLight(0x1f, 0x1f, 0x1f, light);
|
|
ambientLight(0xbf);
|
|
}
|
|
|
|
function keyPressed() {
|
|
if (key == 'd') {
|
|
sphere_mode = sphere_mode === 'earth' ? 'circles' : 'earth';
|
|
} else if (key == ' ') {
|
|
physics = !physics;
|
|
} else if (key >= '0' && key <= '9') {
|
|
make_charges(int(key));
|
|
}
|
|
}
|