210 lines
4.2 KiB
JavaScript
210 lines
4.2 KiB
JavaScript
let charges = [];
|
|
|
|
let sphere_radius = 200;
|
|
|
|
let physics = false;
|
|
let earth = false;
|
|
let skeleton = false;
|
|
let planes = false;
|
|
|
|
let red;
|
|
let yellow;
|
|
|
|
function preload() {
|
|
earth_image = loadImage("atlas1.jpg");
|
|
}
|
|
|
|
function setup() {
|
|
createCanvas(600, 600, WEBGL);
|
|
red = color(0xbf, 0x00, 0x00);
|
|
yellow = color(0xff, 0xff, 0x00);
|
|
}
|
|
|
|
function draw() {
|
|
orbitControl();
|
|
background(50);
|
|
|
|
make_lights();
|
|
if (physics) {
|
|
move_charges(charges);
|
|
}
|
|
if (skeleton) {
|
|
draw_skeleton(sphere_radius);
|
|
}
|
|
|
|
if (planes) {
|
|
let p = charges[0];
|
|
let a = charges[1];
|
|
let b = charges[2];
|
|
p.color = yellow;
|
|
a.color = yellow;
|
|
b.color = yellow;
|
|
let n = p5.Vector.sub(p.position, a.position).cross(p5.Vector.sub(p.position, b.position));
|
|
n.normalize(); // unnecessary
|
|
push();
|
|
strokeWeight(5);
|
|
stroke(0x7f);
|
|
line(
|
|
0,0,0,
|
|
n.x*sphere_radius,n.y*sphere_radius,n.z*sphere_radius,
|
|
)
|
|
fill(0xff);
|
|
strokeWeight(3);
|
|
stroke(0x00);
|
|
beginShape(TRIANGLES);
|
|
const v1 = p5.Vector.mult(p.position, sphere_radius);
|
|
const v2 = p5.Vector.mult(a.position, sphere_radius);
|
|
const v3 = p5.Vector.mult(b.position, sphere_radius);
|
|
vertex(v1.x, v1.y, v1.z);
|
|
vertex(v2.x, v2.y, v2.z);
|
|
vertex(v3.x, v3.y, v3.z);
|
|
endShape();
|
|
pop();
|
|
} else {
|
|
for (let charge of charges) {
|
|
charge.color = red;
|
|
}
|
|
}
|
|
|
|
draw_charges(sphere_radius);
|
|
draw_sphere(sphere_radius, 25);
|
|
}
|
|
|
|
function draw_skeleton(radius) {
|
|
push();
|
|
noStroke();
|
|
fill(0xff);
|
|
sphere(4);
|
|
stroke(0xbf);
|
|
for (let charge of charges) {
|
|
line(
|
|
0,
|
|
0,
|
|
0,
|
|
charge.position.x * radius,
|
|
charge.position.y * radius,
|
|
charge.position.z * radius,
|
|
);
|
|
}
|
|
pop();
|
|
}
|
|
|
|
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(),
|
|
color: red,
|
|
});
|
|
}
|
|
}
|
|
|
|
function draw_charges(radius) {
|
|
push();
|
|
noStroke();
|
|
for (let charge of charges.values()) {
|
|
ambientMaterial(charge.color);
|
|
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,
|
|
earth ? 2 : n_axis_circles,
|
|
color(0x00, 0x9f, 0xff),
|
|
color(0xff, 0x9f, 0x00),
|
|
);
|
|
pop();
|
|
push();
|
|
rotateY(TAU / 4);
|
|
draw_circles(
|
|
radius,
|
|
earth ? 2 : n_axis_circles,
|
|
color(0xff, 0x00, 0xff),
|
|
color(0x00, 0xff, 0x00),
|
|
);
|
|
pop();
|
|
|
|
if (earth) {
|
|
noStroke();
|
|
noFill();
|
|
tint(0xff, 0x9f);
|
|
texture(earth_image);
|
|
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 == ' ') {
|
|
physics = !physics;
|
|
} else if (key == 'd') {
|
|
earth = !earth;
|
|
} else if (key == 'f') {
|
|
skeleton = !skeleton;
|
|
} else if (key == 'g') {
|
|
planes = !planes;
|
|
} else if (key >= '0' && key <= '9') {
|
|
make_charges(int(key));
|
|
}
|
|
}
|
|
|
|
// TODO draw faces
|
|
// algorithm: choose 3 vertices until 2-partition of other vertices has one empty set
|
|
// done when V - E + F = 2. V is known. count E and F while creating faces
|