在其中心旋转图形位图

我正在为学校做一个项目,我们需要在不使用XNA的情况下在C#中进行基本的自上而下的比赛。 首先让我告诉你,到目前为止我们学到的关于编程的东西与制作甚至远程看起来像一场比赛的东西没什么关系。 它没有比数组,循环等更难。所以我们没有学习图形或类似的东西。

说完所有我有以下问题。

我们创建了一个Graphics对象,然后使用DrawImage并使用car.jpg中的位图。

graphics = e.Graphics; graphics.RotateTransform(angle); graphics.DrawImage(car, xPos, yPos, car.Width, car.Height); 

然后我们等待按键,例如右

 case Keys.Right: if (angle != 360) { angle += 10; } else { angle = 0; } this.Refresh(); break; 

我们遇到的问题是旋转的枢轴点位于左上角。 因此,一旦我们将汽车移动到类似(20,25)并开始旋转它,它将使用(0,0)作为旋转中心。 我们想要实现的是将中心旋转点置于汽车的中心位置。

我们一直在尝试寻找改变centerXcenterY的方法,但得出的结论是位图无法实现这一点。 我们一直在努力解决这个问题超过2天,似乎无法找到任何解决方案来实现我们想要的东西。

有没有什么我们在创建Graphics对象时做错了,还是有一种完全不同的方式来改变汽车的centerXcenterY

要绘制旋转的Bitmap您需要执行几个步骤来准备Graphics对象:

  • 首先,将其原点移动到旋转的中点
  • 然后你旋转所需的角度
  • 接下来你把它移回去
  • 现在你可以绘制Bitmap
  • 最后你重置了Graphics

这需要为每个位图完成。

以下是在位置( xPos, yPos )绘制Bitmap bmp代码中的步骤:

 float moveX = bmp.Width / 2f + xPos; float moveY = bmp.Height / 2f+ xPosf; e.Graphics.TranslateTransform(moveX , moveY ); e.Graphics.RotateTransform(angle); e.Graphics.TranslateTransform(-moveX , -moveY ); e.Graphics.DrawImage(bmp, xPos, yPos); e.Graphics.ResetTransform(); 

有一种可能的复杂情况:如果您的Bitmap具有与屏幕不同的dpi分辨率,而不是Graphics您必须首先调整Bitmapdpi设置!

要使Bitmap适应通常的96dpi你可以简单地做一个

 bmp.SetResolution(96,96); 

为了为将来的类视网膜显示做好准备,您可以创建一个在启动时设置的类变量:

 int ScreenDpi = 96; private void Form1_Load(object sender, EventArgs e) { using (Graphics G = this.CreateGraphics()) ScreenDpi = (int)G.DpiX; } 

并在加载Bitmap后使用它:

 bmp.SetResolution(ScreenDpi , ScreenDpi ); 

像往常一样, DrawImage方法使用Bitmap左上角。 您可能需要为旋转点使用不同的Points ,也可能需要使用不同的Points作为汽车的虚拟位置,可能位于其正面的中间位置。

这是静态类,它将在期望区域内的所需位置绘制图像。 更改rotationangle值以旋转图像。 您还可以平移和缩放图像。

