Home > Back-end >  Rectangle bounds of rotated image
Rectangle bounds of rotated image

Time:09-21

I am drawing an image rotated with Graphics transform, but I am unable to get the position and size of the rotated image.

Paint event:

graphics.TranslateTransform(BaseX, BaseY);
graphics.RotateTransform((float)Rotation);
graphics.DrawImage(Image, X - BaseX, Y - BaseY, Image.Width, Image.Height);

ToRectangle method:

public Rectangle ToRotatedRectangle() {
    // Code here to rotate X, Y, Image.Width and Image.Height values
    return new Rectangle(rotatedX, rotatedY, rotatedWidth, rotatedHeight);
}

I have seen several other posts that can get the rotated size, but none of them include the X and Y values. I have attempted rotating them individually but the location is not correct.

CodePudding user response:

Be careful: 'graphics.RotateTransform(X)' rotates image clockwise X degrees whereas 'Math.Cos(X)' and 'Math.Sin(X)' calculate based on X radians.

Based on your translation/rotation, we can calculate the sin and cos values using trig.

graphics.TranslateTransform(BaseX, BaseY);
graphics.RotateTransform((float)Rotation);

...

var sin = Math.Sin(Rotation * Math.PI / 180.0);
var cos = Math.Cos(Rotation * Math.PI / 180.0);

the resultant graphics matrix is multiplied into any given (X,Y) using linear algebra as follows

// (X, Y) =>
// | cos  -sin  BaseX | | X |   | X*cos-Y*sin BaseX |
// | sin   cos  BaseY | | Y | = | X*sin Y*cos BaseY |
// |  0     0     1   | | 1 |   |        1          |
// => (X*cos-Y*sin BaseX, X*sin Y*cos BaseY)

the 4 corner points as drawn on graphics are:

var (x1, y1) = (X-BaseX, Y-BaseY);
var (x2, y2) = (X-BaseX Image.Width, Y-BaseY);
var (x3, y3) = (X-BaseX, Y-BaseY Image.Height);
var (x4, y4) = (X-BaseX Image.Width, Y-BaseY Image.Height);

thus, after translation/rotation, they become

var (X1, Y1) = (cos*(X-BaseX)-sin*(Y-BaseY) BaseX, sin*(X-BaseX) cos*(Y-BaseY) BaseY);
var (X2, Y2) = (cos*(X-BaseX Image.Width)-sin*(Y-BaseY) BaseX, sin*(X-BaseX Image.Width) cos*(Y-BaseY) BaseY);
var (X3, Y3) = (cos*(X-BaseX)-sin*(Y-BaseY Image.Height) BaseX, sin*(X-BaseX) cos*(Y-BaseY Image.Height) BaseY);
var (X4, Y4) = (cos*(X-BaseX Image.Width)-sin*(Y-BaseY Image.Height) BaseX, sin*(X-BaseX Image.Width) cos*(Y-BaseY Image.Height) BaseY);

To get the top, left corner, you would need the smallest from each X and Y value. The width and height would be the difference between the largest and smallest X's and Y's, which can be simplified as shown below.

var (X, Y) = (Math.Min(Math.Min(X1, X2), Math.Min(X3, X4)), Math.Min(Math.Min(Y1, Y2), Math.Min(Y3, Y4)));
var (Width, Height) = (Math.Abs(cos*Image.Width) Math.Abs(sin*Image.Height), Math.Abs(sin*Image.Width) Math.Abs(cos*Image.Height));
  • Related