Rotate the image according to two points

I have two points in my form and a picture, for example:

* [^] [ ] * 

I would like to align the picture with dots so that it looks like this:

 * \^\ \ \ * 

How would I calculate the angle and how would I rotate the PictureBox?

I am currently using this:

 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; 

But this does not work, since the values ​​of x and y are absolute, and therefore they cannot calculate it if point 2 is left from point 1.

To rotate the image, I found the following function:

  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; } 

How to use this feature? I am not sure what values ​​to insert for the offset.

thanks

+7
math c # geometry
source share
2 answers

I do not like to use a corner when it is not necessary.

Here you just want to change the orthonormal basis.

From {X; Y} you want to go to {U; V}, where V (norm 1) is parallel to AB (or point1 point2).

Since {U; V} is an orthonormal basis, Ux = Vy and 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); } } } 
+3
source share

Put all the calculations together.

First of all, the direction of the line connecting the two points can be calculated using

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

Then the vertical direction (90 degrees) should be parallel to the direction discussed above after the rotation, so the rotation angle

 double rotationAngleRadians = angleDegrees - Math.PI/2; 

Having this angle, we can calculate the size of the frame:

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

Now we need to first convert so that the middle of the old image is at position 0. This converts the conversion to (-image.Width/2, -image.Height/2) . Then we apply the rotation to rotationAngleDegrees (which is equal to rotationAngleRadians * 180 / Math.PI ), since Graphics ' rotation expects an angle in degrees. Then we move the image in the middle of the new image, which converts the conversion to (newWidth/2, newHeight/2) .

+2
source share

All Articles