我正在尝试为以下3D立方体选择问题找到有效的算法:
想象一下一个2D点阵列(让它变成x大小的正方形)并将它称为一面。
为了便于计算,我们将max声明为size-1 创建一个六边的立方体,在左下角保持0,0,在右上角保持最大,最大。 使用z跟踪单个立方体所在的边,y为up,x为right
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;
}
现在我想找到一种在随机点选择任意形状(如预定义的随机blob)的方法。 但是可以选择将其调整为方形或锯齿状的圆形。
实际的表面区域会弯曲并在角落上折叠到自身上,这很好并且不需要补偿(想象一下,如果角落与贴纸中心的四分之一匹配,则将贴纸贴在立方体的角落上需要移除贴纸才能粘贴并折叠在角落上。再次,这是期望的效果。
不允许重复选择,因此需要以某种方式过滤两次选择的多维数据集(或以不会发生重复的方式计算)。这可能很简单,例如使用HashSet或List并使用辅助函数来检查条目是否是唯一的(这很好,因为选择总是远远低于1000个立方体)。
包含多维数据集边的类中此函数的委托如下所示: 委托T [] SelectShape(Point3D point,int size);
目前,我正在考虑检查多维数据集的每一侧,以查看选择的哪一部分位于该侧。
计算选择的哪一部分位于所选Point3D的同一侧,这将是微不足道的,因为我们不需要转换位置,只需要转换边界。 接下来将是5个翻译,然后检查其他5个方面以查看所选区域的一部分是否在那一侧。
我在解决这样的问题时变得生疏,所以想知道是否有人能更好地解决这个问题。
@arghbleargh要求进一步解释:
我们将使用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 x 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是问题真正开始出现的地方。 因为现在左右都需要环绕到另一侧。此外,甚至细分部分也会有一个区域落在外面。 伤口上唯一的问题是我们不关心选择的重叠部分。 因此,我们可以在可能的情况下跳过它们,或者稍后从结果中过滤它们。
现在我们从正常轴移动了#39;从侧面到底部,我们需要旋转并匹配正确的坐标,以使点正确地环绕边缘。
由于每一侧的轴都折叠成立方体,某些轴可能需要翻转或旋转才能选择正确的点。
问题仍然存在,是否有更好的解决方案可以选择区域内立方体上的所有点。也许我可以给每一方提供一个平移矩阵并在世界空间中测试坐标?
答案 0 :(得分:0)
找到了一个非常好的解决方案,只需要很少的努力就可以实现。
为空心多维数据集创建一个大小为n + 2的存储空间,其中n是数据中包含的多维数据集的大小。这满足了:双方都在接触但不重叠或分享某些观点。
这将通过创建使用笛卡尔坐标的查找数组来简化计算和转换。 使用单个平移功能来获取所选点的坐标,获得“世界位置”。
使用该函数,我们可以将每个点存储到笛卡尔查找数组中。
选择一个点时,我们可以再次使用相同的函数(或使用存储的数据)并减去(以获得AA或min位置)并添加(以获得BB或最大位置)。
然后我们可以查找AA.xyz和BB.xyz坐标之间的每个条目。 应跳过每个空条目。
如果z不是0或size-1,则使用返回null的数组类型进行优化,因此不需要在中间存储'空心立方体'的空引用。
既然立方体可以选择3D立方体,其他形状是微不足道的,给定3D点,定义3D形状并使用查找数组测试形状中的每个部分,如果不是null则将其添加到选择中。 每个点只选择一次,因为我们只检查每个位置一次。
由于对多维数据集内部和外部的空白进行测试而产生一些计算开销,但是数组访问速度非常快,以至于此解决方案对于我当前的项目来说非常好。