/// <Summary>

/// Creates a new image containing the same image only rotated

/// </Summary>

/// <Param name = "image"> the <see CREF = "system. Drawing. Image"/> to rotate </param>

/// <Param name = "angle"> The amount to rotate the image, clockwise, in degrees </param>

/// <Returns> A new <see CREF = "system. Drawing. Bitmap"/> that is just large enough

/// To contain the rotated image without cutting any corners off. </returns>

/// <Exception CREF = "system. argumentnullexception"> thrown if <see CREF = "image"/> is null. </exception>

Public static bitmap rotateimage (image, float angle)

{

If (image = NULL)

Throw new argumentnullexception ("image ");

Const double Pi2 = math. pi/ 2.0;

// Why can't C # allow these to be const, or at least readonly

// * Sigh * I'm starting to talk like Christian graus: OMG:

Double oldwidth = (double) image. width;

Double oldheight = (double) image. height;

// Convert degrees to radians

Double Theta = (double) angle) * Math. PI/180.0;

Double locked_theta = Theta;

// Ensure Theta is now [0, 2PI)

While (locked_theta <0.0)

Locked_theta + = 2 * Math. Pi;

Double newwidth, newheight;

Int nwidth, nheight; // The newwidth/newheight expressed as ints

# Region explaination of the calculations

/**//*

* The trig involved in calculating the new width and height

* Is fairly simple; the hard part was remembering that when

* PI/2 <= Theta <= PI and 3pi/2 <= Theta <2PI the width and

* Height are switched.

*

* When you rotate a rectangle, R, the bounding box surrounding R

* Contains for right-triangles of empty space. Each of

* Triangles hypotenuse's are a known length, either the width or

* The height of R. Because we know the length of the hypotenuse

* And we have a known angle of rotation, we can use the trig

* Function identities to find the length of the other two sides.

*

* Sine = opposite/hypotenuse

* Cosine = adjacent/hypotenuse

*

* Solving for the unknown we get

*

* Opposite = sine * hypotenuse

* Adjacent = cosine * hypotenuse

*

* Another interesting point about these triangles is that there

* Are only two different triangles. The proof for which is easy

* To see, but its been too long since I 've written a proof that

* I can't explain it well enough to want to publish it.

*

* Just trust me when I say the triangles formed by the lengths

* Width are always the same (for a given theta) and the same

* Goes for the height of R.

*

* Rather than associate the opposite/adjacent sides with

* Width and height of the original bitmap, I'll associate them

* Based on their position.

*

* Adjacent/oppositetop will refer to the triangles making up

* Upper right and lower left corners

*

* Adjacent/oppositebottom will refer to the triangles making up

* The upper left and lower right corners

*

* The names are based on the right side corners, because thats

* Where I did my work on paper (the right side ).

*

* Now if you draw this out, you will see that the width of

* Bounding box is calculated by adding together adjacenttop and

* Oppositebottom while the height is calculate by adding

* Together adjacentbottom and oppositetop.

*/

# Endregion

Double adjacenttop, oppositetop;

Double adjacentbottom, oppositebottom;

// We need to calculate the sides of the triangles based

// On how much rotation is being done to the bitmap.

// Refer to the first paragraph in the explaination above

// Reasons why.

If (locked_theta >=0.0 & locked_theta <Pi2) |

(Locked_theta> = math. Pi & locked_theta <(math. PI + Pi2 )))

{

Adjacenttop = math. Abs (math. Cos (locked_theta) * oldwidth;

Oppositetop = math. Abs (math. Sin (locked_theta) * oldwidth;

Adjacentbottom = math. Abs (math. Cos (locked_theta) * oldheight;

Oppositebottom = math. Abs (math. Sin (locked_theta) * oldheight;

}

Else

{

Adjacenttop = math. Abs (math. Sin (locked_theta) * oldheight;

Oppositetop = math. Abs (math. Cos (locked_theta) * oldheight;

Adjacentbottom = math. Abs (math. Sin (locked_theta) * oldwidth;

Oppositebottom = math. Abs (math. Cos (locked_theta) * oldwidth;

}

Newwidth = adjacenttop + oppositebottom;

Newheight = adjacentbottom + oppositetop;

Nwidth = (INT) math. Ceiling (newwidth );

Nheight = (INT) math. Ceiling (newheight );

Bitmap rotatedbmp = new Bitmap (nwidth, nheight );

Using (Graphics G = graphics. fromimage (rotatedbmp ))

{

// This array will be used to pass in the three points that

// Make up the rotated image

Point [] points;

/**//*

* The values of opposite/adjacenttop/bottom are referring

* Fixed locations instead of in relation to

* Rotating image so I need to change which values are used

* Based on the how much the image is rotating.

*

* For each point, one of the coordinates will always be 0,

* Nwidth, or nheight. This because the bitmap we are drawing on

* Is the bounding box for the rotated bitmap. If both of

* Corrdinates for any of the given points wasn't in the set above

* Then the bitmap we are drawing on wouldn't be the bounding box

* As required.

*/

If (locked_theta >=0.0 & locked_theta <Pi2)

{

Points = new point [] {

New Point (INT) oppositebottom, 0 ),

New Point (nwidth, (INT) oppositetop ),

New Point (0, (INT) adjacentbottom)

};

}

Else if (locked_theta> = Pi2 & locked_theta <math. Pi)

{

Points = new point [] {

New Point (nwidth, (INT) oppositetop ),

New Point (INT) adjacenttop, nheight ),

New Point (INT) oppositebottom, 0)

};

}

Else if (locked_theta> = math. Pi & locked_theta <(math. PI + Pi2 ))

{

Points = new point [] {

New Point (INT) adjacenttop, nheight ),

New Point (0, (INT) adjacentbottom ),

New Point (nwidth, (INT) oppositetop)

};

}

Else

{

Points = new point [] {

New Point (0, (INT) adjacentbottom ),

New Point (INT) oppositebottom, 0 ),

New Point (INT) adjacenttop, nheight)

};

}

G. drawimage (image, points );

}

Return rotatedbmp;

}