改进C++;求半径为r的球体内所有点的算法 语言/编译器:C++(Visual Studio 2013) 经验:~2个月
我在三维空间中的矩形网格中工作(大小:xdim by ydim by zdim),其中,“xgrid、ygrid和zgrid”分别是x、y和z坐标的三维数组。现在,我感兴趣的是找到位于以点为中心的半径为“r”的球体(vi,vj,vk)内的所有点。我想将这些点的索引位置存储在向量“xidx,yidx,zidx”中。对于单个点,该算法有效且速度足够快,但当我希望在3D空间中迭代多个点时,我会遇到很长的运行时间 是否有人对如何改进C++中的算法有什么建议?在运行了一些我在网上发现的评测软件(Luke stackwalker,非常困)之后,“std::vector::size”和“std::vector::operator[]”成员函数似乎让我的代码陷入了困境。非常感谢您的帮助 注意:由于我事先不知道球体中有多少体素,因此我将向量xidx、yidx、zidx的长度设置为大于所需的长度,然后在函数末尾删除所有多余的元素改进C++;求半径为r的球体内所有点的算法 语言/编译器:C++(Visual Studio 2013) 经验:~2个月,c++,algorithm,vector,multidimensional-array,C++,Algorithm,Vector,Multidimensional Array,我在三维空间中的矩形网格中工作(大小:xdim by ydim by zdim),其中,“xgrid、ygrid和zgrid”分别是x、y和z坐标的三维数组。现在,我感兴趣的是找到位于以点为中心的半径为“r”的球体(vi,vj,vk)内的所有点。我想将这些点的索引位置存储在向量“xidx,yidx,zidx”中。对于单个点,该算法有效且速度足够快,但当我希望在3D空间中迭代多个点时,我会遇到很长的运行时间 是否有人对如何改进C++中的算法有什么建议?在运行了一些我在网上发现的评测软件(Luke
void find_nv(int vi, int vj, int vk, vector<double> &xidx, vector<double> &yidx, vector<double> &zidx, double*** &xgrid, double*** &ygrid, double*** &zgrid, int r, double xdim,double ydim,double zdim, double pdim)
{
double xcor, ycor, zcor,xval,yval,zval;
vector<double>xyz(3);
xyz[0] = xgrid[vi][vj][vk];
xyz[1] = ygrid[vi][vj][vk];
xyz[2] = zgrid[vi][vj][vk];
int counter = 0;
// Confine loop to be within boundaries of sphere
int istart = vi - r;
int iend = vi + r;
int jstart = vj - r;
int jend = vj + r;
int kstart = vk - r;
int kend = vk + r;
if (istart < 0) {
istart = 0;
}
if (iend > xdim-1) {
iend = xdim-1;
}
if (jstart < 0) {
jstart = 0;
}
if (jend > ydim - 1) {
jend = ydim-1;
}
if (kstart < 0) {
kstart = 0;
}
if (kend > zdim - 1)
kend = zdim - 1;
//-----------------------------------------------------------
// Begin iterating through all points
//-----------------------------------------------------------
for (int k = 0; k < kend+1; ++k)
{
for (int j = 0; j < jend+1; ++j)
{
for (int i = 0; i < iend+1; ++i)
{
if (i == vi && j == vj && k == vk)
continue;
else
{
xcor = pow((xgrid[i][j][k] - xyz[0]), 2);
ycor = pow((ygrid[i][j][k] - xyz[1]), 2);
zcor = pow((zgrid[i][j][k] - xyz[2]), 2);
double rsqr = pow(r, 2);
double sphere = xcor + ycor + zcor;
if (sphere <= rsqr)
{
xidx[counter]=i;
yidx[counter]=j;
zidx[counter] = k;
counter = counter + 1;
}
else
{
}
//cout << "counter = " << counter - 1;
}
}
}
}
// erase all appending zeros that are not voxels within sphere
xidx.erase(xidx.begin() + (counter), xidx.end());
yidx.erase(yidx.begin() + (counter), yidx.end());
zidx.erase(zidx.begin() + (counter), zidx.end());
return 0;
void find_nv(int vi、int vj、int vk、vector&xidx、vector&yidx、vector&zidx、double***&xgrid、double***&ygrid、double***&zgrid、int r、double xdim、double ydim、double zdim、double pdim)
{
双xcor、ycor、zcor、xval、yval、zval;
向量xyz(3);
xyz[0]=xgrid[vi][vj][vk];
xyz[1]=ygrid[vi][vj][vk];
xyz[2]=zgrid[vi][vj][vk];
int计数器=0;
//将循环限制在球体的边界内
int-istart=vi-r;
int iend=vi+r;
int jstart=vj-r;
int-jend=vj+r;
int kstart=vk-r;
int-kend=vk+r;
如果(istart<0){
istart=0;
}
如果(iend>xdim-1){
iend=xdim-1;
}
if(jstart<0){
jstart=0;
}
如果(jend>ydim-1){
jend=ydim-1;
}
如果(kstart<0){
kstart=0;
}
如果(kend>zdim-1)
kend=zdim-1;
//-----------------------------------------------------------
//开始遍历所有点
//-----------------------------------------------------------
对于(int k=0;k 如果(sphere您似乎已经在这类事情上使用了我最喜欢的技巧,去掉了相对昂贵的平方根函数,只处理半径和中心到点距离的平方值
另一种可能加快速度的方法(a)是更换所有:
xyzzy = pow (plugh, 2)
与更简单的用户通话:
xyzzy = plugh * plugh
您可能会发现,删除函数调用可以加快速度,尽管速度很小
如果可以确定目标数组的最大大小,另一种可能性是使用实数组而不是向量。我知道它们使向量代码尽可能达到疯狂的最优,但它仍然无法与固定大小的数组进行性能匹配(因为它必须完成固定大小数组所做的一切,并处理可能的扩展)
同样,这可能只会以更多内存使用为代价提供非常微小的改进,但以空间换取时间是一种经典的优化策略
除此之外,请确保您明智地使用编译器优化。在大多数情况下,默认生成具有较低级别的优化,以使调试更容易。将其用于生产代码
(a)与所有优化一样,您应该进行测量,而不是猜测!这些建议正是:建议。它们可能会改善情况,也可能不会改善情况,因此由您来测试它们。您最大的问题之一,也是可能阻止编译器进行大量优化的一个问题是,您没有使用f你的网格
如果你真的在使用常规网格,那么
xgrid[i][j][k] = x_0 + i * dxi + j * dxj + k * dxk
ygrid[i][j][k] = y_0 + i * dyi + j * dyj + k * dyk
zgrid[i][j][k] = z_0 + i * dzi + j * dzj + k * dzk
如果栅格是轴对齐的,则
xgrid[i][j][k] = x_0 + i * dxi
ygrid[i][j][k] = y_0 + j * dyj
zgrid[i][j][k] = z_0 + k * dzk
在核心循环中替换这些将导致显著的加速。您可以做两件事。减少要包含的测试点数,并将问题简化为多个2d测试
如果你沿着z轴观察球体,你就有了球体中y+r到y-r的所有点,使用这些点中的每一个,你可以将球体切割成包含x/z平面中的所有点的圆,这些点限制在你测试的特定y的圆半径内。计算圆的半径是一个简单的解决长度问题的方法直角三角形问题底的h
现在,您正在测试立方体中的所有点,但球体的上限范围排除了大多数点。上述算法背后的思想是,您可以将球体每个级别上的测试点限制为包含该高度处圆半径的正方形
这里是一个简单的手绘图形,从侧面显示球体
这里我们看的是半径为ab的球体切片。因为你知道直角三角形的长度ac和bc,你可以使用毕达哥拉斯定理计算ab。现在你有了一个简单的圆,你可以测试其中的点,然后向下移动,它减少长度ac,重新计算ab,然后重复
现在,一旦你有了这些,你实际上可以做更多的优化。首先,你不需要测试圆上的每个点,你只需要测试四分之一的点。如果你测试圆左上象限的点(球体的切片)然后,其他三个点中的点只是同一点向右或向下偏移的镜像