根据两个点旋转图像

本文关键字:两个 旋转 图像 | 更新日期: 2023-09-27 18:34:33

我的表格上有两个点,还有一个图片框,像这样:

*
   [^]
   [ ]
          *

我想将图片框与点对齐,使其看起来像这样:

*
   '^'
    ' '
          *

我将如何计算角度以及如何旋转图片框?

目前我正在使用这个:

double xDifference = Math.Abs(point2.X - point1.X);
double yDifference = Math.Abs(point2.Y - point1.Y);
double angle = Math.Atan(yDifference / xDifference) * 180 / Math.PI;

但这不起作用,因为 x 和 y 值是绝对值,因此如果点 2 在点 1 的剩余部分,他们无法计算它。

为了旋转图像,我找到了以下功能:

    public Bitmap rotateImage(Image image, PointF offset, float angle) {
        // Create a new empty bitmap to hold rotated image
        Bitmap rotatedBmp = new Bitmap(image.Width, image.Height);
        rotatedBmp.SetResolution(image.HorizontalResolution, image.VerticalResolution);
        // Make a graphics object from the empty bitmap
        Graphics g = Graphics.FromImage(rotatedBmp);
        // Put the rotation point in the center of the image
        g.TranslateTransform(offset.X, offset.Y);
        // Rotate the image
        g.RotateTransform(angle);
        // Move the image back
        g.TranslateTransform(-offset.X, -offset.Y);
        // Draw passed in image onto graphics object
        g.DrawImage(image, new PointF(0, 0));
        return rotatedBmp;
    }

我将如何使用该功能?我不确定要插入哪些值进行偏移。

谢谢

根据两个点旋转图像

我不喜欢在不必要的情况下使用角度。

在这里,您只想更改正交基础。

从 {X;Y} 移动到 {U;V},其中 V(范数 1(平行于 AB(或点 1 点 2(。

因为{U;V} 是正交基,Ux = Vy 和 Uy = -Vx。

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace CsiChart
{
    public partial class CustomControl1 : Control
    {
        private const float EPSILON = 1e-6f;
        private Image _image;
        private ImageLayout _imageLayout = ImageLayout.Center;
        private PointF _pointA = new PointF(0, 100);
        private PointF _pointB = new PointF(100, 0);
        public CustomControl1()
        {
            InitializeComponent();
        }
        public Image Image
        {
            get { return _image; }
            set
            {
                if (Equals(_image, value)) return;
                _image = value;
                Invalidate();
                OnImageChanged(EventArgs.Empty);
            }
        }
        public event EventHandler ImageChanged;
        public ImageLayout ImageLayout
        {
            get { return _imageLayout; }
            set
            {
                if (Equals(_imageLayout, value)) return;
                _imageLayout = value;
                Invalidate();
                OnImageLayoutChanged(EventArgs.Empty);
            }
        }
        public event EventHandler ImageLayoutChanged;
        public PointF PointA
        {
            get { return _pointA; }
            set
            {
                if (Equals(_pointA, value)) return;
                _pointA = value;
                Invalidate();
                OnPointAChanged(EventArgs.Empty);
            }
        }
        public event EventHandler PointAChanged;
        public PointF PointB
        {
            get { return _pointB; }
            set
            {
                if (Equals(_pointB, value)) return;
                _pointB = value;
                Invalidate();
                OnPointBChanged(EventArgs.Empty);
            }
        }
        public event EventHandler PointBChanged;
        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
            if (DesignMode) return;
            var g = pe.Graphics;
            g.Clear(BackColor);         
            var image = Image;
            if (image == null) return;
            var clientRectangle = ClientRectangle;
            var centerX = clientRectangle.X + clientRectangle.Width / 2;
            var centerY = clientRectangle.Y + clientRectangle.Height / 2;
            var srcRect = new Rectangle(new Point(0, 0), image.Size);
            var pointA = PointA;
            var pointB = PointB;
            // Compute U, AB vector normalized.
            var vx = pointB.X - pointA.X;
            var vy = pointB.Y - pointA.Y;
            var vLength = (float) Math.Sqrt(vx*vx + vy*vy);
            if (vLength < EPSILON)
            {
                vx = 0;
                vy = 1;
            }
            else
            {
                vx /= vLength;
                vy /= vLength;
            }
            var oldTransform = g.Transform;
            // Change basis to U,V
            // We also take into acount the inverted on screen Y.
            g.Transform = new Matrix(-vy, vx, -vx, -vy, centerX, centerY);
            var imageWidth = image.Width;
            var imageHeight = image.Height;
            RectangleF destRect;
            switch (ImageLayout)
            {
                case ImageLayout.None:
                    destRect = new Rectangle(0, 0, imageWidth, imageHeight);
                    break;
                case ImageLayout.Center:
                    destRect = new Rectangle(-imageWidth/2, -imageHeight/2, imageWidth, imageHeight);
                    break;
                case ImageLayout.Zoom:
                    // XY aligned bounds size of the image.
                    var imageXSize = imageWidth*Math.Abs(vy) + imageHeight*Math.Abs(vx);
                    var imageYSize = imageWidth*Math.Abs(vx) + imageHeight*Math.Abs(vy);
                    // Get best scale to fit.
                    var s = Math.Min(clientRectangle.Width/imageXSize, clientRectangle.Height/imageYSize);
                    destRect = new RectangleF(-imageWidth*s/2, -imageHeight*s/2, imageWidth*s, imageHeight*s);
                    break;
                default:
                    throw new InvalidOperationException();
            }
            g.DrawImage(image, destRect, srcRect, GraphicsUnit.Pixel);
            g.Transform = oldTransform;
        }
        protected virtual void OnImageChanged(EventArgs eventArgs)
        {
            var handler = ImageChanged;
            if (handler == null) return;
            handler(this, eventArgs);
        }
        protected virtual void OnImageLayoutChanged(EventArgs eventArgs)
        {
            var handler = ImageLayoutChanged;
            if (handler == null) return;
            handler(this, eventArgs);
        }
        private void OnPointAChanged(EventArgs eventArgs)
        {
            var handler = PointAChanged;
            if (handler == null) return;
            handler(this, eventArgs);
        }
        private void OnPointBChanged(EventArgs eventArgs)
        {
            var handler = PointBChanged;
            if (handler == null) return;
            handler(this, eventArgs);
        }
    }
}

让我们把所有的计算放在一起。

首先,连接两点的线的方向可以计算如下:

double xDifference = point2.X - point1.X;
double yDifference = point2.Y - point1.Y;
double angleRadians = Math.Atan2(yDifference, xDifference);
然后,旋转

后垂直方向(90度(必须与上面考虑的方向平行,因此旋转角度为

double rotationAngleRadians = angleDegrees - Math.PI/2;

有了这个角度,我们可以计算边界框的大小:

double newWidth =  image.Width * Math.Abs(Math.Cos(rotationAngleRadians)) +
                   image.Height * Math.Abs(Math.Sin(rotationAngleRadians));
double newHeight = image.Width * Math.Abs(Math.Sin(rotationAngleRadians)) +
                   image.Height * Math.Abs(Math.Cos(rotationAngleRadians));

现在,我们首先需要以旧图像的中间位于位置 0 的方式进行转换。这使得翻译转换(-image.Width/2, -image.Height/2) .然后,我们应用rotationAngleDegrees旋转(这是rotationAngleRadians * 180 / Math.PI(,因为Graphics旋转期望角度以度为单位。然后,我们将图像移动到图像的中间,即平移变换 (newWidth/2, newHeight/2) .