hide sphere; euler's forumla trick; cache faces

This commit is contained in:
root 2025-04-26 04:08:10 +00:00
parent cec27160f4
commit 34e1de68f1

View file

@ -2,13 +2,18 @@ let camera;
let red; let red;
let charges = []; let charges = [];
let faces = [];
let sphere_radius = 200; let sphere_radius = 200;
const SURFACE_NONE = 0;
const SURFACE_CIRCLES = 1;
const SURFACE_EARTH = 2;
let surface = SURFACE_CIRCLES;
let physics = false; let physics = false;
let earth = false;
let skeleton = false; let skeleton = false;
let planes = false; let polyhedron = false;
function preload() { function preload() {
@ -16,11 +21,15 @@ function preload() {
} }
function setup() { function setup() {
createCanvas(600, 600, WEBGL); createCanvas(windowWidth, windowHeight, WEBGL);
camera = createCamera(); camera = createCamera();
red = color(0xbf, 0x00, 0x00); red = color(0xbf, 0x00, 0x00);
} }
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}
function draw() { function draw() {
orbitControl(); orbitControl();
background(50); background(50);
@ -29,9 +38,12 @@ function draw() {
if (physics) move_charges(charges); if (physics) move_charges(charges);
draw_charges(sphere_radius); draw_charges(sphere_radius);
draw_sphere(sphere_radius, 25);
if (skeleton) draw_skeleton(sphere_radius); if (skeleton) draw_skeleton(sphere_radius);
if (planes) draw_planes(sphere_radius); if (polyhedron) {
if (physics || faces.length === 0) find_faces();
draw_faces(sphere_radius);
}
draw_sphere(sphere_radius, 25);
} }
function face_dist_sq([v1, v2, v3]) { function face_dist_sq([v1, v2, v3]) {
@ -39,8 +51,8 @@ function face_dist_sq([v1, v2, v3]) {
return createVector(camera.eyeX, camera.eyeY, camera.eyeZ).sub(center).magSq(); return createVector(camera.eyeX, camera.eyeY, camera.eyeZ).sub(center).magSq();
}; };
function draw_planes(radius) { function find_faces() {
let faces = []; faces = [];
for (let i = 2; i < charges.length; i += 1) { for (let i = 2; i < charges.length; i += 1) {
for (let j = 1; j < i; j += 1) { for (let j = 1; j < i; j += 1) {
for (let k = 0; k < j; k += 1) { for (let k = 0; k < j; k += 1) {
@ -53,6 +65,7 @@ function draw_planes(radius) {
// ... by checking if the other vertices are on the same // ... by checking if the other vertices are on the same
// side of the plane generated by p1 p2 p3 // side of the plane generated by p1 p2 p3
let plane_separates_vertices = false; let plane_separates_vertices = false;
let euler_formula = false;
for (let r = 1; r < charges.length; r += 1) { for (let r = 1; r < charges.length; r += 1) {
for (let s = 0; s < r; s += 1) { for (let s = 0; s < r; s += 1) {
if ( if (
@ -85,30 +98,32 @@ function draw_planes(radius) {
); );
plane_separates_vertices ||= t >= 0 && t <= 1; plane_separates_vertices ||= t >= 0 && t <= 1;
if (plane_separates_vertices) break; if (plane_separates_vertices) break;
euler_formula ||= charges.length * 2 - faces.length == 4;
if (euler_formula) break;
} }
if (plane_separates_vertices) break; if (plane_separates_vertices || euler_formula) break;
} }
if (euler_formula) return;
if (!plane_separates_vertices) { if (!plane_separates_vertices) {
faces.push([ faces.push([p1, p2, p3]);
p5.Vector.mult(p1, radius),
p5.Vector.mult(p2, radius),
p5.Vector.mult(p3, radius),
]);
} }
} }
} }
} }
}
function draw_faces(radius) {
// fix OpenGL stacking alpha behaviour // fix OpenGL stacking alpha behaviour
faces.sort((a, b) => face_dist_sq(b) - face_dist_sq(a)); faces.sort((a, b) => face_dist_sq(b) - face_dist_sq(a));
push(); push();
strokeWeight(2); strokeWeight(2);
stroke(0x00); stroke(0x00);
for ([v1, v2, v3] of faces) { for ([p1, p2, p3] of faces) {
fill(0xbf, 0x7f); fill(0xbf, 0x7f);
beginShape(TRIANGLES); beginShape(TRIANGLES);
vertex(v1.x, v1.y, v1.z); vertex(p1.x * radius, p1.y * radius, p1.z * radius);
vertex(v2.x, v2.y, v2.z); vertex(p2.x * radius, p2.y * radius, p2.z * radius);
vertex(v3.x, v3.y, v3.z); vertex(p3.x * radius, p3.y * radius, p3.z * radius);
endShape(); endShape();
} }
pop(); pop();
@ -176,11 +191,14 @@ function draw_sphere(radius, n_axis_circles) {
stroke(0x3f); stroke(0x3f);
noFill(); noFill();
if (surface === SURFACE_NONE) n_axis_circles = 0;
else if (surface === SURFACE_EARTH) n_axis_circles = 2;
push(); push();
rotateX(TAU / 4); rotateX(TAU / 4);
draw_circles( draw_circles(
radius, radius,
earth ? 2 : n_axis_circles, n_axis_circles,
color(0x00, 0x9f, 0xff), color(0x00, 0x9f, 0xff),
color(0xff, 0x9f, 0x00), color(0xff, 0x9f, 0x00),
); );
@ -189,13 +207,13 @@ function draw_sphere(radius, n_axis_circles) {
rotateY(TAU / 4); rotateY(TAU / 4);
draw_circles( draw_circles(
radius, radius,
earth ? 2 : n_axis_circles, n_axis_circles,
color(0xff, 0x00, 0xff), color(0xff, 0x00, 0xff),
color(0x00, 0xff, 0x00), color(0x00, 0xff, 0x00),
); );
pop(); pop();
if (earth) { if (surface === SURFACE_EARTH) {
noStroke(); noStroke();
noFill(); noFill();
tint(0xff, 0x9f); tint(0xff, 0x9f);
@ -239,16 +257,20 @@ function keyPressed() {
if (key == ' ') { if (key == ' ') {
physics = !physics; physics = !physics;
} else if (key == 'd') { } else if (key == 'd') {
earth = !earth; surface = (surface + 1) % 3;
} else if (key == 'f') { } else if (key == 'f') {
skeleton = !skeleton; skeleton = !skeleton;
} else if (key == 'g') { } else if (key == 'g') {
planes = !planes; polyhedron = !polyhedron;
} else if (key >= '0' && key <= '9') { } else if (key >= '0' && key <= '9') {
make_charges(int(key)); make_charges(Math.pow(int(key), 2));
faces = [];
} }
} }
// TODO draw faces // TODO draw faces
// algorithm: choose 3 vertices until 2-partition of other vertices has one empty set // 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 // done when V - E + F = 2. V is known. count E and F while creating faces
// when the graph is finished: E = F * 3 / 2
// V - E + F = V - F * 3 / 2 + F = V - F / 2
// V * 2 - F = 4