<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />故事,第 1 部分
下午早些时候,十月下旬的阳光与男孩和他的朋友们玩耍。这还不可怕。 万圣节还有几个小时。
(重新设计的 JMP 用户社区即将到来!第 2 部分和第 3 部分将在那里找到您! )
视频和代码
该视频序列显示了模拟退火,用于在球体周围均匀放置 3200 个点。最初,这些点被放置在从北极到南极的双螺旋中。我不是在尝试双螺旋;我希望有更多的初始传播,但无论如何它都有效。颜色仅用于可视化。在初始点之后,退火过程开始。https://en.wikipedia.org/wiki/Annealing_(冶金)描述了一种物理退火过程,其中金属被加热以松弛结晶结构,使原子移动到不同的关系中。有些材料甚至可能在十月阳光的温暖中退火。这里的 JSL 已针对视频进行了调整,并未针对其他任何内容进行优化……但已经足够好了。在退火阶段,加热和冷却的时间表控制着点距离最近的点的距离。因为有很多点在两极挤在一起,所以时间表需要让系统保持一段时间,以便这些点有时间迁移出去。在那个“高温”下,这些点跳得足够远,以至于它们经常进入另一个点的附近太远。时间表的逐渐冷却阶段让积分稳定下来,移动越来越少。视频在他们完全安顿下来之前就结束了。
https://www.youtube.com/watch?v=8-Fjw1wD-Oc

nnodes = 3200;
xx = -nnodes * 3 / 2;
nodelocs = J(nnodes, 3, 0); // 每个节点的 x,y,z 点
对于( i = 1, i <= nnodes, i++,
f = i / nnodes; // 0..1
z = Cos( f * Pi() ); // 从上到下
r = Sin( f * Pi() ); // 半径
x = 罪(10000 * f)* r; // 10,000 弧度
y = Cos( 10000 * f ) * r; // 太多了。但它有效......
节点[i, 1] = x;
节点[i, 2] = y;
节点[i, 3] = z;
);
//nodeobj = 场景显示列表(); nodeobj<
addnodes = Function( {thisnnodes},
{inode, delta, pos = [0 0 0], result = Scene Display List()},
For( inode = 1, inode <= thisnnodes, inode++,
delta = nodelocs[inode, 0] - pos;
pos = nodelocs[inode, 0];
//显示(位置,增量);
结果 << 翻译(增量);
rgb = 颜色到 RGB(热颜色(inode / nnodes,“光谱”))*1;
//显示(inode/nnodes,rgb);
结果<<颜色(rgb [1],rgb [2],rgb [3]);
结果 << sphere(.005, 3, 3)//calllist(nodeobj);
;
);
结果<<翻译(-pos); //恢复原始位置
result// 返回显示列表
;
);
//a=addnodes();
// 将节点设置为半径为 1 的球体,大约为 0,0,0
调整 = 函数({d},
{inode,半径,最近,dist,err,pos,newlocs = J(nnodes,3,.),table = KDTable(nodelocs)},
对于(inode = 1,inode <= nnodes,inode++,
pos = nodelocs[inode, 0];
// 轻推离最近的邻居
表 << 删除行(索引节点);
{closest, dist} = table << knearestrows(5, pos);
表<<插入行(inode);
对于(iclose = 1,iclose <= 5,iclose++,
err = pos - nodelocs[closest[iclose], 0] + J( 1, 3, Random Normal( 0, .01 ) ); // [dx dy dz]
//pos = pos + .00991/ 错误; // 移开
对于(idim = 1,idim <= 3,idim++,
如果(错误[idim] < 0,
pos[idim] -= d / iclose,
pos[idim] += d / iclose
)
);
);
// 向 1.000 微移半径
半径 = Sqrt( Sum( pos
位置 ) );
//err = 1.0 - 半径; // 如果半径太小,则 err 为正
位置 = 位置 / 半径; // 大错误移动得更快
newlocs[inode, 0] = 位置; // 临时拷贝
);
nodelocs = newlocs; // 将温度复制到实际
0 // 虚拟返回值
;
);
角度 = 30;
场景 = 场景框(1924 / 2, 1084 / 2);
构建 = 函数({thisnnodes},
{},
场景<<清晰;
scene << ShowArcBall( never/*always*/ /*During Drag*/ );
场景 << 背景颜色(黑色);
场景 << 透视图(65, .1, 5);
场景<<翻译(0.0,0.0,-2.0);
角度 += .1;
场景 << 旋转(角度 * 0.23, 1, 0, 0);
场景 << 旋转(角度 * 0.11, 0, 1, 0);
场景 << 旋转(角度 * 2、0、0、1);
object = addnodes(thisnnodes);
场景<< ArcBall(对象,1);
);
构建(1);
新窗口(“点世界”,场景);
对于( i = 1, i <= 3200, i += 4,
构建(我);
场景<<更新;
等待(0);
// 场景<
);
For( i = 1, i < 5000, i++, // 几乎在 1000 处完成
vint = 插值(i, 1, .00001, 100, .0005, 200, .001, 4000, .0005, 5000, .00001);
显示(我,vint);
构建(3200);
场景<<更新;
等待(0);
调整(文特);
//场景<
);
建造();
场景<<更新;
等待(0);