2013-09-30 88 views
0

我有在位於原點(0,0,0)以3D陣列的二進制對象。我需要在z軸上旋轉此對象。如何以任何角度旋轉沒有固定大小的多維數組?如何在c#中旋轉3D數組?

我創建了一個三維點類:

public class Point3 
{ 
    public double X { get; set; } 
    public double Y { get; set; } 
    public double Z { get; set; } 
} 

我想在做一個foreach中的每個點,並將其旋轉:

foreach (Point3 p in listPoint3) 
{ 
    RotatePoint(p, angle); 
} 

什麼建議嗎?

+0

你是什麼意思「沒有固定大小的多維數組」。你正在使用「那個」,就好像你指的是前面描述的那樣。請說明「3D陣列」的含義。您不需要等級爲3的原始數組來存儲設計時未知數量的頂點。你的意思是一個以空間起源爲中心的想象約束框? 「二元對象」是什麼意思? –

+0

@EduardDumitru多維數組可以具有任意大小,例如[10,20,40]或[40,35,70],沒有固定大小。它指的是3d數組中的對象。是的,我想象的是空間中心的物體。二進制對象意味着一個只有0或1的數組,因爲一個數組只是一個立方體,但在它內部我可以繪製任何東西。 – Butzke

+0

所以三維原始數組包含0和1,1意味着那裏有東西,0意味着那裏什麼也沒有。我是否正確?如果我得到了正確的答案,你是否意識到沒有人能從你的問題中理解這一點?此外,如果我說得對,那有點「密集」。您以非矢量方式存儲3d形狀,這自然會導致很多問題。你可以旋轉這樣一個對象,但是你會失去解析力(很多)。你爲什麼創建'Point3'類(這是更好的)。你的3d矩陣和'Point3'之間有什麼關係? –

回答

2

你需要知道什麼軸要旋轉的。但是,如果這只是一個問題,那麼可以看看。 空間(namespace System.Windows.Media.Media3D)

你可以試試這個:

double angle = 45; 

RotateTransform3D zrotation = new RotateTransform3D(new AxisAngleRotation3D(
            new Vector3D(0, 0, 1), angle)); 

foreach (Point3D p in listPoint3) 
{ 
    Point3D rotatedPoint = zrotation.Transform(p); 
} 

,如果你想這些堆棧您應該使用內置的Point3D

另外:(多個變換)

double zAngle = 45; 
double xAngle = 10; 

Transform3DGroup group = new Transform3DGroup(); 
group.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), xAngle))); 
group.Children.Add(new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 0, 1), zAngle))); 

foreach (Point3D p in listPoint3) 
{ 
    Point3D rotatedPoint = group.Transform(p); 
} 
4

您colud創建一個程序來ROTAT e使用參數方程旋轉3d對象的每個點。

X '= X * COS(O)-Y * SIN(O)

Y'= Y * SIN(O)-Y * COS(O)

Z」 = Z

private Point3 RotatePoint(Point3 p0, int angle) 
{ 
    Point3 p = new Point3() 
    { 
     X = p0.X * Math.Cos(angle) - p0.Y * Math.Sin(angle), 
     Y = p0.X * Math.Sin(angle) + p0.Y * Math.Cos(angle), 
     Z = p0.Z, 
    }; 

    return p; 
} 
1

所以,你必須是存儲像要繞Z軸旋轉的3D位圖「單色對象」。你必須先了解一個轉數後,你將最終造成事實上的光學像差,您使用的array index這是一個自然數表示對象的零部件的座標。

在旋轉時的任何整數值將最有可能成爲一個無理數。傳統上(不是談論特殊程序和框架)的人存儲無理數的近似值doublefloatdecimal變量(它只能存儲有理數集的一小部分)是沒有什麼相比於近似的通過將其存儲在一個整數(一個array index)中來表示無理數。此外,即使質量損失如果對於您的應用沒有太大的重要性,您也一定要明白從數學角度而言,經過多次旋轉後,您的3d形狀將被滾筒修剪刻在原來的平行六面體中,沿着Z軸。

