注意事项:在我有更多的声望点数之前他们不允许我嵌入图像(抱歉),但是所有链接都是发布在imgur上的图片!:) 谢谢
我复制了一种方法,可以使用傅里叶变换来动画化任何单一路径(1个封闭路径)。这会创建旋转圆圈的动画(epicycles),这些圆圈彼此旋转,并遵循输入的点,跟踪路径作为连续的环/函数。
我想将此系统应用于3D。我能够想到的两种方法是使用球坐标系(两个复平面)或三个Epicycles-->一个用于每个轴(x,y,z),具有它们各自的参数方程。这可能是开始的最佳方式!!
2个周期,一个用于X轴,一个用于Y轴:
图片:一个周期-> 复数-> 用于X和Y
傅里叶变换背景!!!:
•欧拉公式允许我们将复平面中的每个点分解为角度(指数函数的参数)和振幅(Cn系数)
•在这种意义上,每个无限级数中的项表示为以半径cn为半径的圆上的一个点,偏移2πnt/T弧度
•下面的图像显示了如何将相位/振幅的一组复数之和可视化为在复平面中连接的一组圆。每个红线都表示序列和中的一个项:cne2πi(nT)t
•添加总和的每个分项仅对在复杂空间中连接这些红色向量进行拼接:
旋转动画圆:
圆到动画绘制:
•如果您具有在二维(x-y)空间中的线条绘制,可以将其数学描述为参数函数。(两个单变量函数,均以辅助变量(T在本例中)为基础:
例如,下面是马的简单线条绘制,以及通过图像中的黑色像素的参数路径,然后将该路径分解为其X和Y组件:
此时,我们需要计算这两条路径的傅里叶逼近,并使用该逼近的系数来确定所需最终可视化所需的圆的相位和振幅。
我复制了一种方法,可以使用傅里叶变换来动画化任何单一路径(1个封闭路径)。这会创建旋转圆圈的动画(epicycles),这些圆圈彼此旋转,并遵循输入的点,跟踪路径作为连续的环/函数。
我想将此系统应用于3D。我能够想到的两种方法是使用球坐标系(两个复平面)或三个Epicycles-->一个用于每个轴(x,y,z),具有它们各自的参数方程。这可能是开始的最佳方式!!
2个周期,一个用于X轴,一个用于Y轴:
![img](https://istack.dev59.com/uNTaQ.webp)
![img](https://istack.dev59.com/mIzd7.webp)
•欧拉公式允许我们将复平面中的每个点分解为角度(指数函数的参数)和振幅(Cn系数)
•在这种意义上,每个无限级数中的项表示为以半径cn为半径的圆上的一个点,偏移2πnt/T弧度
•下面的图像显示了如何将相位/振幅的一组复数之和可视化为在复平面中连接的一组圆。每个红线都表示序列和中的一个项:cne2πi(nT)t
•添加总和的每个分项仅对在复杂空间中连接这些红色向量进行拼接:
旋转动画圆:
![img](https://istack.dev59.com/pqf7w.webp)
•如果您具有在二维(x-y)空间中的线条绘制,可以将其数学描述为参数函数。(两个单变量函数,均以辅助变量(T在本例中)为基础:
例如,下面是马的简单线条绘制,以及通过图像中的黑色像素的参数路径,然后将该路径分解为其X和Y组件:
![Horse Path](https://istack.dev59.com/FNwjF.webp)
Python代码: 此示例使用的Python代码可在guithub上找到。
我已经成功地将该过程动画化为2D,但我想将其应用于3D。
以下代码表示2D动画--> 我已经让它工作:
[使用JavaScript和P5.js库]
傅里叶算法(fourier.js):
// a + bi
class Complex {
constructor(a, b) {
this.re = a;
this.im = b;
}
add(c) {
this.re += c.re;
this.im += c.im;
}
mult(c) {
const re = this.re * c.re - this.im * c.im;
const im = this.re * c.im + this.im * c.re;
return new Complex(re, im);
}
}
function dft(x) {
const X = [];
const Values = [];
const N = x.length;
for (let k = 0; k < N; k++) {
let sum = new Complex(0, 0);
for (let n = 0; n < N; n++) {
const phi = (TWO_PI * k * n) / N;
const c = new Complex(cos(phi), -sin(phi));
sum.add(x[n].mult(c));
}
sum.re = sum.re / N;
sum.im = sum.im / N;
let freq = k;
let amp = sqrt(sum.re * sum.re + sum.im * sum.im);
let phase = atan2(sum.im, sum.re);
X[k] = { re: sum.re, im: sum.im, freq, amp, phase };
Values[k] = {phase};
console.log(Values[k]);
}
return X;
}
Sketch功能/动画(Sketch.js):
let x = [];
let fourierX;
let time = 0;
let path = [];
function setup() {
createCanvas(800, 600);
const skip = 1;
for (let i = 0; i < drawing.length; i += skip) {
const c = new Complex(drawing[i].x, drawing[i].y);
x.push(c);
}
fourierX = dft(x);
fourierX.sort((a, b) => b.amp - a.amp);
}
function epicycles(x, y, rotation, fourier) {
for (let i = 0; i < fourier.length; i++) {
let prevx = x;
let prevy = y;
let freq = fourier[i].freq;
let radius = fourier[i].amp;
let phase = fourier[i].phase;
x += radius * cos(freq * time + phase + rotation);
y += radius * sin(freq * time + phase + rotation);
stroke(255, 100);
noFill();
ellipse(prevx, prevy, radius * 2);
stroke(255);
line(prevx, prevy, x, y);
}
return createVector(x, y);
}
function draw() {
background(0);
let v = epicycles(width / 2, height / 2, 0, fourierX);
path.unshift(v);
beginShape();
noFill();
for (let i = 0; i < path.length; i++) {
vertex(path[i].x, path[i].y);
}
endShape();
const dt = TWO_PI / fourierX.length;
time += dt;
最重要的是!路径/坐标: (这是一个三角形)
let drawing = [
{ y: -8.001009734 , x: -50 },
{ y: -7.680969345 , x: -49 },
{ y: -7.360928956 , x: -48 },
{ y: -7.040888566 , x: -47 },
{ y: -6.720848177 , x: -46 },
{ y: -6.400807788 , x: -45 },
{ y: -6.080767398 , x: -44 },
{ y: -5.760727009 , x: -43 },
{ y: -5.440686619 , x: -42 },
{ y: -5.12064623 , x: -41 },
{ y: -4.800605841 , x: -40 },
...
...
{ y: -8.001009734 , x: -47 },
{ y: -8.001009734 , x: -48 },
{ y: -8.001009734 , x: -49 },
];