Skip to content

Commit

Permalink
feat: add Arrow3D, VectorField3D
Browse files Browse the repository at this point in the history
  • Loading branch information
SeiyaCooper committed Jun 22, 2024
1 parent 53e6761 commit f3ad26d
Show file tree
Hide file tree
Showing 13 changed files with 490 additions and 261 deletions.
1 change: 1 addition & 0 deletions site/components/TopBar.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const examples = [
"Magnetic Focus",
"Orbit Animation",
"Axes2D",
"Animation Set",
];
---

Expand Down
31 changes: 31 additions & 0 deletions site/pages/gallery/Animation Set.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
import Example from "../../layouts/Example.astro";
---

<Example title="Animation Set">
<script>
import * as MRAPH from "../../../src/mraph.js";

const layer = new MRAPH.Layer().appendTo(document.body);

const vf3d = new MRAPH.VectorField3D();
layer.add(vf3d);
vf3d.colorFunc = (x, y, z, length) => {
const hue = (length - 0.1) * 4 - 1.35;
return MRAPH.MathFunc.lerpArray(new MRAPH.Color(0, 0.9, 1), new MRAPH.Color(1, 0.1, 0.1), hue);
};

vf3d.animate.transformTo(new MRAPH.Point(0, 0), { runTime: 1.5 });
vf3d.animate.transformTo(new MRAPH.VectorField2D(), { runTime: 1.5 });
vf3d.animate.transformTo(new MRAPH.Axes2D(), { runTime: 1.5 });
vf3d.animate.rotateZ(Math.PI * 4, { runTime: 3 });
vf3d.animate.moveTo(MRAPH.VECTORS.UP);
vf3d.animate.moveTo(MRAPH.VECTORS.DOWN, { curve: MRAPH.Timeline.easeOutBounce });
vf3d.animate.moveTo(MRAPH.VECTORS.ORIGIN);
layer.scene.animate.rotateY(Math.PI / 3);
layer.scene.animate.rotateX(Math.PI / 3);
layer.camera.animate.moveTo(new MRAPH.Vector(0, 0, -5));

layer.play();
</script>
</Example>
12 changes: 7 additions & 5 deletions src/core/Camera.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import Matrix from "../math/Matrix.js";
import Vector from "../math/Vector.js";
import Node from "./Node.js";

export default class Camera {
export default class Camera extends Node {
center = new Vector(0, 0, -10);
rotation = new Vector(0, 0, 0);
up = new Vector(0, 1, 0);
projectionMat = Matrix.identity(4);
viewMat = Matrix.identity(4);

constructor() {
super();
const self = this;
const handler = {
get(obj, prop) {
Expand All @@ -17,7 +19,7 @@ export default class Camera {
set(obj, prop, value) {
obj[prop] = value;
if (+prop <= 2) {
self.update();
self.updateMatrix();
}
return true;
},
Expand All @@ -29,7 +31,7 @@ export default class Camera {
this.rotation = rotProxy;
}

update() {
updateMatrix() {
const center = this.center;
const rotation = this.rotation;
this.viewMat = Matrix.translation(...center)
Expand All @@ -51,7 +53,7 @@ export default class Camera {
);
this.near = near;
this.far = far;
this.update();
this.updateMatrix();
return this;
}

Expand All @@ -65,7 +67,7 @@ export default class Camera {
this.projectionMat = mat;
this.near = near;
this.far = far;
this.update();
this.updateMatrix();
return this;
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/Layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ export default class Layer {
this.renderer = new rendererClass(this.canvas, contextConfig);
this.clearCanvas(COLORS.GRAY_E);
this.defaultMaterial.colorMode = "vertex";
this.scene.layer = this;
this.camera.layer = this;
}

/**
Expand Down
106 changes: 106 additions & 0 deletions src/core/Node.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,110 @@ export default class Node {
}
return this;
}

/**
* A collection of animation methods
*/
animate = {
/**
* Shifts this mobject to a new place
* @param {Vector | number[]} pos
* @param {Object} config
*/
moveTo: ((pos, { runTime = 1, curve } = {}) => {
let start;
const config = {
start: () => {
start = this.center;
},
update: (p) => {
this.center = start.lerp(pos, p);
this.updateMatrix();
},
curve,
};
this.layer.timeline.addFollow(runTime, config);
}).bind(this),

/**
* Scales this mobject by a factor
* @param {Vector | number[]} factor
* @param {Object} config
*/
scaleTo: ((factor, { runTime = 1, curve } = {}) => {
let start, to;
const config = {
start: () => {
start = this.scale;
to = start.elMult(factor);
},
update: (p) => {
this.scale = start.lerp(to, p);
this.updateMatrix();
},
curve,
};
this.layer.timeline.addFollow(runTime, config);
}).bind(this),

/**
* Rotates this mobject around x axis
* @param {Vector | number[]} factor
* @param {Object} config
*/
rotateX: ((angle, { runTime = 1, curve } = {}) => {
let start;
const config = {
start: () => {
start = this.rotation.x;
},
update: (p) => {
this.rotation.x = start + p * angle;
this.updateMatrix();
},
curve,
};
this.layer.timeline.addFollow(runTime, config);
}).bind(this),

/**
* Rotates this mobject around y axis
* @param {Vector | number[]} factor
* @param {Object} config
*/
rotateY: ((angle, { runTime = 1, curve } = {}) => {
let start;
const config = {
start: () => {
start = this.rotation.y;
},
update: (p) => {
this.rotation.y = start + p * angle;
this.updateMatrix();
},
curve,
};
this.layer.timeline.addFollow(runTime, config);
}).bind(this),

/**
* Rotates this mobject around z axis
* @param {Vector | number[]} factor
* @param {Object} config
*/
rotateZ: ((angle, { runTime = 1, curve } = {}) => {
let start;
const config = {
start: () => {
start = this.rotation.z;
},
update: (p) => {
this.rotation.z = start + p * angle;
this.updateMatrix();
},
curve,
};
this.layer.timeline.addFollow(runTime, config);
}).bind(this),
};
}
17 changes: 16 additions & 1 deletion src/math/Vector.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default class Vector extends Array {
}

/**
* Project to another vector
* Projects this vector to another vector
* @param {Vector} vec
* @returns {Vector}
*/
Expand Down Expand Up @@ -167,6 +167,21 @@ export default class Vector extends Array {
return this;
}

/**
* resize this vector with a number to fill
* @param {number} row
* @param {number} [n=0]
*/
resize(row, n = 0) {
const out = Vector.fromRow(row, n);

for (let j = 0; j < out.length; j++) {
out[j] = this[j] ?? n;
}

return out;
}

/**
* print this vertor on the console
*/
Expand Down
2 changes: 1 addition & 1 deletion src/mobjects/2D/Line.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Matrix from "../../math/Matrix.js";
export default class Line extends Mobject2D {
strokeWidth = 0.05;
strokeColor = new Color(1, 1, 1, 1);
indices = { data: [0, 1, 3, 2, 0, 3] };
tips = [];
tipWidth = 0.06;
tipLength = 0.12;
Expand All @@ -20,6 +19,7 @@ export default class Line extends Mobject2D {
super();
this.start = start;
this.end = end;
this.setIndex([0, 1, 3, 2, 0, 3]);
}

update() {
Expand Down
14 changes: 1 addition & 13 deletions src/mobjects/2D/VectorField2D.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ export default class VectorField2D extends Mobject {
const yRange = this.yRange;
for (let x = xRange[0]; x <= xRange[1]; x += xRange[2]) {
for (let y = yRange[0]; y <= yRange[1]; y += yRange[2]) {
const arrow = new Arrow(
new Point(new Vector(x, y, 0).add(this.center)),
new Vector(...func(x, y, this.center[2]))
);
const arrow = new Arrow(new Point(new Vector(x, y, 0)), new Vector(...func(x, y, this.center[2])));
const length = this.lengthFunc(arrow.length);
arrow.length = length;
arrow.setColor(this.colorFunc(x, y, length));
Expand All @@ -54,13 +51,4 @@ export default class VectorField2D extends Mobject {
setColor(color) {
this.colorFunc = () => color;
}

set center(center) {
this._center = center;
this.update();
}

get center() {
return this._center;
}
}
61 changes: 61 additions & 0 deletions src/mobjects/3D/Arrow3D.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Mobject3D from "./Mobject3D.js";
import Point3D from "./Point3D.js";
import Cylinder from "../../geometry/Cylinder.js";
import Matrix from "../../math/Matrix.js";
import Vector from "../../math/Vector.js";
import * as VECTORS from "../../constants/vectors.js";
import * as COLORS from "../../constants/colors.js";

export default class Arrow3D extends Mobject3D {
tipWidth = 0.06;
tipLength = 0.12;
strokeWidth = 0.05;

constructor(start = new Point3D(-1, 0), end = new Point3D(1, 0)) {
super();
this.start = start;
this.end = Vector.isInstance(end) ? new Point3D(start.center.add(end)) : end;
this.material.colorMode = "single";
this.setColor(COLORS.SEIYA_PINK);
}

update() {
const r = this.strokeWidth / 2;
const cylinder = new Cylinder({
radii: [r, r, this.tipWidth, 0],
heights: [this.length - this.tipLength + 0.05, 0, this.tipLength],
phiSegments: 8,
});

cylinder.update();
this.mergeAttributes(cylinder, "position", "normal");
this.setIndex(this.getAttributeVal("position").length / 3);

const vector = this.vector;
const UP = VECTORS.UP;
const pivot = vector.cross(UP);
const angle = Math.acos(vector.project(UP).y / vector.norm);

const transMatrix = Matrix.rotateOn(pivot, angle, 4).trans(Matrix.translation(...this.start.center));

this.matrixTransform(transMatrix, 4);
}

set vector(vec) {
this.end = new Point3D(this.start.center.add(vec));
}

get vector() {
return this.end.center.minus(this.start.center);
}

set length(val) {
const vec = this.vector;
vec.norm = val;
this.vector = vec;
}

get length() {
return this.vector.norm;
}
}
Loading

0 comments on commit f3ad26d

Please sign in to comment.