// COPYRIGHT (C) Tom. ALL RIGHTS RESERVED. // THE AntdUI PROJECT IS AN WINFORM LIBRARY LICENSED UNDER THE Apache-2.0 License. // LICENSED UNDER THE Apache License, VERSION 2.0 (THE "License") // YOU MAY NOT USE THIS FILE EXCEPT IN COMPLIANCE WITH THE License. // YOU MAY OBTAIN A COPY OF THE LICENSE AT // // http://www.apache.org/licenses/LICENSE-2.0 // // UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING, SOFTWARE // DISTRIBUTED UNDER THE LICENSE IS DISTRIBUTED ON AN "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // SEE THE LICENSE FOR THE SPECIFIC LANGUAGE GOVERNING PERMISSIONS AND // LIMITATIONS UNDER THE License. // GITEE: https://gitee.com/antdui/AntdUI // GITHUB: https://github.com/AntdUI/AntdUI // CSDN: https://blog.csdn.net/v_132 // QQ: 17379620 using System; using System.Drawing; using System.Windows.Forms; namespace AntdUI { public class Cube { public int width = 0; public int height = 0; public int depth = 0; double xRotation = 0.0; double yRotation = 0.0; double zRotation = 0.0; Math3D.Camera camera1 = new Math3D.Camera(); Math3D.Point3D cubeOrigin; public Point a, b, c, d; public double RotateX { get { return xRotation; } set { xRotation = value; } } public double RotateY { get { return yRotation; } set { yRotation = value; } } public double RotateZ { get { return zRotation; } set { zRotation = value; } } public Cube(int Width, int Height, int Depth) { width = Width; height = Height; depth = Depth; cubeOrigin = new Math3D.Point3D(width / 2, height / 2, depth / 2); } public static Rectangle getBounds(PointF[] points) { double left = points[0].X; double right = points[0].X; double top = points[0].Y; double bottom = points[0].Y; for (int i = 1; i < points.Length; i++) { if (points[i].X < left) left = points[i].X; if (points[i].X > right) right = points[i].X; if (points[i].Y < top) top = points[i].Y; if (points[i].Y > bottom) bottom = points[i].Y; } return new Rectangle(0, 0, (int)Math.Round(right - left), (int)Math.Round(bottom - top)); } public void calcCube(Point drawOrigin) { var point3D = new PointF[24]; var tmpOrigin = new Point(0, 0); var point0 = new Math3D.Point3D(0, 0, 0); double zoom = Screen.PrimaryScreen.Bounds.Width / 1.5D; var cubePoints = fillCubeVertices(width, height, depth); var anchorPoint = cubePoints[4]; double cameraZ = -(((anchorPoint.X - cubeOrigin.X) * zoom) / cubeOrigin.X) + anchorPoint.Z; camera1.Position = new Math3D.Point3D(cubeOrigin.X, cubeOrigin.Y, cameraZ); cubePoints = Math3D.Translate(cubePoints, cubeOrigin, point0); cubePoints = Math3D.RotateX(cubePoints, xRotation); cubePoints = Math3D.RotateY(cubePoints, yRotation); cubePoints = Math3D.RotateZ(cubePoints, zRotation); cubePoints = Math3D.Translate(cubePoints, point0, cubeOrigin); Math3D.Point3D vec; for (int i = 0; i < point3D.Length; i++) { vec = cubePoints[i]; if (vec.Z - camera1.Position.Z >= 0) { point3D[i].X = (int)((double)-(vec.X - camera1.Position.X) / (-0.1F) * zoom) + drawOrigin.X; point3D[i].Y = (int)((double)(vec.Y - camera1.Position.Y) / (-0.1F) * zoom) + drawOrigin.Y; } else { tmpOrigin.X = (int)((double)(cubeOrigin.X - camera1.Position.X) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.X; tmpOrigin.Y = (int)((double)-(cubeOrigin.Y - camera1.Position.Y) / (double)(cubeOrigin.Z - camera1.Position.Z) * zoom) + drawOrigin.Y; point3D[i].X = (float)((vec.X - camera1.Position.X) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.X); point3D[i].Y = (float)(-(vec.Y - camera1.Position.Y) / (vec.Z - camera1.Position.Z) * zoom + drawOrigin.Y); point3D[i].X = (int)point3D[i].X; point3D[i].Y = (int)point3D[i].Y; } } a = Point.Round(point3D[4]); b = Point.Round(point3D[5]); c = Point.Round(point3D[6]); d = Point.Round(point3D[7]); } public PointF Centre() { return new PointF(CX, CY); } public PointF CentreY() { return new PointF(d.X + width / 2F, CY); } public PointF CentreX() { return new PointF(CX, d.Y + height / 2F); } public float CY { get { if (a.Y < d.Y) return a.Y + height / 2F; else return d.Y + height / 2F; } } public float CX { get { if (c.X < d.X) return c.X + width / 2F; else return d.X + width / 2F; } } public static Math3D.Point3D[] fillCubeVertices(int width, int height, int depth) { return new Math3D.Point3D[]{ //front face new Math3D.Point3D(0, 0, 0), new Math3D.Point3D(0, height, 0), new Math3D.Point3D(width, height, 0), new Math3D.Point3D(width, 0, 0), //back face new Math3D.Point3D(0, 0, depth), new Math3D.Point3D(0, height, depth), new Math3D.Point3D(width, height, depth), new Math3D.Point3D(width, 0, depth), //left face new Math3D.Point3D(0, 0, 0), new Math3D.Point3D(0, 0, depth), new Math3D.Point3D(0, height, depth), new Math3D.Point3D(0, height, 0), //right face new Math3D.Point3D(width, 0, 0), new Math3D.Point3D(width, 0, depth), new Math3D.Point3D(width, height, depth), new Math3D.Point3D(width, height, 0), //top face new Math3D.Point3D(0, height, 0), new Math3D.Point3D(0, height, depth), new Math3D.Point3D(width, height, depth), new Math3D.Point3D(width, height, 0), //bottom face new Math3D.Point3D(0, 0, 0), new Math3D.Point3D(0, 0, depth), new Math3D.Point3D(width, 0, depth), new Math3D.Point3D(width, 0, 0), }; } public Bitmap ToBitmap(Bitmap bmp) { var vertex = new PointF[] { d, a, b, c }; using (var srcCB = new ImageData()) { srcCB.FromBitmap(bmp); int srcH = bmp.Height, srcW = bmp.Width; #region setVertex float xmin = float.MaxValue; float ymin = xmin; float xmax = float.MinValue; float ymax = xmax; for (int i = 0; i < 4; i++) { xmax = Math.Max(xmax, vertex[i].X); ymax = Math.Max(ymax, vertex[i].Y); xmin = Math.Min(xmin, vertex[i].X); ymin = Math.Min(ymin, vertex[i].Y); } var rect = new Rectangle((int)xmin, (int)ymin, (int)(xmax - xmin), (int)(ymax - ymin)); Vector AB = new Vector(vertex[0], vertex[1]), BC = new Vector(vertex[1], vertex[2]), CD = new Vector(vertex[2], vertex[3]), DA = new Vector(vertex[3], vertex[0]); AB /= AB.Magnitude; BC /= BC.Magnitude; CD /= CD.Magnitude; DA /= DA.Magnitude; #endregion #region 返回 using (var destCB = new ImageData()) { destCB.A = new byte[rect.Width, rect.Height]; destCB.B = new byte[rect.Width, rect.Height]; destCB.G = new byte[rect.Width, rect.Height]; destCB.R = new byte[rect.Width, rect.Height]; var ptInPlane = new PointF(); int x1, x2, y1, y2; double dab, dbc, dcd, dda; float dx1, dx2, dy1, dy2, dx1y1, dx1y2, dx2y1, dx2y2, nbyte; int y = 0, x; while (++y < rect.Height) { x = 0; while (++x < rect.Width) { var srcPt = new Point(x, y); srcPt.Offset(rect.Location); if ((!Vector.IsCCW(srcPt, vertex[0], vertex[1])) && (!Vector.IsCCW(srcPt, vertex[1], vertex[2])) && (!Vector.IsCCW(srcPt, vertex[2], vertex[3])) && (!Vector.IsCCW(srcPt, vertex[3], vertex[0]))) { dab = Math.Abs((new Vector(vertex[0], srcPt)).CrossProduct(AB)); dbc = Math.Abs((new Vector(vertex[1], srcPt)).CrossProduct(BC)); dcd = Math.Abs((new Vector(vertex[2], srcPt)).CrossProduct(CD)); dda = Math.Abs((new Vector(vertex[3], srcPt)).CrossProduct(DA)); ptInPlane.X = (float)(srcW * (dda / (dda + dbc))); ptInPlane.Y = (float)(srcH * (dab / (dab + dcd))); x1 = (int)ptInPlane.X; y1 = (int)ptInPlane.Y; if (x1 >= 0 && x1 < srcW && y1 >= 0 && y1 < srcH) { x2 = (x1 == srcW - 1) ? x1 : x1 + 1; y2 = (y1 == srcH - 1) ? y1 : y1 + 1; dx1 = ptInPlane.X - x1; if (dx1 < 0) dx1 = 0; dx1 = 1f - dx1; dx2 = 1f - dx1; dy1 = ptInPlane.Y - y1; if (dy1 < 0) dy1 = 0; dy1 = 1f - dy1; dy2 = 1f - dy1; dx1y1 = dx1 * dy1; dx1y2 = dx1 * dy2; dx2y1 = dx2 * dy1; dx2y2 = dx2 * dy2; nbyte = srcCB.A[x1, y1] * dx1y1 + srcCB.A[x2, y1] * dx2y1 + srcCB.A[x1, y2] * dx1y2 + srcCB.A[x2, y2] * dx2y2; destCB.A[x, y] = (byte)nbyte; nbyte = srcCB.B[x1, y1] * dx1y1 + srcCB.B[x2, y1] * dx2y1 + srcCB.B[x1, y2] * dx1y2 + srcCB.B[x2, y2] * dx2y2; destCB.B[x, y] = (byte)nbyte; nbyte = srcCB.G[x1, y1] * dx1y1 + srcCB.G[x2, y1] * dx2y1 + srcCB.G[x1, y2] * dx1y2 + srcCB.G[x2, y2] * dx2y2; destCB.G[x, y] = (byte)nbyte; nbyte = srcCB.R[x1, y1] * dx1y1 + srcCB.R[x2, y1] * dx2y1 + srcCB.R[x1, y2] * dx1y2 + srcCB.R[x2, y2] * dx2y2; destCB.R[x, y] = (byte)nbyte; } } } } return destCB.ToBitmap(); } } #endregion } } }