convex polyhedron
This commit is contained in:
parent
838eae2cbf
commit
cec27160f4
1 changed files with 83 additions and 66 deletions
143
sketch.js
143
sketch.js
|
@ -1,3 +1,6 @@
|
||||||
|
let camera;
|
||||||
|
let red;
|
||||||
|
|
||||||
let charges = [];
|
let charges = [];
|
||||||
|
|
||||||
let sphere_radius = 200;
|
let sphere_radius = 200;
|
||||||
|
@ -7,8 +10,6 @@ let earth = false;
|
||||||
let skeleton = false;
|
let skeleton = false;
|
||||||
let planes = false;
|
let planes = false;
|
||||||
|
|
||||||
let red;
|
|
||||||
let yellow;
|
|
||||||
|
|
||||||
function preload() {
|
function preload() {
|
||||||
earth_image = loadImage("atlas1.jpg");
|
earth_image = loadImage("atlas1.jpg");
|
||||||
|
@ -16,8 +17,8 @@ function preload() {
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
createCanvas(600, 600, WEBGL);
|
createCanvas(600, 600, WEBGL);
|
||||||
|
camera = createCamera();
|
||||||
red = color(0xbf, 0x00, 0x00);
|
red = color(0xbf, 0x00, 0x00);
|
||||||
yellow = color(0xff, 0xff, 0x00);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw() {
|
function draw() {
|
||||||
|
@ -25,76 +26,92 @@ function draw() {
|
||||||
background(50);
|
background(50);
|
||||||
|
|
||||||
make_lights();
|
make_lights();
|
||||||
if (physics) {
|
if (physics) move_charges(charges);
|
||||||
move_charges(charges);
|
|
||||||
}
|
draw_charges(sphere_radius);
|
||||||
if (skeleton) {
|
draw_sphere(sphere_radius, 25);
|
||||||
draw_skeleton(sphere_radius);
|
if (skeleton) draw_skeleton(sphere_radius);
|
||||||
|
if (planes) draw_planes(sphere_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (planes) {
|
function face_dist_sq([v1, v2, v3]) {
|
||||||
let p_charge = charges[0];
|
const center = p5.Vector.add(v1, v2).add(v3).mult(1 / 3);
|
||||||
let a_charge = charges[1];
|
return createVector(camera.eyeX, camera.eyeY, camera.eyeZ).sub(center).magSq();
|
||||||
let b_charge = charges[2];
|
};
|
||||||
p_charge.color = yellow;
|
|
||||||
a_charge.color = yellow;
|
function draw_planes(radius) {
|
||||||
b_charge.color = yellow;
|
let faces = [];
|
||||||
let p = p_charge.position;
|
for (let i = 2; i < charges.length; i += 1) {
|
||||||
let a = a_charge.position;
|
for (let j = 1; j < i; j += 1) {
|
||||||
let b = b_charge.position;
|
for (let k = 0; k < j; k += 1) {
|
||||||
let n = p5.Vector.sub(p, a).cross(p5.Vector.sub(p, b));
|
// Check if p1 p2 p3 form a face of the convex polyhedron
|
||||||
n.normalize(); // unnecessary
|
// enclosing all vertices ...
|
||||||
|
const p1 = charges[i].position;
|
||||||
|
const p2 = charges[j].position;
|
||||||
|
const p3 = charges[k].position;
|
||||||
|
const normal = p5.Vector.sub(p2, p1).cross(p5.Vector.sub(p3, p1));
|
||||||
|
// ... by checking if the other vertices are on the same
|
||||||
|
// side of the plane generated by p1 p2 p3
|
||||||
|
let plane_separates_vertices = false;
|
||||||
|
for (let r = 1; r < charges.length; r += 1) {
|
||||||
|
for (let s = 0; s < r; s += 1) {
|
||||||
|
if (
|
||||||
|
r === i || r === j || r === k ||
|
||||||
|
s === i || s === j || s === k
|
||||||
|
) continue;
|
||||||
|
const q1 = charges[r].position;
|
||||||
|
const q2 = charges[s].position;
|
||||||
|
// Let l(t) := q1 + (q2 - q1) * t.
|
||||||
|
// L := { l(t) : 0 <= t <= 1 } is the line segment
|
||||||
|
// between q1 and q2. L intersects the plane
|
||||||
|
// generated by p1 p2 p3 iff l(t) intersects with
|
||||||
|
// the plane for some 0 <= t <= 1.
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// A point k is on the plane generated by p1 p2 p3 iff
|
||||||
|
// dot(k - p1, normal) = 0. Let n := normal.
|
||||||
|
//
|
||||||
|
// dot(l(t) - p1, n) = 0
|
||||||
|
// iff dot(q1 + (q2 - q1) * t - p1, n) = 0
|
||||||
|
// iff dot(q1 - p1, n) + dot(q2 - q2, n) * t = 0
|
||||||
|
// iff t = dot(p1 - q1, n) / dot(q2 - q2, n)
|
||||||
|
const t = (
|
||||||
|
p5.Vector.dot(p5.Vector.sub(p1, q1), normal) /
|
||||||
|
p5.Vector.dot(p5.Vector.sub(q2, q1), normal)
|
||||||
|
);
|
||||||
|
plane_separates_vertices ||= t >= 0 && t <= 1;
|
||||||
|
if (plane_separates_vertices) break;
|
||||||
|
}
|
||||||
|
if (plane_separates_vertices) break;
|
||||||
|
}
|
||||||
|
if (!plane_separates_vertices) {
|
||||||
|
faces.push([
|
||||||
|
p5.Vector.mult(p1, radius),
|
||||||
|
p5.Vector.mult(p2, radius),
|
||||||
|
p5.Vector.mult(p3, radius),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fix OpenGL stacking alpha behaviour
|
||||||
|
faces.sort((a, b) => face_dist_sq(b) - face_dist_sq(a));
|
||||||
push();
|
push();
|
||||||
strokeWeight(5);
|
strokeWeight(2);
|
||||||
stroke(0x7f);
|
|
||||||
line(
|
|
||||||
0, 0, 0,
|
|
||||||
n.x * sphere_radius, n.y * sphere_radius, n.z * sphere_radius,
|
|
||||||
)
|
|
||||||
fill(0xff);
|
|
||||||
strokeWeight(3);
|
|
||||||
stroke(0x00);
|
stroke(0x00);
|
||||||
|
for ([v1, v2, v3] of faces) {
|
||||||
|
fill(0xbf, 0x7f);
|
||||||
beginShape(TRIANGLES);
|
beginShape(TRIANGLES);
|
||||||
const v1 = p5.Vector.mult(p, sphere_radius);
|
|
||||||
const v2 = p5.Vector.mult(a, sphere_radius);
|
|
||||||
const v3 = p5.Vector.mult(b, sphere_radius);
|
|
||||||
vertex(v1.x, v1.y, v1.z);
|
vertex(v1.x, v1.y, v1.z);
|
||||||
vertex(v2.x, v2.y, v2.z);
|
vertex(v2.x, v2.y, v2.z);
|
||||||
vertex(v3.x, v3.y, v3.z);
|
vertex(v3.x, v3.y, v3.z);
|
||||||
endShape();
|
endShape();
|
||||||
|
}
|
||||||
pop();
|
pop();
|
||||||
for (let i = 4; i < charges.length; i += 1) {
|
|
||||||
for (let j = 3; j < i; j += 1) {
|
|
||||||
push();
|
|
||||||
const u = charges[i].position;
|
|
||||||
const v = charges[j].position;
|
|
||||||
const t = p5.Vector.dot(p5.Vector.sub(p, u), n) / p5.Vector.dot(p5.Vector.sub(v, u), n);
|
|
||||||
const intersects_plane = t >= 0 && t <= 1;
|
|
||||||
if (intersects_plane) {
|
|
||||||
stroke(0xff, 0x1f, 0x00);
|
|
||||||
} else {
|
|
||||||
stroke(0x00, 0xff, 0x00);
|
|
||||||
}
|
|
||||||
strokeWeight(3);
|
|
||||||
line(
|
|
||||||
charges[i].position.x * sphere_radius,
|
|
||||||
charges[i].position.y * sphere_radius,
|
|
||||||
charges[i].position.z * sphere_radius,
|
|
||||||
charges[j].position.x * sphere_radius,
|
|
||||||
charges[j].position.y * sphere_radius,
|
|
||||||
charges[j].position.z * sphere_radius,
|
|
||||||
);
|
|
||||||
pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (let charge of charges) {
|
|
||||||
charge.color = red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_charges(sphere_radius);
|
|
||||||
draw_sphere(sphere_radius, 25);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw_skeleton(radius) {
|
function draw_skeleton(radius) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue