Use the arrows to move around, and the plus minus buttons to zoom in and out. Use P to pause and resume the animation, and R to show or hide the real part of the parabola.
A fork of Complex Parabolas 3D by Ofir
xxxxxxxxxx
var complexRes = 40; // How many program pixels there are on each side of the square (for a total of complexRes x complexRes pixels).
var squareSize = 12; // Size of each program pixel in computer pixels.
var input; // An array representing the complex point z(i,j) at the coordinates (i,j)
var output; // An array representing the image f(z(i,j)) at the coordinate (i,j) (computed at a given time t)
var mid = complexRes*squareSize/2;
var l1Size = 2; // The source of the function f will be {z=a+bi | max(|a|,|b|)<l1Size}
var ii = [0,1]; // = sqrt(-1)
var zero = [0,0]; // = 0
var t=0;
var dt = Math.PI/30;
// rotation
var cameraHorAngle = Math.PI/10; //full rotation
var cameraVerAngle = Math.PI/4; // should be in [-PI/2,PI/2]
var cameraDistance = 800;
var pause = false;
/**
* Returns the value of the function f at the complex point z, at the real time t.
*/
function f(z, t){
return addReal(mult(z,z), 2*Math.sin(t)); // z^2 + sin(t)
}
function setup() {
createCanvas((complexRes-1)*squareSize, (complexRes-1)*squareSize, WEBGL);
background(0);
colorMode(HSB, 360, 100, 100)
//normalize = range/complexRes;
createComplexInput();
initOutput();
computeOutput(t);
updateScreen();
tx = -complexRes*squareSize/2;
ty = -complexRes*squareSize/2;
}
//float[] mouse = new float[]{1,0};
function draw() {
background(0);
updateScreen();
cameraX = Math.sin(cameraHorAngle)*Math.cos(cameraVerAngle);
cameraY = Math.cos(cameraHorAngle)*Math.cos(cameraVerAngle);
cameraZ = Math.sin(cameraVerAngle);
camera(cameraX*cameraDistance,cameraY*cameraDistance,cameraZ*cameraDistance,0,0,0,0,0,-1);
if (pause){
return;
}
computeOutput(t);
t+=dt;
}
/**
* Creates an input corresponding to the grid of pixels.
*/
function createComplexInput(){
input = []
for (let i=0; i<complexRes; i++){
var innerInput = [];
input.push(innerInput);
for (let j=0; j<complexRes; j++){
var a = (2*j/complexRes-1) * l1Size;
var b = (2*i/complexRes-1) * l1Size;
innerInput.push([a,b]);
}
}
}
/**
* Initializes the output array.
*/
function initOutput(){
output = [];
for (let i=0; i<complexRes; i++){
var innerOutput = [];
output.push(innerOutput);
for (let j=0; j<complexRes; j++){
innerOutput.push(zero);
}
}
}
/**
* Compute the output of f(z,t) at time t on the given input.
*/
function computeOutput(t){
var result;
for (let i=0; i<complexRes; i++){
for (let j=0; j<complexRes; j++){
result = f(input[i][j], t);
if (result==null)
result = zero;
output[i][j] = result;
}
}
}
function complexToColor(z){
// z = a+bi
a = z[0];
b = z[1];
// polar coordinates
var theta = atan2(b,a);
var r = (a*a+b*b)*10;
var tt = map(theta,-1*PI,PI,0,360);
var rr = map(atan(r),0,PI/2,0,100);
return color(tt,100,rr);
}
var drawReal = true;
function updateScreen(){
drawComplexParabola();
drawAxes();
if (drawReal){
drawRealParabola();
}
}
function drawRealParabola(){
stroke(255);
noFill();
strokeWeight(5);
for (let i=1; i<complexRes; i++){
beginShape();
vertex(squareSize*(i-1)-mid, 0, -output[i-1][complexRes/2][0]*50);
vertex(squareSize*(i)-mid, 0, -output[i][complexRes/2][0]*50);
endShape();
}
}
function drawComplexParabola(){
noStroke();
for (let i=1; i<complexRes; i++){
for (let j=1; j<complexRes; j++){
c = complexToColor(output[i][j]);
fill(c);
beginShape();
vertex(squareSize*(i-1)-mid, squareSize*(j-1)-mid, complex_norm(output[i-1][j-1])*50);
vertex(squareSize*(i)-mid, squareSize*(j-1)-mid, complex_norm(output[i][j-1])*50);
vertex(squareSize*(i)-mid, squareSize*(j)-mid, complex_norm(output[i][j])*50);
vertex(squareSize*(i-1)-mid, squareSize*(j)-mid, complex_norm(output[i-1][j])*50);
endShape();
}
}
}
function drawAxes(){
//fill(255);
//strokeWeight(10);
//rect(-1000,-squareSize,2000,2*squareSize);
//rect(-squareSize,-1000,2*squareSize,2000);
stroke(255);
noFill();
strokeWeight(5);
beginShape();
vertex(-1000,0,0);
vertex(1000,0,0);
endShape();
beginShape();
vertex(0,-1000,0);
vertex(0,1000,0);
endShape();
strokeWeight(5);
beginShape();
vertex(0,0,-1000);
vertex(0,0,1000);
endShape();
}
function complex_norm(z){
return Math.sqrt(z[0]*z[0] + z[1]*z[1]);
}
function keyPressed(){
//print(key);
if (key=='r'){
drawReal = !drawReal;
return;
}
if (key=='p'){
pause = !pause;
return;
}
if (key=='+'){
cameraDistance -= 50;
if (cameraDistance < 0){
cameraDistance = 0;
}
return;
}
if (key=='-'){
cameraDistance += 50;
return;
}
if (key=='ArrowUp'){
cameraVerAngle += Math.PI/20;
if (cameraVerAngle>Math.PI/2){
cameraVerAngle=Math.PI/2;
}
return;
}
if (key=='ArrowDown'){
cameraVerAngle -= Math.PI/20;
if (cameraVerAngle<-Math.PI/2){
cameraVerAngle=-Math.PI/2;
}
return;
}
if (key=='ArrowLeft'){
cameraHorAngle -= Math.PI/20;
return;
}
if (key=='ArrowRight'){
cameraHorAngle += Math.PI/20;
return;
}
}