在Project中添加此类,并从Win Form调用静态函数。

 public static class FullImage { public static Image image; public static RectangleF DisplayRect, SourceRect; public static Size ParentBoundry; public static float rotationangle=0; internal static void Paint(Graphics graphics) { if (image == null) return; float hw = DisplayRect.X + DisplayRect.Width / 2f; float hh = DisplayRect.Y + DisplayRect.Height / 2f; System.Drawing.Drawing2D.Matrix m = graphics.Transform; m.RotateAt(rotationangle, new PointF(hw, hh), System.Drawing.Drawing2D.MatrixOrder.Append); graphics.Transform = m; graphics.DrawImage(image, new RectangleF(DisplayRect.X, DisplayRect.Y, DisplayRect.Width, DisplayRect.Height), SourceRect, GraphicsUnit.Pixel); graphics.ResetTransform(); } public static void LoadImage(Image img) { image = img; SizeF s = GetResizedSize(image, ParentBoundry); SourceRect = new RectangleF(0, 0, image.Width, image.Height); DisplayRect = new RectangleF(ParentBoundry.Width / 2 - s.Width / 2, ParentBoundry.Height / 2 - s.Height / 2, s.Width, s.Height); } public static Size GetResizedSize(Image ImageToResize, Size size) { int sourceWidth = ImageToResize.Width; int sourceHeight = ImageToResize.Height; float nPercent = 0; float nPercentW = 0; float nPercentH = 0; nPercentW = ((float)size.Width / (float)sourceWidth); nPercentH = ((float)size.Height / (float)sourceHeight); if (nPercentH < nPercentW) nPercent = nPercentH; else nPercent = nPercentW; int destWidth = (int)(sourceWidth * nPercent); int destHeight = (int)(sourceHeight * nPercent); return new Size(destWidth, destHeight); } internal static void MouseWheel(int delta) { if (delta > 0) DisplayRect = ZoomImage(DisplayRect,CurrentMouse, .1f); else DisplayRect = ZoomImage(DisplayRect, CurrentMouse, -.1f); } private RectangleF ZoomImage(RectangleF ImageRectangle, PointF MouseLocation, float ScaleFactor) { /// Original Size and Location SizeF OriginalSize = ImageRectangle.Size; PointF OriginalPoint = ImageRectangle.Location; ///Mouse cursor location -located in width% and height% of totaloriginal image float mouse_widthpercent = System.Math.Abs(OriginalPoint.X - MouseLocation.X) / OriginalSize.Width * 100; float mouse_heightpercent = System.Math.Abs(OriginalPoint.Y - MouseLocation.Y) / OriginalSize.Height * 100; ///Zoomed Image by scalefactor SizeF FinalSize = new SizeF(OriginalSize.Width + OriginalSize.Width * ScaleFactor, OriginalSize.Height + OriginalSize.Height * ScaleFactor); if (FinalSize.Width < 15 || FinalSize.Height < 15) return ImageRectangle; if (FinalSize.Width > 60000 || FinalSize.Height > 60000) return ImageRectangle; /// How much width increases and height increases float widhtincrease = FinalSize.Width - OriginalSize.Width; float heightincrease = FinalSize.Height - OriginalSize.Height; /// Adjusting Image location after zooming the image PointF FinalLocation = new System.Drawing.PointF(OriginalPoint.X - widhtincrease * mouse_widthpercent / 100, OriginalPoint.Y - heightincrease * mouse_heightpercent / 100); ImageRectangle = new RectangleF(FinalLocation.X, FinalLocation.Y, FinalSize.Width, FinalSize.Height); return ImageRectangle; } static bool drag = false; static Point Initial, CurrentMouse; internal static void MouseMove(Point location) { CurrentMouse = location; if (drag) { DisplayRect = new RectangleF(DisplayRect.X + location.X - Initial.X, DisplayRect.Y + location.Y - Initial.Y, DisplayRect.Width, DisplayRect.Height); Initial = location; } } internal static void MouseDown(Point location) { Initial = location; drag = true; } internal static void MouseUp(Point location) { drag = false; } } 

在项目中添加此代码后(更好地添加单独的cs文件),从Win Form类(Form1.cs)调用函数。

 public partial class Form1 : Form { public Form1() { InitializeComponent(); this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true); this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); this.SetStyle(ControlStyles.ResizeRedraw, true); FullImage.ParentBoundry = new Size(this.Width, this.Height); // Enter the image path FullImage.LoadImage(Image.FromFile(@"D:\a.jpg")); } //Create a paint event private void Form1_Paint(object sender, PaintEventArgs e) { FullImage.Paint(e.Graphics); } private void Form1_MouseDown(object sender, MouseEventArgs e) { Vault.FullImage.MouseDown(e.Location); this.Invalidate(); } private void Form1_MouseMove(object sender, MouseEventArgs e) { Vault.FullImage.MouseMove(e.Location); this.Invalidate(); } private void Form1_MouseUp(object sender, MouseEventArgs e) { Vault.FullImage.MouseUp(e.Location); this.Invalidate(); } protected override void OnMouseWheel(MouseEventArgs e) { Vault.FullImage.MouseWheel(e.Delta); this.Invalidate(); } 

现在,如果你想旋转图像,只需设置你想要的值(使用滑块,按钮或添加更多function来检测鼠标移动然后旋转)

示例:添加一个按钮,每次单击按钮时将值增加1。

  private void button1_clicked(object sender, EventArgs e) { FullImage.rotationangle++; this.invalidate(); } 

要从中心旋转左上角,首先需要知道它的角度,然后按所需的角度调整它,然后按新角度重新计算新的左上角:

 var newXPos = (int)(xPos + car.Width / 2.0 + Math.Cos(Math.Atan2(-car.Height / 2, -car.Width / 2) + angle / 180.0 * Math.PI) * -car.Width / 2.0); var newYPos = (int)(yPos + car.Height / 2.0 + Math.Sin(Math.Atan2(-car.Height / 2, -car.Width / 2) + angle / 180.0 * Math.PI) * -car.Height / 2.0); graphics = e.Graphics; graphics.RotateTransform(angle); graphics.DrawImage(car, newXPos, newYPos, car.Width, car.Height);