2014-12-18 2 views
7

점하고있는 PictureBox에 따라 이미지를 회전 :은 다음과 같이 두 개의 내 양식에 두 점을

* 

    [^] 
    [ ] 

      * 
나는 그것이 다음과 같습니다 있도록 포인트와의 PictureBox를 정렬하고 싶은

:

* 

    \^\ 
    \ \ 

      * 

어떻게 각도를 계산하고 PictureBox를 회전시킬 수 있습니까? 현재 내가 이것을 사용하고

: x와 y 값은 절대 때문에

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; 

는하지만 작동하지 않습니다, 그리고 점 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; 
    } 

가 어떻게 그 기능을 사용

:

이미지를 회전하려면, 나는 다음과 같은 기능을 발견? 오프셋 값을 삽입 할 값을 모르겠습니다.

감사합니다.

+2

나는 "그림"을 좋아한다. – PiotrWolkowski

+2

먼저 abs를 사용하지 말고'Math.Atan2'를 사용해야합니다. – Vlad

+0

둘째, 어느 지점을 중심으로 회전하고 싶습니까? 이미지의 중심에 대해서는 오프셋이 있어야합니다 ('-image.Width/2, -image.Height/2'). – Vlad

답변

2

모든 계산을합시다. 모든

우선이 두 점을 연결하는 선 방향이

double xDifference = point2.X - point1.X; 
double yDifference = point2.Y - point1.Y; 

double angleRadians = Math.Atan2(yDifference, xDifference); 

의해 계산 될 수있다 다음으로, 수직 방향 (90 °)이 있으므로, 회전 후 상기 고려 된 방향과 평행하게해야

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)); 
: 회전 각도가이 각도를 갖는

double rotationAngleRadians = angleDegrees - Math.PI/2; 

, 우리는 경계 상자의 크기를 계산할 수 있습니다3210

이제 이미지의 중간 부분이 위치 0에 위치하도록 변환해야합니다. 그러면 변환이 (-image.Width/2, -image.Height/2)으로 변환됩니다. 그런 다음 rotationAngleDegrees (rotationAngleRadians * 180/Math.PI)으로 회전을 적용합니다 (Graphics '각도는도를 필요로 함). 그런 다음 이미지가 이미지의 중간에 위치하도록 변환합니다. 즉, 변환 변환은 (newWidth/2, newHeight/2)입니다.

3

필자는 각도를 사용하지 않는 것이 좋습니다.

여기서 정규직 단위를 변경하기 만하면됩니다.

{X; Y}에서 {U; V}로 이동하고 V (노멀 1)는 AB (또는 point1 point2)와 평행합니다.

{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); 
     } 
    } 
} 
관련 문제