傅里叶本轮图绘制心形XX
20260801 创建
豆包辅助
大Bug ,没能实现绘图
参考:Discrete Fourier Transform & Epicycles: Scripting – GeoGebra
#二、进阶版:心形图案傅里叶描图(完整 DFT 实现)
#网上 “圆圈画任何图案” 的核心效果,基于离散傅里叶变换 (DFT) 实现:将闭合曲线分解为数十个旋转圆,末端点精准描出原图案。
#步骤 1:创建基础控制参数
t = 滑动条(0, 2π, 0.01, 0)
Npts = 64
M = 滑动条(5, 64, 1, 30)
#Npts:心形曲线的采样点数,建议取 32/64/128(2 的幂次),越大越精细但越卡顿
#M:保留的傅里叶分量数,控制圆圈数量与描图精度
#步骤 2:采样心形曲线(生成离散点集)
#用经典心形参数方程均匀采样,生成 64 个轮廓点:
#Pts = 序列(
# (16 sin(2π (m-1) / Npts)^3,
# 13 cos(2π (m-1) / Npts) - 5 cos(4π (m-1) / Npts) - 2 cos(6π (m-1) / Npts) - cos(8π (m-1) / Npts)),
# m, 1, Npts )
Pts = 序列( (16 sin(2π (m-1) / Npts)^3, 13 cos(2π (m-1) / Npts) - 5 cos(4π (m-1) / Npts) - 2 cos(6π (m-1) / Npts) - cos(8π (m-1) / Npts)), m, 1, Npts )
#输入后绘图区会自动出现一个由点组成的心形轮廓。
#步骤 3:计算离散傅里叶系数 (DFT)
#对采样点做复数形式的 DFT,得到每个频率分量的幅值与相位:
#c = 序列(
# 1/Npts * 总和(
# (x(元素(Pts, m)) + ί * y(元素(Pts, m))) * e^(-ί * 2π * (k-1) * (m-1) / Npts),
# m, 1, Npts ),
# k, 1, Npts )
c = 序列( 1/Npts * 总和( (x(元素(Pts, m)) + ί * y(元素(Pts, m))) * e^(-ί * 2π * (k-1) * (m-1) / Npts), m, 1, Npts ), k, 1, Npts )
freq = 序列( (k-1) - Npts/2, k, 1, Npts )
#c:复数傅里叶系数,模长 = 对应圆的半径,辐角 = 圆的初始相位
#freq:对应分量的旋转频率,正数逆时针、正数顺时针旋转
#步骤 4:按幅值降序排序(优化视觉效果)
#把半径最大的圆排在最前面,画面层次感更强,也更符合主流动画的呈现效果:
amp = 映射( abs(z), z, c )
#sortedIndex = -排序索引(-amp, false)
#sortedIndex = 映射(索引(pp,c),pp,amp)
sortedamp=-升序排列(-amp)
sortedIndex = 映射(索引(pp,amp),pp,sortedamp)
#sortedIndex = 序列( 索引(元素(amp,i),c),i,1, Npts )
c_{sorted} = 映射( 元素(c, i), i, sortedIndex )
freq_{sorted} = 映射( 元素(freq, i), i, sortedIndex )
#步骤 5:生成旋转圆系统与末端描点
cumSum = 序列( 总和( 元素(c_{sorted}, i) * e^(ί * 元素(freq_{sorted}, i) * t), i, 1, k ), k, 1, M )
centers = 合并( {(0,0)}, 映射( (real(z),imaginary(z)), z,take(cumSum, 1, M-1) ) )
#circleList = 序列( 圆周( 元素(centers, k), abs(元素(c_{sorted}, k)) ), k, 1, M )
circleList = 序列( 圆周( 元素(centers, k), sqrt(real(元素(c_{sorted}, k))^2+imaginary(元素(c_{sorted}, k))^2) ), k, 1, M )
#srqt(real(元素(c_{sorted}, k))^2+imaginary(元素(c_{sorted}, k))^2)
vectorList = 序列( 向量( 元素(centers, k), (real(元素(cumSum, k)), imaginary(元素(cumSum, k))) ), k, 1, M )
endPoint = (real(元素(cumSum, M)), imaginary(元素(cumSum, M)))
#步骤 6:生成描绘轨迹并启动动画
#drawPath = 轨迹(endPoint, t)
#右键点击t滑动条 → 「启动动画」,即可看到大小圆圈同步旋转、末端点逐步描出完整心形的动画。拖动M滑动条可增减圆圈数量,观察描图精度的变化。
#三、自定义与优化技巧
#替换成任意图案:用 GeoGebra 的「画笔」工具手绘闭合曲线,在曲线上均匀取点存入列表Pts,替换步骤 2 的心形采样命令即可,建议采样点数量取 2 的幂次。
#性能优化:采样点Npts不超过 256,分量数M不超过 100;可在属性里关闭圆的填充、调细线条,提升动画流畅度。
#常见问题排查:图案偏移需检查 DFT 公式中(m-1)和(k-1)是否完整;虚数报错请确认用的是ί(iota)而非英文字母i。