如何在c#中旋转3D数组?

时间:2013-09-30 14:30:22

标签: c# multidimensional-array rotation

我在原点(0,0,0)中的3d数组中有一个二进制对象。我需要在z轴上以动态方式旋转此对象。如何在任何角度旋转没有固定大小的多维数组?

我创建了一个3d Point类:

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);
}

有什么建议吗?

3 个答案:

答案 0 :(得分:4)

colud创建一个例程,使用参数方程旋转每个点来旋转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 :(得分:2)

您需要知道要旋转的轴。但如果这只是一个值得关注的问题。 (名称空间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);
}

答案 2 :(得分:1)

所以你有一个“单色物体”,它就像一个你想围绕Z轴旋转的3D位图一样存储。您必须首先了解在经过多次旋转之后,您最终会因为使用array index而导致光学像差,而double是表示对象组件坐标的自然数。

旋转后,任何整数值很可能会变成无理数。传统上(不是在谈论特殊程序和框架)人们在floatdecimalarray index变量中存储无理数的近似值这一事实(它只能存储有理数的一小部分)通过将它存储在一个整数(Point3)中,将与无理数的近似值进行比较。

此外,即使质量损失如果在您的应用中不重要,您必须确保从数学上讲,在经过多次旋转之后,您的3d形状将由刻有圆柱的圆柱修剪。在原始的平行六面体中,沿着Z轴。

就是这样。你说你已经创建了一个名为public class Point3 { public double X { get; set; } public double Y { get; set; } public double Z { get; set; } } 的课程:

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;
    }

    ...
}

也许您应该遵循@Jeroen van Langen的建议并使用标准类,如果这样的类已经存在的话。好处是,如果有人已经建立或将要构建使用该类的库,您可以立即开始使用该库。 但是现在这不是那么重要。

@Alpert已经为围绕oZ轴旋转一个点提供了一个很棒的C#代码。这是该代码的n“扩展方法”改编:

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);
    }

    ...

}

您可以更进一步,制作一个可以围绕oZ轴旋转一系列点的扩展方法:

int[,,] matrix;

现在你说你有一个带有1和0的3d基元矩阵:

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 }; } } ... } 矩阵。

可以这样实现(请记住我之前谈到的质量损失):

Point3

这将占用WIDTH x HEIGHT x DEPTH矩阵中的所有单元格,对于不等于0的每个单元格,它将生成一个具有该特定位置坐标的新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; } } ... } 实例序列“渲染”回到数组中: / p>

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

要将其包装起来,您可以使用以下所有方法:

{{1}}