簡體   English   中英

如何在C#中旋轉3D陣列?

[英]How can I rotate a 3D array in c#?

我在原點(0,0,0)的3d數組中有一個二進制對象。 我需要在z軸上旋轉該對象。 如何以任意角度旋轉沒有固定大小的多維數組?

我創建了一個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);
}

有什么建議嗎?

您可以創建一個例程,使用參數方程式旋轉每個點,以旋轉3d對象。

x'= x * cos(o)-y * sin(o)

y'= y * sin(o)-y * cos(o)

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

您需要知道要在哪個軸上旋轉。 但這只是一個問題,在哪里看。 (命名空間為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);
}

因此,您有一個“單色對象”,該對象存儲為想要繞Z軸旋轉的3D位圖。 您必須首先了解,經過多次旋轉后,由於使用array index這是代表對象組件坐標的自然數)導致的光學像差,最終會導致光學像差。

旋轉時,任何整數值很可能會成為無理數。 傳統上(不是在討論特殊程序和框架)人們將無理數的近似值存儲在double floatfloatdecimal變量中(只能存儲有理數集的一小部分),與無理數的逼近相比沒有任何意義 。通過將其存儲在整數( array index )中。

此外,即使質量損失對您的應用而言並不重要,您也必須確保您了解,從數學上講,經過多次旋轉后,您的3D形狀將被原件上刻有圓柱體進行修剪平行六面體,沿Z軸。

就像這樣 您說您已經制作了一個名為Point3的類:

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

如果已經存在此類,也許您應該遵循@Jeroen van Langen的建議並使用標准類。 好處是,如果有人在那里已經建立或將要建立一個使用該類的庫,則可以立即開始使用該庫。 但這現在還不那么重要。

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

    ...

}

現在您說您有一個3d基本矩陣,其中包含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
                };

        }
    }

    ...

}

這將占用WIDTH x HEIGHT x DEPTH矩陣中的所有像元,並且對於每個不等於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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM