Rotate the Graphics bitmap in its center

I am working on a project for school, we need to make a basic game down the race in C # without using XNA. First of all, let me tell you that the material that we learned about programming so far has little to do with creating something that even remotely resembles a race. It has not become more complicated than arrays, loops, etc. Therefore, we did not learn about the schedule or anything like that.

Having said everything, I have the following problem.

We created a Graphics object and then use DrawImage and use a bitmap with car.jpg.

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

Then we wait for the keystroke, for example on the right.

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

The problem is that the pivot point for rotation is in the upper left corner. So, as soon as we move the car to something like (20,25) and begin to rotate it, it will use (0,0) as the center of rotation. What we want to achieve is the center of the center of rotation in the center of our car.

We tried to find ways to change centerX and centerY RotateTransform , but came to the conclusion that this is not possible with a bitmap. We have been struggling with this problem for more than two days and, it seems, cannot find a solution to achieve what we want.

Is there something we are doing wrong when creating a Graphics object, or is there a completely different way to change centerX and centerY for a car?

+8
c # graphics
source share
3 answers

To draw a rotated Bitmap , you need to take a few steps to prepare the Graphics object:

  • first you move your start to the middle of the turn
  • then you turn the right angle
  • then you will return it.
  • now you can draw Bitmap
  • finally you reset Graphics

This must be done for each bitmap.

Below are the code steps for drawing a Bitmap bmp at position ( xPos, yPos ):

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

There is one possible complication: if your Bitmap has a different dpi resolution than the screen, that is, Graphics , you must first set the Bitmap dpi parameter!

To adapt Bitmap to regular 96dpi , you can simply do

 bmp.SetResolution(96,96); 

To prepare for future mesh displays, you can create a class variable that you set at startup:

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

and use it after downloading Bitmap :

 bmp.SetResolution(ScreenDpi , ScreenDpi ); 

As usual, the DrawImage method uses the upper left corner of the Bitmap . You may need to use Points for the pivot point, and possibly also for the virtual position of your car, perhaps in the middle of its front.

+5
source share

Here is a static class that will draw the image in the right place within the desired area. Change the rotation value to rotate the image. You can also pan and zoom the image.

Add this class to your project and call static functions from 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; } } 

After adding this code to the project (it is better to add a separate cs file), call the functions from the Win Form class (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(); } 

Now, if you want to rotate the image, just set the desired value (using the slider, button or add a few more functions to detect mouse movement, and then rotate)

Example: add a button and each time the pressed button increases the value by 1.

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

To rotate the upper left corner from the center, you first need to know its angle, then adjust it to the desired angle and recount the new upper left corner at a new angle:

 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); 
0
source share

All Articles