diff --git a/index.html b/index.html index ff66bc9..45e21e7 100644 --- a/index.html +++ b/index.html @@ -6,18 +6,108 @@ p5.js +
+ + diff --git a/sketch.js b/sketch.js index 1d3cb0a..a04f4ac 100644 --- a/sketch.js +++ b/sketch.js @@ -4,7 +4,7 @@ let red; let charges = []; let faces = []; -let sphere_radius = 200; +let sphere_radius; const SURFACE_NONE = 0; const SURFACE_CIRCLES = 1; @@ -13,7 +13,14 @@ const SURFACE_EARTH = 2; let surface = SURFACE_CIRCLES; let physics = false; let skeleton = false; -let polyhedron = false; +let polytope = false; + +let buttons_surface; +let checkbox_physics; +let checkbox_skeleton; +let checkbox_polytope; + +let aside_size; function preload() { @@ -21,25 +28,53 @@ function preload() { } function setup() { - createCanvas(windowWidth, windowHeight, WEBGL); + createCanvas(0, 0, WEBGL); + aside_size = int(getComputedStyle(document.documentElement).getPropertyValue('--aside-size').replace('px', '')); + windowResized(); + camera = createCamera(); red = color(0xbf, 0x00, 0x00); + sphere_radius = min(250, min(width, height) / 2 * 0.8); + + checkbox_physics = document.getElementById("checkbox-physics"); + checkbox_physics.checked = physics; + + checkbox_skeleton = document.getElementById("checkbox-skeleton"); + checkbox_skeleton.checked = skeleton; + + checkbox_polytope = document.getElementById("checkbox-polytope"); + checkbox_polytope.checked = polytope; + + buttons_surface = [ + document.getElementById("button-surface-none"), + document.getElementById("button-surface-circles"), + document.getElementById("button-surface-earth"), + ] + buttons_surface[surface].disabled = true; } function windowResized() { - resizeCanvas(windowWidth, windowHeight); + if (windowWidth >= windowHeight) { + resizeCanvas(windowWidth - aside_size, windowHeight); + } else { + resizeCanvas(windowWidth, windowHeight - aside_size); + } } function draw() { - orbitControl(); background(50); + orbitControl(); + camera.centerX = 0; + camera.centerY = 0; + camera.centerZ = 0; + make_lights(); if (physics) move_charges(charges); draw_charges(sphere_radius); if (skeleton) draw_skeleton(sphere_radius); - if (polyhedron) { + if (polytope) { if (physics || faces.length === 0) find_faces(); draw_faces(sphere_radius); } @@ -56,7 +91,7 @@ function find_faces() { for (let i = 2; i < charges.length; i += 1) { for (let j = 1; j < i; j += 1) { for (let k = 0; k < j; k += 1) { - // Check if p1 p2 p3 form a face of the convex polyhedron + // Check if p1 p2 p3 form a face of the convex polytope // enclosing all vertices ... const p1 = charges[i].position; const p2 = charges[j].position; @@ -83,7 +118,7 @@ function find_faces() { // If L intersects the plane, q1 and q2 are on // opposite sides of the plane generated by p1 p2 p3, // so p1 p2 p3 can't be a face. If we want the - // polyhedron to be convex. Which we do. + // polytope to be convex. Which we do. // // A point k is on the plane generated by p1 p2 p3 iff // dot(k - p1, normal) = 0. Let n := normal. @@ -118,8 +153,8 @@ function draw_faces(radius) { push(); strokeWeight(2); stroke(0x00); + fill(0xbf, 0x7f); for ([p1, p2, p3] of faces) { - fill(0xbf, 0x7f); beginShape(TRIANGLES); vertex(p1.x * radius, p1.y * radius, p1.z * radius); vertex(p2.x * radius, p2.y * radius, p2.z * radius); @@ -155,13 +190,7 @@ function make_charges(n) { 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), - ); + position = p5.Vector.random3D(); } charges.push({ position: position, @@ -255,15 +284,36 @@ function make_lights() { function keyPressed() { if (key == ' ') { - physics = !physics; + toggle_physics(); } else if (key == 'd') { - surface = (surface + 1) % 3; + set_surface((surface + 1) % 3); } else if (key == 'f') { - skeleton = !skeleton; + toggle_skeleton(); } else if (key == 'g') { - polyhedron = !polyhedron; + toggle_polytope(); } else if (key >= '0' && key <= '9') { make_charges(int(key)); faces = []; } } + +function toggle_physics() { + physics = !physics; + checkbox_physics.checked = physics; +} + +function set_surface(value) { + surface = value; + for (let button of buttons_surface) button.disabled = false; + buttons_surface[value].disabled = true; +} + +function toggle_skeleton() { + skeleton = !skeleton; + checkbox_skeleton.checked = skeleton; +} + +function toggle_polytope() { + polytope = !polytope; + checkbox_polytope.checked = polytope; +} diff --git a/thomson-problem.js b/thomson-problem.js index 0cbbdaa..8b8245c 100644 --- a/thomson-problem.js +++ b/thomson-problem.js @@ -11,11 +11,11 @@ function move_charges(charges) { let acceleration_mag = 1 / displacement.mag() * 0.001; let ai; if (acceleration_mag === Infinity) { - ai = createVector(random(-1, 1), random(-1, 1), random(-1, 1)); + ai = p5.Vector.random3D(); } else { - ai = displacement.copy(); + ai = displacement.copy().normalize(); } - ai = ai.normalize().mult(acceleration_mag); + ai.mult(acceleration_mag); let aj = p5.Vector.mult(ai, -1); project_onto_plane(ai, charges[i].position); project_onto_plane(aj, charges[j].position);