C# 根据两点旋转图像
我的表格上有两点,还有一个图片盒,像这样:C# 根据两点旋转图像,c#,math,geometry,C#,Math,Geometry,我的表格上有两点,还有一个图片盒,像这样: * [^] [ ] * * \^\ \ \ * 我想将picturebox与点对齐,使其看起来像这样: * [^] [ ] * * \^\ \ \ * 我将如何计算角度以及如何旋转PictureBox 目前我使用的是: double xDifference = Math.Abs(point2.X -
*
[^]
[ ]
*
*
\^\
\ \
*
我想将picturebox与点对齐,使其看起来像这样:
*
[^]
[ ]
*
*
\^\
\ \
*
我将如何计算角度以及如何旋转PictureBox
目前我使用的是:
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;
}
我将如何使用该功能?我不确定要为偏移插入什么值
谢谢让我们把所有的计算放在一起 首先,连接两个点的线的方向可以通过
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。这使得translate变换通过
(-image.Width/2,-image.Height/2)
。然后,我们通过rotationAngleDegrees
(即rotationAngleRadians*180/Math.PI
)应用旋转,因为Graphics
“旋转需要角度(度)。然后,我们将图像移到新图像的中间,即由<代码>(NeWiWeld/ 2,NeWelt/2)< /C> >转换转换。 < P>当不必要时,我不喜欢使用角度。
在这里,你只需要改变正交基
从{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);
}
}
}
使用系统;
使用系统图;
使用System.Drawing.Drawing2D;
使用System.Windows.Forms;
名称空间图表
{
公共部分类CustomControl1:控件
{
私有常量浮点ε=1e-6f;
私人形象"形象;;
私有ImageLayout\u ImageLayout=ImageLayout.Center;
私有点f _pointA=新点f(0,100);
私有点f_pointB=新点f(100,0);
公共CustomControl1()
{
初始化组件();
}
公众形象
{
获取{return\u image;}
设置
{
if(等于(_image,value))返回;
_形象=价值;
使无效();
OnImageChanged(EventArgs.Empty);
}
}
公共事件事件处理程序已更改;
公共图像布局图像布局
{
获取{return\u imageLayout;}
设置
{
if(等于(_imageLayout,value))返回;
_imageLayout=值;
使无效();
OnImageLayoutChanged(EventArgs.Empty);
}
}
公共事件事件处理程序ImageLayoutChanged;
公共点
{
获取{return\u pointA;}
设置
{
if(等于(_pointA,value))返回;
_点A=值;
使无效();
OnPointAChanged(EventArgs.Empty);
}
}
公共事件事件处理程序点已更改;
公共点
{
获取{return\u pointB;}
设置
{
if(等于(_pointB,value))返回;
_点B=值;
使无效();
OnPointBChanged(EventArgs.Empty);
}
}
公共事件EventHandler PointB已更改;
受保护的覆盖无效OnPaint(PaintEventArgs pe)
{
基础漆(pe);
如果(设计模式)返回;
var g=pe.图形;
g、 清晰(背景色);
var图像=图像;
if(image==null)返回;
var clientRectangle=clientRectangle;
var centerX=clientRectangle.X+clientRectangle.Width/2;
变量centerY=clientRectangle.Y+clientRectangle.Height/2;
var srcRect=新矩形(新点(0,0),image.Size);
var pointA=pointA;
var pointB=pointB;
//计算U,AB向量归一化。
var vx=点B.X-点A.X;
var vy=点B.Y-点A.Y;
变量长度=(浮点)数学Sqrt(vx*vx+vy*vy);
if(长度<ε)
{
vx=0;
vy=1;
}
其他的
{
vx/=V长度;
vy/=v长度;
}
var-oldTransform=g.变换;
//将基准更改为U,V
//我们还考虑了屏幕Y上的反转。
g、 变换=新矩阵(-vy,vx,-vx,-vy,centerX,centerY);
var imageWidth=image.Width;
var imageHeight=image.Height;
矩形破坏;
开关(图像布局)
{
案例图像布局。无:
destRect=新矩形(0,0,imageWidth,imageHeight);
打破
案例图像布局。中心:
destRect=新矩形(-imageWidth/2,-imageHeight/2,imageWidth,imageHeight);
打破
案例图像布局。缩放:
//图像的XY对齐边界大小。
var imageXSize=imageWidth*Math.Abs(vy)+imageHeight*Math.Abs(vx);
var imageYSize=imageWidth*Math.Abs(vx)+imageHeight*Math.Abs(vy);
//获得适合的最佳比例。
var s=Math.Min(clientRectangle.Width/imageXSize,clientRectangle.Height/imageYSize);
destRect=新矩形F(-imageWidth*s/2,-imageHeight*s/2,imageWidth*s,imageHeight*s);
打破
违约:
抛出新的