From 34e1de68f1913d0c737aa2589b4981c78c556c3a Mon Sep 17 00:00:00 2001
From: root <>
Date: Sat, 26 Apr 2025 04:08:10 +0000
Subject: [PATCH] hide sphere; euler's forumla trick; cache faces

---
 sketch.js | 68 ++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 45 insertions(+), 23 deletions(-)

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