在3D立方体上折叠选定的点



我正在尝试为以下3D立方体选择问题找到一个有效的算法:

想象一个点的二维数组(让它的大小为x大小的正方形),并称之为边。

为方便计算,我们将max声明为size-1创建一个六边形的立方体,左下方为0,0,右上方为max,max。使用z来跟踪单个立方体所在的边,y为上,x为右

public class Point3D {
public int x,y,z;
public Point3D(){}
public Point3D(int X, int Y, int Z) {
x = X;
y = Y;
z = Z;
}
}
Point3D[,,] CreateCube(int size)
{
Point3D[,,] Cube = new Point3D[6, size, size];
for(int z=0;z<6;z++)
{           
for(int y=0;y<size;y++)
{
for(int x=0;x<size;x++)
{
Cube[z,y,x] = new Point3D(x,y,z);
}
}
}
return Cube;
}

现在要选择一个随机的单点,我们可以使用三个随机数:

Point3D point = new Point(
Random(0,size), // 0 and max
Random(0,size), // 0 and max
Random(0,6));   // 0 and 5

要选择加号,我们可以检测给定的方向是否适合当前的边。否则,我们会发现立方体位于与中心点接触的一侧。

使用如下4个函数:

private T GetUpFrom<T>(T[,,] dataSet, Point3D point) where T : class {
if(point.y < max)
return dataSet[point.z, point.y + 1, point.x];
else {
switch(point.z) {
case 0: return dataSet[1, point.x, max];      // x+
case 1: return dataSet[5, max, max - point.x];// y+
case 2: return dataSet[1, 0, point.x];        // z+
case 3: return dataSet[1, max - point.x, 0];  // x-
case 4: return dataSet[2, max, point.x];      // y-
case 5: return dataSet[1, max, max - point.x];// z-
}
}
return null;
}

现在我想找到一种在随机点选择任意形状(如预定义的随机blobs)的方法。但我愿意把它调整成方形或锯齿形的圆形。

实际的表面区域将被扭曲并在角落上折叠起来,这很好,不需要补偿(想象一下在立方体的角落上放一张贴纸,如果角落与贴纸的中心匹配,则需要移除四分之一的贴纸以使其粘在角落上并折叠)。这也是我们想要的效果。

不允许重复选择,因此需要以某种方式过滤将被选择两次的多维数据集(或者以不发生重复的方式计算)。这可能很简单,如使用HashSet或List并使用辅助函数来检查条目是否唯一(这很好,因为选择总是远低于最大1000个立方体)。

这个函数在包含立方体侧面的类中的委托是这样的:委托T[] SelectShape(Point3D point, int size);

目前我正在考虑检查立方体的每一面,看看选择的哪一部分位于那一面。

计算选择的哪一部分在选定的Point3D的同一侧,将是微不足道的,因为我们不需要转换位置,只需要转换边界。接下来是5个翻译,然后检查其他5个面,看看所选区域的一部分是否在那一边。

我对解决这种问题已经生疏了,所以我想知道是否有人有更好的解决方案。

@ arghblleargh要求进一步解释:

我们将使用一个6边的立方体,尺寸为16。每条边是16x16点。存储为三维数组,我使用z表示side, y, x,这样数组将以:new Point3D[z, y, x]初始化,它对于锯齿数组几乎相同,默认情况下是可序列化的(因此也很好)[z][y][x],但需要单独初始化每个子数组。

让我们选择一个大小为5x5的正方形,以选定的点为中心。要找到这样一个5x5的平方减法,并在问题的轴上加2:x-2到x+2, y-2到y+2。

随机选择一条边,我们选择的点是z = 0(立方体的x+边),y = 6, x = 6。

6-2和6+2都在16 × 16数组的范围内,很容易选择。

将选择点移动到x=0和y=6将被证明更具挑战性。因为x - 2需要在我们选择的边的左边查找。幸运的是,我们选择了0边或x+边,因为只要我们不在上或下边也不在立方体的上或下边,所有的轴都是x+ =右,y+ =上。所以要得到左边的坐标只需要减去max (size - 1) - x,记住size = 16, max = 15, x = 0-2 = -2, max - x = 13。这边的分式是x = 13到15 y = 4到8。将它添加到我们可以在原始侧选择的部分,将得到整个选择。

将选择范围移动到0,6将被证明是更复杂的,因为现在我们不能隐藏在知道所有轴对齐的安全后面。可能需要一些轮换。只有4种可能的翻译,所以它仍然是可管理的。

移到0,0是问题真正开始出现的地方。像现在一样,左边和下面都需要绕到另一边。此外,即使是细分的部分也会有一个区域落在外面。这个伤口上唯一的良药就是我们不关心选择的重叠部分。因此,我们可以在可能的情况下跳过它们,或者稍后从结果中过滤它们。

现在我们从"法轴"一侧移动到底部,我们需要旋转并匹配正确的坐标,以便点正确地环绕边缘。

当每个边的轴折叠成一个立方体时,一些轴可能需要翻转或旋转以选择正确的点。

问题仍然存在,是否有更好的解决方案可以选择立方体上所有在一个区域内的点。也许我可以给每一边一个平移矩阵和世界空间中的测试坐标?

找到了一个很好的解决方案,几乎不需要付出什么努力。

为大小为n + 2的Hollow Cube创建存储,其中n是数据中包含的多维数据集的大小。这就满足了:边是接触的,但不重叠或共享某些点。

这将通过创建一个使用笛卡尔坐标的查找数组来简化计算和转换。使用单个平移函数获取选定点的坐标,获得"世界位置"。

使用该函数可以将每个点存储到笛卡尔查找数组中。

当选择一个点时,我们可以再次使用相同的函数(或使用存储的数据)并进行减法(获得AA或最小位置)和加法(获得BB或最大位置)。

那么我们就可以查找AA之间的每个条目。xyz和BB。xyz坐标。每个空项应该被跳过。

如果需要的话,使用一种数组类型进行优化,如果z不是0或size-1,则返回null,因此不需要在中间存储'空心立方体'的空引用。

现在立方体可以选择3D立方体,其他形状是微不足道的,给定一个3D点,定义一个3D形状并使用查找数组测试形状中的每个部分,如果不是null,将其添加到选择中。每个点只被选中一次,因为我们只检查每个位置一次。

由于测试多维数据集的内部和外部为空,会产生一些计算开销,但数组访问速度非常快,因此该解决方案适用于我当前的项目。

最新更新