在图形位图的中心旋转图形位图

本文关键字:位图 图形 旋转 | 更新日期: 2023-09-27 18:27:29

我正在为学校做一个项目,我们需要在不使用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)作为旋转中心。我们想要实现的是将旋转的中心点设置在汽车的中心。

我们已经尝试寻找改变RotateTransformcenterXcenterY的方法,但得出的结论是,使用位图是不可能的。我们已经为这个问题挣扎了两天多,似乎找不到任何解决方案来实现我们想要的东西。

是我们在创建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();

有一个可能的复杂情况:如果Bitmapdpi分辨率与屏幕不同,即与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作为旋转点,也可能用于汽车的虚拟位置,可能位于前部的中间。。

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

在您的项目中添加此类,并从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();
    }

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

示例:添加一个按钮,每次单击该按钮都会将值增加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);