Im trying to rotate a image with matrix object and can't get it right
When i rotate the image i got a black spot, it's one pixel wrong and it's the same with 180 angle and 270 angle.
90 angle ex.
A picture of this problem:
http://www.spasm-design.com/rotate/onePixelWrong.jpg
And here is the code:
public System.Drawing.Image Rotate(System.Drawing.Image image, String angle, String direction)
{
Int32 destW, destH;
float destX, destY, rotate;
destW = image.Width;
destH = image.Height;
destX = destY = 0;
if (r == "90" || r == "270")
{
destW = image.Height;
destH = image.Width;
destY = (image.Width - destW) / 2;
destX = (image.Height - destH) / 2;
}
rotate = (direction == "y") ? float.Parse(angle) : float.Parse("-" + angle);
Bitmap b = new Bitmap(destW, destH, PixelFormat.Format24bppRgb);
b.SetResolution(image.HorizontalResolution, image.VerticalResolution);
Matrix x = new Matrix();
x.Translate(destX, destY);
x.RotateAt(rotate, new PointF(image.Width / 2, image.Height / 2));
Graphics g = Graphics.FromImage(b);
g.PageUnit = GraphicsUnit.Pixel;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.Transform = x;
g.DrawImage(image, 0, 0);
g.Dispose();
x.Dispose();
return b;
}
if someone have a good ide why this is happening please tell me.
Have a good day!
I think you're just getting a rounding error on this line:
x.RotateAt(rotate, new PointF(image.Width / 2, image.Height / 2));
Width and Height are both int properties. Try this instead:
x.RotateAt(rotate, new PointF((float)Math.Floor(image.Width / 2),
(float)Math.Floor(image.Height / 2)));
(Not tested, so not sure if this will work.)
Update: I don't think my above fix will work, but it may point you in the direction of the problem. If you can't fix it by adjusting the rounding, you may just need to change destX to -1 to get rid of the black line.
This works:
x.RotateAt(rotate, new PointF(image.Width / 2, image.Height / 2));
this "image.Width / 2" returns float
First i find out what angle is, if it is 90 or 270 flip the image so image.width = image.height and image.height = width
If a do that i get a problem when i rotate the image for the image width can be bigger then height of the image so then i need to reset the image x,y coordinates to 0,0
So this "destY = (image.Width - destW) / 2;" calculate offset of the image to the bitmap
and this "x.Translate(destX, destY);" set the image x equivalent to bitmap x
but something is going wrong for the rotation makes picture 1px to small.
so for my english but im not the best of it, i hope you can read it any why :)
for more questions please send me those and i'm going to try explain what i mean.
A much simpler solution is:
Add one pixel around the image.
Rotate the image.
Remove the one pixel.
Code:
// h and w are the width/height
// cx and cy are the centre of the image
myBitmap = new Bitmap(w + 2, h + 2);
mygraphics = Graphics.FromImage(myBitmap);
mygraphics.TranslateTransform(cx, cy);
mygraphics.RotateTransform(angle);
mygraphics.TranslateTransform(-cx, -cy);
mygraphics.DrawImage(myimage, new Point(1, 1));
// image crop
myBitmap= myBitmap.Clone(new Rectangle(1, 1, (int)w, (int)h), myimage.PixelFormat)
This is the main idea. Hope it helps.
Related
I want to rotate a Bitmap around a given point and have that point become the new center of the Bitmap.
Here is what I tried first
Bitmap rotate(Bitmap img, float angle, int cx, int cy)
{
Bitmap result = new Bitmap(img.Width, img.Height);
int middleX = img.Width / 2,
middleY = img.Height / 2;
using (Graphics g = Graphics.FromImage(result))
{
g.Clear(Color.Black);
g.TranslateTransform(cx, cy);
g.RotateTransform(angle);
g.TranslateTransform(-cx, -cy);
g.TranslateTransform(middleX - cx, middleY - cy); //shift (cx, cy) to be at the center, does not work
g.DrawImage(originalImage, new Point(0, 0));
}
return result;
}
But when I go to translate the image after rotation, the translation is in the original space instead of this new rotated space and doesn't come out right.
I tried basically every combination of things I could think of with no luck. Search results only describe how to rotate around a point.
Original image (red dot is the point to rotate around) -
After rotating by 45 degrees the image should be translated so that the red dot is the center of the image
You have to set the matrix order to Append for the final translation. I have no idea why this is what makes it work. I literally just brute force tried every possible way of doing everything until it worked. I'd still be interested in an explanation of what is going on though.
Bitmap rotate(Bitmap img, float angle, int cx, int cy)
{
Bitmap result = new Bitmap(img.Width, img.Height);
int mx = img.Width / 2,
my = img.Height / 2;
using (Graphics g = Graphics.FromImage(result))
{
g.Clear(Color.Black);
g.TranslateTransform(cx, cy);
g.RotateTransform(angle);
g.TranslateTransform(-cx, -cy);
g.TranslateTransform(mx - cx, my - cy, MatrixOrder.Append);
g.DrawImage(originalImage, new Point(0, 0));
}
return result;
}
I have done some searching and i can not find any function thats doing what i whant it todo.
I have a image file of a scanned document with text, but the document is some degrees rotated so i whant to rotate it so the text being inline with each other.
In a perfect world its should be a function doing this automaticly but i can not find anything and what i understand to get it to work automaticly its needed to be some analyze of the image and i think its to big thing todo.
But then i have done a tool to rotate the image on a website manually, but now i need a function to save the rotation to the image file.
This seems to be some differents methods for but no one i tested doing what i whant.
The function i have finded that works almost like i whant is:
public static Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor) {
int w = bmp.Width;
int h = bmp.Height;
PixelFormat pf = default(PixelFormat);
if (bkColor == Color.Transparent)
{
pf = PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
Bitmap tempImg = new Bitmap(w, h, pf);
Graphics g = Graphics.FromImage(tempImg);
g.Clear(bkColor);
g.DrawImageUnscaled(bmp, 1, 1);
g.Dispose();
GraphicsPath path = new GraphicsPath();
path.AddRectangle(new RectangleF(0f, 0f, w, h));
Matrix mtrx = new Matrix();
//Using System.Drawing.Drawing2D.Matrix class
mtrx.Rotate(angle);
RectangleF rct = path.GetBounds(mtrx);
Bitmap newImg = new Bitmap(Convert.ToInt32(rct.Width), Convert.ToInt32(rct.Height), pf);
g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(-rct.X, -rct.Y);
g.RotateTransform(angle);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(tempImg, 0, 0);
g.Dispose();
tempImg.Dispose();
return newImg; }
But this do not change the height and width of the image file so the image file is in the same size but the image "object" has been scaled and rotated.
Any idea how i can do this good?
Answer
I find the solution that worked with my image that has a resolution on 300 at a old answer here.
If I've understood your question correctly, you essentially want to work out the new size of an image once rotated, and how to position the rotated image in it's new bitmap.
The diagram hopefully helps make clear the solution. Here is a bit of pseudo code:
sinVal = abs(sin(angle))
cosVal = abs(cos(angle))
newImgWidth = sinVal * oldImgHeight + cosVal * oldImgWidth
newImgHeight = sinVal * oldImgWidth + cosVal * oldImgHeight
originX = 0
originY = sinVal * oldImgWidth
You want to make the new image from the newImgWidth and newImgHeight, and then perform a rotation around the origin (originX, originY) and then render the image to this point. This will fall over if the angle (in degrees) isn't between -90 and 0 degrees (depicted). If it is between 0 and 90 degrees, then you just change the origin:
originX = sinVal * oldImgHeight
originY = 0
If it is in the range 90 degrees to 270 degrees (-90 degrees) then it is a little tricker (see example code below).
Your code re-written (briefly tested) - it is slightly dodgy but seems to work:
public static Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor)
{
angle = angle % 360;
if (angle > 180)
angle -= 360;
System.Drawing.Imaging.PixelFormat pf = default(System.Drawing.Imaging.PixelFormat);
if (bkColor == Color.Transparent)
{
pf = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
}
else
{
pf = bmp.PixelFormat;
}
float sin = (float)Math.Abs(Math.Sin(angle * Math.PI / 180.0)); // this function takes radians
float cos = (float)Math.Abs(Math.Cos(angle * Math.PI / 180.0)); // this one too
float newImgWidth = sin * bmp.Height + cos * bmp.Width;
float newImgHeight = sin * bmp.Width + cos * bmp.Height;
float originX = 0f;
float originY = 0f;
if (angle > 0)
{
if (angle <= 90)
originX = sin * bmp.Height;
else
{
originX = newImgWidth;
originY = newImgHeight - sin * bmp.Width;
}
}
else
{
if (angle >= -90)
originY = sin * bmp.Width;
else
{
originX = newImgWidth - sin * bmp.Height;
originY = newImgHeight;
}
}
Bitmap newImg = new Bitmap((int)newImgWidth, (int)newImgHeight, pf);
Graphics g = Graphics.FromImage(newImg);
g.Clear(bkColor);
g.TranslateTransform(originX, originY); // offset the origin to our calculated values
g.RotateTransform(angle); // set up rotate
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
g.DrawImageUnscaled(bmp, 0, 0); // draw the image at 0, 0
g.Dispose();
return newImg;
}
Note the Degrees to Radians Conversion (180 Degrees == Pi Radians) for the trig functions
Edit: big issue was negative sin values, and me getting width/height confused when calculating origin x/y - this should work fine now (tested)
Edit: modified code to handle any angle
This is strictly a comment to the nice answer by VisualMelon above, But I'm not allowed to add comments...
There are two tiny bugs in the code
a) The first check after the modulus should either be split into two, or changed to e.g.
if (180<Math.Abs(angle)) angle -= 360*Math.Sign(angle);
Otherwise angles between -360 and -180 will fail, as only +180 to +360 were handled
b) Just after the newImg assignment, a resolution assignment is missing, e.g.
newImg.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
If omitted the image will be scaled if the source is not 96 dpi.
....And splitting sticks, the intermediate calculations of dimensions and offsets ought to be kept in double, and only reduced to float last
How do I rotate image then move to the top left 0,0 without cutting off the image.
Please read the comments inside the code. I got stuck at STEP 3
I think using trigonometry should be able to solve this problem.
thanks
private Bitmap RotateImage(Bitmap b, float angle)
{
//create a new empty bitmap to hold rotated image
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
//make a graphics object from the empty bitmap
Graphics g = Graphics.FromImage(returnBitmap);
//STEP 1 move rotation point to top left
g.TranslateTransform((float)0, (float)0);
//STEP 2 rotate
g.RotateTransform(angle);
//STEP 3 move image back to top left without cutting off the image
//SOME trigonometry calculation here
int newY = b.Height;
g.TranslateTransform(-(float)0, -newY);
//draw passed in image onto graphics object
g.DrawImage(b, new Point(0, 0));
return returnBitmap;
}
Does this cover the 'trigonometry'? I have made it step 0 because I think you need to do it first. That way you can calculate the size of the resulting bitmap, which will be bigger - see my comments in the code.
private Bitmap RotateImage(Bitmap b, float Angle) {
// The original bitmap needs to be drawn onto a new bitmap which will probably be bigger
// because the corners of the original will move outside the original rectangle.
// An easy way (OK slightly 'brute force') is to calculate the new bounding box is to calculate the positions of the
// corners after rotation and get the difference between the maximum and minimum x and y coordinates.
float wOver2 = b.Width / 2.0f;
float hOver2 = b.Height / 2.0f;
float radians = -(float)(Angle / 180.0 * Math.PI);
// Get the coordinates of the corners, taking the origin to be the centre of the bitmap.
PointF[] corners = new PointF[]{
new PointF(-wOver2, -hOver2),
new PointF(+wOver2, -hOver2),
new PointF(+wOver2, +hOver2),
new PointF(-wOver2, +hOver2)
};
for (int i = 0; i < 4; i++) {
PointF p = corners[i];
PointF newP = new PointF((float)(p.X * Math.Cos(radians) - p.Y * Math.Sin(radians)), (float)(p.X * Math.Sin(radians) + p.Y * Math.Cos(radians)));
corners[i] = newP;
}
// Find the min and max x and y coordinates.
float minX = corners[0].X;
float maxX = minX;
float minY = corners[0].Y;
float maxY = minY;
for (int i = 1; i < 4; i++) {
PointF p = corners[i];
minX = Math.Min(minX, p.X);
maxX = Math.Max(maxX, p.X);
minY = Math.Min(minY, p.Y);
maxY = Math.Max(maxY, p.Y);
}
// Get the size of the new bitmap.
SizeF newSize = new SizeF(maxX - minX, maxY - minY);
// ...and create it.
Bitmap returnBitmap = new Bitmap((int)Math.Ceiling(newSize.Width), (int)Math.Ceiling(newSize.Height));
// Now draw the old bitmap on it.
using (Graphics g = Graphics.FromImage(returnBitmap)) {
g.TranslateTransform(newSize.Width / 2.0f, newSize.Height / 2.0f);
g.RotateTransform(Angle);
g.TranslateTransform(-b.Width / 2.0f, -b.Height / 2.0f);
g.DrawImage(b, 0, 0);
}
return returnBitmap;
}
There are some looooong and hungry algorithms for doing so, but as of yet I haven't come up with or found anything particularly fast.
The fastest way is to this is to use unsafe calls to manipulate the image memory directly using LockBits. It sounds scary but it's pretty straight forward. If you search for LockBits you'll find plently of examples such as here.
The interesting bit is:
BitmapData originalData = originalBitmap.LockBits(
new Rectangle(0, 0, originalWidth, originalHeight),
ImageLockMode.ReadOnly,
PixelFormat.Format32bppRgb);
Once you have the BitmapData you can pass the pixels and map them into a new image (again using LockBits). This is significantly quicker than using the Graphics API.
Here's what I ended up doing (after an extensive amount of continued research, and the helpful link provided by TheCodeKing):
public Image RotateImage(Image img, float rotationAngle)
{
// When drawing the returned image to a form, modify your points by
// (-(img.Width / 2) - 1, -(img.Height / 2) - 1) to draw for actual co-ordinates.
//create an empty Bitmap image
Bitmap bmp = new Bitmap((img.Width * 2), (img.Height *2));
//turn the Bitmap into a Graphics object
Graphics gfx = Graphics.FromImage(bmp);
//set the point system origin to the center of our image
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
//now rotate the image
gfx.RotateTransform(rotationAngle);
//move the point system origin back to 0,0
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
//set the InterpolationMode to HighQualityBicubic so to ensure a high
//quality image once it is transformed to the specified size
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
//draw our new image onto the graphics object with its center on the center of rotation
gfx.DrawImage(img, new PointF((img.Width / 2), (img.Height / 2)));
//dispose of our Graphics object
gfx.Dispose();
//return the image
return bmp;
}
Cheers!
void Graphics.RotateTransform(float angle);
This should rotate the image in C#. What is it doing instead?
I haven't experimented too much with GDI+. Remember to reverse the rotation after the image is drawn.
This answer returns both the offset it should be drawn on and the image which has been rotated.It works by recreating the new image to the size it should be without clipping the angles. Originally written by Hisenburg from the #C# IRC chatroom and Bloodyaugust.
public static double NormalizeAngle(double angle)
{
double division = angle / (Math.PI / 2);
double fraction = Math.Ceiling(division) - division;
return (fraction * Math.PI / 2);
}
public static Tuple<Image,Size> RotateImage(Image img, double rotationAngle)
{
double normalizedRotationAngle = NormalizeAngle(rotationAngle);
double widthD = img.Width, heightD = img.Height;
double newWidthD, newHeightD;
newWidthD = Math.Cos(normalizedRotationAngle) * widthD + Math.Sin(normalizedRotationAngle) * heightD;
newHeightD = Math.Cos(normalizedRotationAngle) * heightD + Math.Sin(normalizedRotationAngle) * widthD;
int newWidth, newHeight;
newWidth = (int)Math.Ceiling(newWidthD);
newHeight = (int)Math.Ceiling(newHeightD);
Size offset = new Size((newWidth - img.Width) / 2,(newHeight - img.Height) / 2);
Bitmap bmp = new Bitmap(newWidth, newHeight);
Graphics gfx = Graphics.FromImage(bmp);
//gfx.Clear(Color.Blue);
gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);
gfx.RotateTransform((float)(rotationAngle / Math.PI * 180));
gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);
gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfx.DrawImage(img, new PointF((bmp.Width / 2 - img.Width / 2), (bmp.Height / 2 - img.Height / 2)));
gfx.Dispose();
return new Tuple<Image,Size>(bmp,offset);
}
System.Drawing.Image imageToRotate = System.Drawing.Image.FromFile(imagePath);
switch (rotationAngle.Value)
{
case "90":
imageToRotate.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
case "180":
imageToRotate.RotateFlip(RotateFlipType.Rotate180FlipNone);
break;
case "270":
imageToRotate.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
default:
throw new Exception("Rotation angle not supported.");
}
imageToRotate.Save(imagePath, ImageFormat.Jpeg);
I am writing a small 2d game engine in C# for my own purposes, and it works fine except for the sprite collision detection. I've decided to make it a per-pixel detection (easiest for me to implement), but it is not working the way it's supposed to. The code detects a collision long before it happens. I've examined every component of the detection, but I can't find the problem.
The collision detection method:
public static bool CheckForCollision(Sprite s1, Sprite s2, bool perpixel) {
if(!perpixel) {
return s1.CollisionBox.IntersectsWith(s2.CollisionBox);
}
else {
Rectangle rect;
Image img1 = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(s1.Image, s1.Position, s1.Origin, s1.Rotation, out rect), s1.Scale);
int posx1 = rect.X;
int posy1 = rect.Y;
Image img2 = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(s2.Image, s2.Position, s2.Origin, s2.Rotation, out rect), s2.Scale);
int posx2 = rect.X;
int posy2 = rect.Y;
Rectangle abounds = new Rectangle(posx1, posy1, (int)img1.Width, (int)img1.Height);
Rectangle bbounds = new Rectangle(posx2, posy2, (int)img2.Width, (int)img2.Height);
if(Utilities.RectangleIntersects(abounds, bbounds)) {
uint[] bitsA = s1.GetPixelData(false);
uint[] bitsB = s2.GetPixelData(false);
int x1 = Math.Max(abounds.X, bbounds.X);
int x2 = Math.Min(abounds.X + abounds.Width, bbounds.X + bbounds.Width);
int y1 = Math.Max(abounds.Y, bbounds.Y);
int y2 = Math.Min(abounds.Y + abounds.Height, bbounds.Y + bbounds.Height);
for(int y = y1; y < y2; ++y) {
for(int x = x1; x < x2; ++x) {
if(((bitsA[(x - abounds.X) + (y - abounds.Y) * abounds.Width] & 0xFF000000) >> 24) > 20 &&
((bitsB[(x - bbounds.X) + (y - bbounds.Y) * bbounds.Width] & 0xFF000000) >> 24) > 20)
return true;
}
}
}
return false;
}
}
The image rotation method:
internal static Image RotateImagePoint(Image img, Vector pos, Vector orig, double rotation, out Rectangle sz) {
if(!(new Rectangle(new Point(0), img.Size).Contains(new Point((int)orig.X, (int)orig.Y))))
Console.WriteLine("Origin point is not present in image bound; unwanted cropping might occur");
rotation = (double)ra_de((double)rotation);
sz = GetRotateDimensions((int)pos.X, (int)pos.Y, img.Width, img.Height, rotation, false);
Bitmap bmp = new Bitmap(sz.Width, sz.Height);
Graphics g = Graphics.FromImage(bmp);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.RotateTransform((float)rotation);
g.TranslateTransform(sz.Width / 2, sz.Height / 2, MatrixOrder.Append);
g.DrawImage(img, (float)-orig.X, (float)-orig.Y);
g.Dispose();
return bmp;
}
internal static Rectangle GetRotateDimensions(int imgx, int imgy, int imgwidth, int imgheight, double rotation, bool Crop) {
Rectangle sz = new Rectangle();
if (Crop == true) {
// absolute trig values goes for all angles
double dera = de_ra(rotation);
double sin = Math.Abs(Math.Sin(dera));
double cos = Math.Abs(Math.Cos(dera));
// general trig rules:
// length(adjacent) = cos(theta) * length(hypotenuse)
// length(opposite) = sin(theta) * length(hypotenuse)
// applied width = lo(img height) + la(img width)
sz.Width = (int)(sin * imgheight + cos * imgwidth);
// applied height = lo(img width) + la(img height)
sz.Height = (int)(sin * imgwidth + cos * imgheight);
}
else {
// get image diagonal to fit any rotation (w & h =diagonal)
sz.X = imgx - (int)Math.Sqrt(Math.Pow(imgwidth, 2.0) + Math.Pow(imgheight, 2.0));
sz.Y = imgy - (int)Math.Sqrt(Math.Pow(imgwidth, 2.0) + Math.Pow(imgheight, 2.0));
sz.Width = (int)Math.Sqrt(Math.Pow(imgwidth, 2.0) + Math.Pow(imgheight, 2.0)) * 2;
sz.Height = sz.Width;
}
return sz;
}
Pixel getting method:
public uint[] GetPixelData(bool useBaseImage) {
Rectangle rect;
Image image;
if (useBaseImage)
image = Image;
else
image = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(Image, Position, Origin, Rotation, out rect), Scale);
BitmapData data;
try {
data = ((Bitmap)image).LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
}
catch (ArgumentException) {
data = ((Bitmap)image).LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat);
}
byte[] rawdata = new byte[data.Stride * image.Height];
Marshal.Copy(data.Scan0, rawdata, 0, data.Stride * image.Height);
((Bitmap)image).UnlockBits(data);
int pixelsize = 4;
if (data.PixelFormat == PixelFormat.Format24bppRgb)
pixelsize = 3;
else if (data.PixelFormat == PixelFormat.Format32bppArgb || data.PixelFormat == PixelFormat.Format32bppRgb)
pixelsize = 4;
double intdatasize = Math.Ceiling((double)rawdata.Length / pixelsize);
uint[] intdata = new uint[(int)intdatasize];
Buffer.BlockCopy(rawdata, 0, intdata, 0, rawdata.Length);
return intdata;
}
The pixel retrieval method works, and the rotation method works as well, so the only place that the code might be wrong is the collision detection code, but I really have no idea where the problem might be.
I don't think many people here will bother to scrutinize your code to figure out what exactly is wrong. But I can come with some hints to how you can find the problem.
If collision happens long before it is supposed to I suggest your bounding box check isn't working properly.
I would change the code to dump out all the data about rectangles at collision. So you can create some code that will display the situation at collision. That might be easier than looking over the numbers.
Apart from that I doubt that per pixel collision detection easier for you to implement. When you allow for rotation and scaling that quickly becomes difficult to get right. I would do polygon based collision detection instead.
I have made my own 2D engine like you but I used polygon based collision detection and that worked fine.
I think I've found your problem.
internal static Rectangle GetRotateDimensions(int imgx, int imgy, int imgwidth, int imgheight, double rotation, bool Crop) {
Rectangle sz = new Rectangle(); // <-- Default constructed rect here.
if (Crop == true) {
// absolute trig values goes for all angles
double dera = de_ra(rotation);
double sin = Math.Abs(Math.Sin(dera));
double cos = Math.Abs(Math.Cos(dera));
// general trig rules:
// length(adjacent) = cos(theta) * length(hypotenuse)
// length(opposite) = sin(theta) * length(hypotenuse)
// applied width = lo(img height) + la(img width)
sz.Width = (int)(sin * imgheight + cos * imgwidth);
// applied height = lo(img width) + la(img height)
sz.Height = (int)(sin * imgwidth + cos * imgheight);
// <-- Never gets the X & Y assigned !!!
}
Since you never assigned imgx and imgy to the X and Y coordinates of the Rectangle, every call of GetRotateDimensions will produce a Rectangle with the same location. They may be of differing sizes, but they will always be in the default X,Y position. This would cause the really early collisions that you are seeing because any time you tried to detect collisions on two sprites, GetRotateDimensions would put their bounds in the same position regardless of where they actually are.
Once you have corrected that problem, you may run into another error:
Rectangle rect;
Image img1 = GraphicsHandler.ResizeImage(GraphicsHandler.RotateImagePoint(s1.Image, s1.Position, s1.Origin, s1.Rotation, out rect), s1.Scale);
// <-- Should resize rect here.
int posx1 = rect.X;
int posy1 = rect.Y;
You get your boundary rect from the RotateImagePoint function, but you then resize the image. The X and Y from the rect are probably not exactly the same as that of the resized boundaries of the image. I'm guessing that you mean for the center of the image to remain in place while all points contract toward or expand from the center in the resize. If this is the case, then you need to resize rect as well as the image in order to get the correct position.
I doubt this is the actual problem, but LockBits doesn't guarantee that the bits data is aligned to the image's Width.
I.e., there may be some padding. You need to access the image using data[x + y * stride] and not data[x + y * width]. The Stride is also part of the BitmapData.