它是這樣的。你說你已經做了一個名爲Point3類:

public class Point3 { 
    public double X { get; set; } 
    public double Y { get; set; } 
    public double Z { get; set; } 
} 

也許你應該遵循@Jeroen麪包車蘭根的意見,並使用標準的類,如果這樣的類已經存在。好處是,如果有人已經建立或將要建立一個使用該類的圖書館,你可以立即開始使用圖書館。 但現在並不那麼重要。

@Alpert已經給出了一個很棒的C#代碼來圍繞oZ軸旋轉一個點。這是代碼的N「擴展方法」改編:

public static class RotationHelpers { 

    public static Point3 RotatePoint(this Point3 point, int angle) { 
     var result = new Point3() { 
      X = point.X * Math.Cos(angle) - point.Y * Math.Sin(angle), 
      Y = point.X * Math.Sin(angle) + point.Y * Math.Cos(angle), 
      Z = point.Z, 
     }; 
     return result; 
    } 

    ... 
} 

你可以更進一步,使這些轉動點繞OZ軸序列擴展方法:

public static class RotationHelpers { 

    ... 

    public static IEnumerable<Point3> RotatePoints(this IEnumerable<Point3> points, int angle) { 
     foreach (var point in points) 
      yield return point.RotatePoint(angle); 
    } 

    ... 

} 

現在你說你有1和0三維矩陣的本原它:

int[,,] matrix; 

你需要以某種方式轉換的本質定義的點,並且矩陣爲Point3實例的序列,旋轉次然後將結果序列轉換回int[,,]矩陣。

可以像這樣來實現(記住質量的損失我早先提到):

public static class RotationHelpers { 

    ... 

    public static IEnumerable<Point3> ToPoints(this int[,,] matrix) { 
     int lx = matrix.GetLength(0); 
     int ly = matrix.GetLength(1); 
     int lz = matrix.GetLength(2); 

     for (int x = 0; x < lx; x++) 
     for (int y = 0; y < ly; y++) 
     for (int z = 0; z < lz; z++) { 

      bool is1 = matrix[x, y, z] != 0;  
      if (is1) 
       yield return new Point3 { 
        X = x - lx/2, 
        Y = y - ly/2, 
        Z = z - lz/2 
       }; 

     } 
    } 

    ... 

} 

這將需要所有的細胞在寬x高x深矩陣和每個不等於0的單元格將產生具有該特定位置的座標的新實例Point3

該序列可以然後通過使用先前描述RotatePoints方法,然後可用於「渲染」背所得Point3實例的序列爲陣列的以下方法的角度旋轉:

public static class RotationHelpers { 

    ... 

    public static void AssignPoints(this int[,,] matrix, IEnumerable<Point3> points) { 
     int lx = matrix.GetLength(0); 
     int ly = matrix.GetLength(1); 
     int lz = matrix.GetLength(2); 

     for (int x = 0; x < lx; x++) 
     for (int y = 0; y < ly; y++) 
     for (int z = 0; z < lz; z++) 
      matrix[x, y, z] = 0; 

     foreach (var point in points) { 
      // this is when quality is lost, because things like 1.7 and 1.71 
      // will both become =2 

      var x = (int)Math.Round(point.X) + lx/2; 
      var y = (int)Math.Round(point.Y) + ly/2; 
      var z = (int)Math.Round(point.Z) + lz/2; 

      // this is where you loose parts of the object because 
      // it doesn't fit anymore inside the parallelepiped 
      if ((x >= 0) && (y >= 0) && (z >= 0) && 
       (x < lx) && (y < ly) && (z < lz)) 
       matrix[x, y, z] = 1; 
     } 
    } 

    ... 

} 

要把它包起來,你可以像這樣使用所有這些方法:

int[,,] matrix = ... 
int angle = ... 

IEnumerable<Point3> points = matrix.ToPoints(); 
IEnumerable<Point3> rotatedPoints = points.RotatePoints(angle); 

matrix.AssignPoints(rotatedPoints); 
// now you have the original matrix, rotated by angle