2013-09-30 24 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