2013-08-30 57 views
0

我試圖找到有效的算法如下3D魔方的選擇問題:一個3D立方體摺疊選穴

試想點的二維數組(可以使其平方大小x的大小)和呼叫它是一面。

爲了便於計算,我們將max聲明爲size-1 創建一個六邊形的立方體,在左下角保留0,0和右上角的最大值,最小值。 使用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; 
} 

現在我想找到一種方法來選擇一個隨機點任意形狀(如預定義的隨機斑點)。 但會解決它調整爲一個正方形或鋸齒狀的圓。

實際的表面積會被彎曲並摺疊到角上,這很好,並且不需要補償(假設在立方體的角上貼一個貼紙,如果角與貼紙的中心相匹配的四分之一貼紙需要被移除才能在拐角處粘貼和摺疊)。這也是預期的效果。

不允許有重複的選擇,因此需要選擇兩次的多維數據集需要以某種方式進行過濾(或以不會發生重複的方式進行計算)。這可能很簡單,因爲使用HashSet或List以及使用幫助函數來檢查條目是否是唯一的(這是正確的,因爲選項總是遠遠低於1000立方體)。

包含多邊形面的類中此函數的代表如下所示: 委託T [] SelectShape(Point3D point,int size);

目前我正在考慮檢查立方體的每一側以查看選擇的哪一部分位於該側。

計算選擇的哪一部分位於所選Point3D的同一側,這將是微不足道的,因爲我們不需要翻譯位置,只需要邊界。 接下來將是5個翻譯,然後檢查其他5個方面,以查看所選區域的一部分是否在那邊。

我在解決像這樣的問題時生疏了,所以想知道是否有人對這個問題有更好的解決方案。

@arghbleargh要求進一步的解釋:

我們將用6個面的立方體,並使用一個大小爲16每一面16×16點。 作爲一個三維數組存儲我使用z爲side,y,x,使得數組將以:new Point3D [z,y,x]啓動,它對於鋸齒狀數組幾乎完全相同,默認情況下它是可序列化的所以這也會很好)[z] [y] [x]但需要對每個子陣列進行單獨的初始化。

讓我們選擇一個大小爲5x5的正方形,以選定點爲中心。 要找到這樣一個5x5平方減法並將2添加到所討論的軸:x-2到x + 2和y-2到y + 2。

隨機

一個selectubg側,我們選擇點爲z = 0(X +立方體的側),Y = 6,X = 6

兩個6-2和6 + 2是公內的16 x 16陣列的邊界和易於選擇的限制。

將選擇點移動到x = 0和y = 6然而會證明更具挑戰性。 由於x-2需要查看我們所選側面的左側。 幸運的是,我們選擇了邊0或x +,因爲只要我們不在頂部或底部,而不是在立方體的頂部或底部,所有軸都是x + = right,y + = up。 所以要獲得左側的座標只需要減去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是問題真正開始出現的地方。 現在左右兩邊都需要環繞到其他邊。而且,即使是細分的部分也會有一個區域落在外面。 這個傷口唯一的救星就是我們不關心選擇的重疊部分。 所以我們可以在可能時跳過它們,或者稍後從結果中過濾它們。

現在我們從'法線軸'移動到底部,我們需要旋轉並匹配正確的座標,以便正確地包圍邊緣。

由於每側的軸線都摺疊在一個立方體中,某些軸可能需要翻轉或旋轉以選擇正確的點。

問題仍然存在,如果有更好的解決方案可用於選擇區域內的立方體上的所有點。也許我可以給每一方一個翻譯矩陣,並在世界空間測試座標?

+0

你的問題很混亂。這聽起來像是你想從一個立方體的表面上取樣,但除此之外很難理解任何細節。你能給我們一些期望的輸入和輸出的例子嗎?最好使用三維座標來解釋問題(不管你是否會這樣實現)。 – arghbleargh

+0

找到這兩個相關的選擇算法: [鏈接](http://en.wikipedia.org/wiki/Moore_neighborhood) [鏈接](http://en.wikipedia.org/wiki/Von_Neumann_neighborhood) 我是誰試圖圍繞一個空心立方體,其側面接觸但不共享相同的點。 – FreezyExp

回答

0

找到一個相當不錯的解決方案,需要很少的努力來實現。

爲空心立方體創建一個大小爲n + 2的存儲空間,其中n是數據中包含的立方體的大小。這滿足:雙方感動但不重疊或分享某些點。

這將通過創建使用笛卡爾座標的查找數組來簡化計算和翻譯。 使用單個翻譯功能獲取選定點的座標,獲取「世界位置」。

使用該函數我們可以將每個點存儲到笛卡爾查找數組中。當選擇一個點時,我們可以再次使用相同的函數(或使用存儲的數據)並減去(得到AA或最小位置)並添加(得到BB或最大位置)。

然後我們可以查找AA.xyz和BB.xyz座標之間的每個條目。 應該跳過每個空條目。

如果需要,通過使用如果z不是0或大小-1而返回null的數組類型進行優化,因此不需要在中間存儲空心立方體的空引用。

既然立方體可以選擇三維立方體,其他形狀很簡單,給定一個三維點,定義三維形狀並用查找數組測試每個零件的形狀,如果不是零,則將其添加到選區。 每個點只選擇一次,因爲我們只檢查每個位置一次。

由於對立方體內部和外部的空白進行測試,計算開銷很小,但數組訪問速度如此之快,以至於這個解決方案對我當前的項目來說很好。