AABB tree for atoms
This commit is contained in:
parent
40685415a8
commit
9247568f34
140
scattering.js
140
scattering.js
|
@ -44,20 +44,37 @@ function veryClose(x, y) {
|
|||
}
|
||||
|
||||
/*****************************************
|
||||
* Parameters
|
||||
* Object Classes
|
||||
****************************************/
|
||||
|
||||
let width = 800;
|
||||
let height = 600;
|
||||
class Rect {
|
||||
constructor(args) {
|
||||
if ('r1' in args) {
|
||||
this.x_0 = Math.min(args.r1.x_0, args.r2.x_0);
|
||||
this.y_0 = Math.min(args.r1.y_0, args.r2.y_0);
|
||||
this.x_1 = Math.max(args.r1.x_1, args.r2.x_1);
|
||||
this.y_1 = Math.max(args.r1.y_1, args.r2.y_1);
|
||||
} else {
|
||||
this.x_0 = args.x_0;
|
||||
this.x_1 = args.x_1;
|
||||
this.y_0 = args.y_0;
|
||||
this.y_1 = args.y_1;
|
||||
}
|
||||
}
|
||||
|
||||
area() {
|
||||
return (this.x_1 - this.x_0)*(this.y_1 - this.y_0);
|
||||
}
|
||||
}
|
||||
|
||||
let windowRect = new Rect({x_0: 0, x_1: 800, y_0: 0, y_1: 600})
|
||||
let width = windowRect.x_1;
|
||||
let height = windowRect.y_1;
|
||||
|
||||
/* Infinite lines are drawn with length = 2*longestDiag which will always
|
||||
* cross the entire screen. */
|
||||
let longestDiag = distance(width, height);
|
||||
|
||||
/*****************************************
|
||||
* Object Classes
|
||||
****************************************/
|
||||
|
||||
/* Basic infinite line class, useful for physics simulation */
|
||||
class InfiniteLine {
|
||||
constructor(x_0, y_0, angle) {
|
||||
|
@ -66,8 +83,7 @@ class InfiniteLine {
|
|||
this.angle = angle;
|
||||
}
|
||||
|
||||
/* If the line is outside of the canvas */
|
||||
cullable() {
|
||||
insideOfRect(r) {
|
||||
// implicit equation of a line:
|
||||
// (y - y_0)cos(theta) - (x - x_0)*sin(theta) = 0
|
||||
// Evaluate the LHS for two points of a line segment. If the
|
||||
|
@ -79,15 +95,20 @@ class InfiniteLine {
|
|||
const upper_left = f(0,0);
|
||||
const upper_right = f(width,0);
|
||||
if (sign(upper_left) != sign(upper_right))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
const lower_left = f(0,height);
|
||||
if (sign(lower_left) != sign(upper_left))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
const lower_right = f(width,height);
|
||||
return sign(lower_right) == sign(lower_left)
|
||||
&& sign(lower_right) == sign(upper_right);
|
||||
return sign(lower_right) != sign(lower_left)
|
||||
|| sign(lower_right) != sign(upper_right);
|
||||
}
|
||||
|
||||
/* If the line is outside of the canvas */
|
||||
cullable() {
|
||||
return !this.insideOfRect(windowRect);
|
||||
}
|
||||
|
||||
// Returns true if drawn.
|
||||
|
@ -95,6 +116,7 @@ class InfiniteLine {
|
|||
if (this.cullable())
|
||||
return false;
|
||||
|
||||
fill(color(0,0,0));
|
||||
translate(this.x_0, this.y_0);
|
||||
rotate(this.angle);
|
||||
strokeWeight(2);
|
||||
|
@ -116,6 +138,7 @@ class PlaneWave extends InfiniteLine {
|
|||
}
|
||||
|
||||
drawArrow() {
|
||||
fill(color(0,0,0));
|
||||
translate(this.x_0, this.y_0);
|
||||
rotate(this.angle);
|
||||
triangle(-5, 0, 0, 15, 5, 0);
|
||||
|
@ -128,14 +151,91 @@ class Atom {
|
|||
constructor(x,y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.boundRect = new Rect({
|
||||
x_0: x - Atom.radius,
|
||||
x_1: x + Atom.radius,
|
||||
y_0: y - Atom.radius,
|
||||
y_1: y + Atom.radius
|
||||
});
|
||||
}
|
||||
|
||||
updatePos(x,y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.boundRect.x_0 = x - Atom.radius;
|
||||
this.boundRect.x_1 = x + Atom.radius;
|
||||
this.boundRect.y_0 = y - Atom.radius;
|
||||
this.boundRect.y_1 = y + Atom.radius;
|
||||
}
|
||||
|
||||
draw() {
|
||||
color(255,0,0);
|
||||
fill(color(255,0,0));
|
||||
circle(this.x, this.y, Atom.radius);
|
||||
}
|
||||
}
|
||||
|
||||
class AABBNode {
|
||||
constructor(args) {
|
||||
this.leftNode = null;
|
||||
this.rightNode = null;
|
||||
if (args !== undefined) {
|
||||
this.obj = args.obj;
|
||||
this.rect = args.rect;
|
||||
} else {
|
||||
this.obj = null;
|
||||
this.rect = null;
|
||||
}
|
||||
}
|
||||
|
||||
add(obj, rect) {
|
||||
// Empty node (the root). Add object.
|
||||
if (this.obj === null && this.leftNode === null && this.rightNode === null) {
|
||||
this.obj = obj;
|
||||
this.rect = rect;
|
||||
} else if (this.obj !== null) {
|
||||
// Leaf node. Split node.
|
||||
this.leftNode = new AABBNode({obj: this.obj, rect: this.rect});
|
||||
this.rightNode = new AABBNode({obj: obj, rect: rect});
|
||||
this.rect = new Rect({r1: this.rect, r2: rect});
|
||||
this.obj = null;
|
||||
} else {
|
||||
// General case with two children.
|
||||
const newLeftRect = new Rect({r1: this.leftNode.rect, r2: rect});
|
||||
const newRightRect = new Rect({r1: this.rightNode.rect, r2: rect});
|
||||
|
||||
if (newLeftRect.area() < newRightRect.area()) {
|
||||
this.leftNode.add(obj, rect);
|
||||
} else {
|
||||
this.rightNode.add(obj, rect);
|
||||
}
|
||||
|
||||
this.rect = new Rect({r1 : this.leftNode.rect, r2 : this.rightNode.rect})
|
||||
}
|
||||
}
|
||||
|
||||
draw(n) {
|
||||
if (this.rect !== null) {
|
||||
fill(color(0, n, 0, 100));
|
||||
quad(this.rect.x_0, this.rect.y_0,
|
||||
this.rect.x_0, this.rect.y_1,
|
||||
this.rect.x_1, this.rect.y_1,
|
||||
this.rect.x_1, this.rect.y_0);
|
||||
}
|
||||
|
||||
if (this.obj !== null) {
|
||||
this.obj.draw();
|
||||
}
|
||||
|
||||
if (this.leftNode) {
|
||||
this.leftNode.draw(n+10);
|
||||
}
|
||||
|
||||
if (this.rightNode) {
|
||||
this.rightNode.draw(n+10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Mouse handler classes.
|
||||
*
|
||||
|
@ -204,7 +304,6 @@ class AtomMouseHandler extends MouseHandler {
|
|||
} else {
|
||||
const oldAtom = this.currentAtom;
|
||||
this.currentAtom = null;
|
||||
console.log('abcd');
|
||||
return this.stateTo('base', oldAtom);
|
||||
}
|
||||
}
|
||||
|
@ -218,8 +317,7 @@ class AtomMouseHandler extends MouseHandler {
|
|||
}
|
||||
|
||||
handleMouseMove() {
|
||||
this.currentAtom.x = mouseX;
|
||||
this.currentAtom.y = mouseY;
|
||||
this.currentAtom.updatePos(mouseX, mouseY);
|
||||
this.currentAtom.draw();
|
||||
return null;
|
||||
}
|
||||
|
@ -277,7 +375,7 @@ class SimulationMouseHandler extends MouseHandler {
|
|||
class Simulation {
|
||||
constructor() {
|
||||
this.planeWaves = [];
|
||||
this.atoms = [];
|
||||
this.atomTree = new AABBNode();
|
||||
this.mouseHandler = new SimulationMouseHandler();
|
||||
}
|
||||
|
||||
|
@ -286,7 +384,7 @@ class Simulation {
|
|||
if (handleRet instanceof PlaneWave) {
|
||||
this.planeWaves.push(handleRet);
|
||||
} else if (handleRet instanceof Atom) {
|
||||
this.atoms.push(handleRet);
|
||||
this.atomTree.add(handleRet, handleRet.boundRect);
|
||||
}
|
||||
|
||||
for (let ind = 0; ind < this.planeWaves.length; ind++) {
|
||||
|
@ -296,9 +394,7 @@ class Simulation {
|
|||
}
|
||||
}
|
||||
|
||||
for (let ind = 0; ind < this.atoms.length; ind++) {
|
||||
this.atoms[ind].draw();
|
||||
}
|
||||
this.atomTree.draw(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue