Skip to content

Commit 1280e8d

Browse files
committed
Created Repo
1 parent 0459daa commit 1280e8d

File tree

8 files changed

+264
-0
lines changed

8 files changed

+264
-0
lines changed

Complex.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
class Complex {
2+
3+
constructor(x, y) {
4+
this.x = x;
5+
this.y = y;
6+
}
7+
8+
add(comp) {
9+
this.x += comp.x;
10+
this.y += comp.y;
11+
return new Complex(this.x, this.y);
12+
}
13+
14+
scale(scale) {
15+
this.x *= scale;
16+
this.y *= scale;
17+
return new Complex(this.x, this.y);
18+
}
19+
20+
cexp() {
21+
return new Complex(exp(this.x) * cos(this.y), exp(this.x) * sin(this.y));
22+
}
23+
24+
mul(b) {
25+
const cache = this.x * b.x - this.y * b.y;
26+
this.y = this.x * b.y + this.y * b.x;
27+
this.x = cache;
28+
return new Complex(this.x, this.y);
29+
}
30+
31+
abs() {
32+
return dist(0, 0, this.x, this.y);
33+
}
34+
35+
print() {
36+
print(this.x + " + " + this.y + "i");
37+
}
38+
39+
render() {
40+
stroke(255);
41+
strokeWeight(3);
42+
point(this.x * SCALE, this.y * SCALE);
43+
}
44+
}

DFT_Machine.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// ################# SETTINGS #################
2+
let VELO = 0.01,
3+
SCALE = 30.0,
4+
drawData = false,
5+
customMode = false;
6+
// ################# SETTINGS #################
7+
8+
let vertices = [];
9+
let renderer;
10+
let font;
11+
12+
function preload() {
13+
font = loadFont("Quicksand.ttf");
14+
}
15+
16+
function setup() {
17+
createCanvas(800, 800);
18+
frameRate(35);
19+
20+
// Render fourier text
21+
const points = font.textToPoints("Fourier", -width/2 + 50, -height/2 + 420, 192, {
22+
sampleFactor: 0.6
23+
});
24+
vertices = points.map(p => new Complex(p.x / SCALE, p.y / SCALE));
25+
//print("Vertices: ", vertices.length);
26+
27+
// Calc DFT and initiate animation
28+
renderer = new Renderer(DFT(), vertices);
29+
renderer.buildEpicycles(vertices.length);
30+
vertices = [];
31+
}
32+
33+
function draw() {
34+
background(51);
35+
translate(width / 2, height / 2);
36+
37+
if (renderer) {
38+
renderer.render();
39+
}
40+
}
41+
42+
function mouseClicked() {
43+
const x = (mouseX - width/2) / SCALE;
44+
const y = (mouseY - height/2) / SCALE;
45+
vertices.push(new Complex(x, y));
46+
47+
renderer = new Renderer(DFT(), vertices);
48+
renderer.buildEpicycles(vertices.length);
49+
if (!customMode) {
50+
VELO = 0.05;
51+
drawData = true;
52+
customMode = true;
53+
}
54+
}
55+
56+
/*
57+
* ###################################################################
58+
* Discrete Fourier Trasformation (DFT) Algorithm
59+
* 1/2𝜋∫ 𝑓(𝑡)𝑒⁻ⁿⁱᵗ𝑑𝑡=𝑐ₙ
60+
*/
61+
function DFT() {
62+
let func = [];
63+
for (const n in vertices) {
64+
let sigma = new Complex(0, 0);
65+
for (const t in vertices) {
66+
let unitVector = new Complex(0, 1);
67+
unitVector = unitVector.scale(-2 * PI * (n-floor(vertices.length/2)) * (t/vertices.length));
68+
unitVector = unitVector.cexp();
69+
unitVector = unitVector.mul(vertices[t]);
70+
unitVector = unitVector.scale(1/vertices.length);
71+
sigma = sigma.add(unitVector);
72+
}
73+
func.push(sigma);
74+
}
75+
return func;
76+
}
77+
/*
78+
* ##############################################################
79+
*/

Epicycle.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
2+
3+
/*
4+
* A circle with a planet that has a position and a constant velocity
5+
*/
6+
class Epicycle {
7+
8+
constructor(position, initialDirectionVector, radialVelocity) {
9+
this.position = position;
10+
this.radialVelocity = radialVelocity;
11+
this.size = initialDirectionVector.abs();
12+
this.angle = atan2(initialDirectionVector.y, initialDirectionVector.x);
13+
}
14+
15+
getPlanetPosition() {
16+
return new Complex(
17+
this.position.x + this.size * cos(this.angle),
18+
this.position.y + this.size * sin(this.angle)
19+
);
20+
}
21+
22+
update() {
23+
this.angle += this.radialVelocity * VELO;
24+
}
25+
26+
draw(position) {
27+
this.position = position;
28+
29+
// Draw vector
30+
stroke(200);
31+
strokeWeight(1);
32+
line(this.position.x * SCALE,
33+
this.position.y * SCALE,
34+
(this.position.x + this.size * cos(this.angle)) * SCALE,
35+
(this.position.y + this.size * sin(this.angle)) * SCALE
36+
);
37+
38+
// Draw circle
39+
stroke(80);
40+
noFill();
41+
const ax = this.position.x * SCALE;
42+
const ay = this.position.y * SCALE;
43+
circle(ax, ay, this.size * 2 * SCALE);
44+
}
45+
}

Quicksand.ttf

75.2 KB
Binary file not shown.

Renderer.js

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
class Renderer {
2+
3+
constructor(dftFunction, vertices) {
4+
this.dftFunction = dftFunction;
5+
this.vertices = vertices;
6+
this.path = [];
7+
}
8+
9+
10+
/*
11+
* Builds all epicycle data based on the dft results
12+
*/
13+
buildEpicycles() {
14+
this.epicycles = [];
15+
const position = new Complex(0, 0);
16+
17+
for (let i=0; i<this.vertices.length; i++) {
18+
const initialDirectionVector = this.dftFunction[i]; // y-Axis (offset/position)
19+
const radialVelocity = i - floor(this.vertices.length / 2); // x-Axis (frequency/velocity)
20+
const epicycle = new Epicycle(position, initialDirectionVector, radialVelocity);
21+
22+
this.epicycles.push(epicycle);
23+
position.add(initialDirectionVector);
24+
}
25+
26+
this.epicycles = this.epicycles.sort((a, b) => b.size - a.size);
27+
}
28+
29+
30+
/*
31+
* Renders all epicycles
32+
*/
33+
render() {
34+
35+
// Draw epicycles
36+
let currentCoords = new Complex(0, 0);
37+
for (const epicycle of this.epicycles) {
38+
epicycle.update();
39+
epicycle.draw(currentCoords);
40+
currentCoords = epicycle.getPlanetPosition();
41+
}
42+
43+
// Draw vertex history (result line of epicycle drawing)
44+
const lastPlanet = this.epicycles[this.epicycles.length-1];
45+
let previousPathPoint = this.path[0];
46+
this.path.push(lastPlanet.getPlanetPosition());
47+
if (this.path.length > 1) {
48+
let i=128;
49+
for (const vertex of this.path) {
50+
colorMode(HSB, 255);
51+
stroke(i%255, 255, 255);
52+
strokeWeight(2);
53+
if (customMode || dist(vertex.x, vertex.y, previousPathPoint.x, previousPathPoint.y) < 0.8)
54+
line(vertex.x * SCALE, vertex.y * SCALE, previousPathPoint.x * SCALE, previousPathPoint.y * SCALE);
55+
previousPathPoint = vertex;
56+
i+=0.2;
57+
}
58+
}
59+
60+
// Draw vertices (user inputs)
61+
if (drawData) {
62+
colorMode(RGB, 255);
63+
for (const vertex of this.vertices) {
64+
stroke(255);
65+
strokeWeight(4);
66+
point(vertex.x * SCALE, vertex.y * SCALE);
67+
}
68+
}
69+
}
70+
}

index.html

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<html>
2+
<head>
3+
<meta charset="UTF-8">
4+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
5+
6+
<!-- PLEASE NO CHANGES BELOW THIS LINE (UNTIL I SAY SO) -->
7+
<script language="javascript" type="text/javascript" src="libraries/p5.min.js"></script>
8+
<script language="javascript" type="text/javascript" src="Complex.js"></script>
9+
<script language="javascript" type="text/javascript" src="Epicycle.js"></script>
10+
<script language="javascript" type="text/javascript" src="Renderer.js"></script>
11+
<script language="javascript" type="text/javascript" src="DFT_Machine.js"></script>
12+
<!-- OK, YOU CAN MAKE CHANGES BELOW THIS LINE AGAIN -->
13+
14+
<!-- This line removes any default padding and style.
15+
You might only need one of these values set. -->
16+
<style> body { padding: 0; margin: 0; } </style>
17+
</head>
18+
19+
<body>
20+
</body>
21+
</html>

libraries/p5.min.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sketch.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mode=p5.js
2+
mode.id=processing.mode.p5js.p5jsMode

0 commit comments

Comments
 (0)