Rotate and Scale rectangle as per user control - c#

I have UserControl of Size 300*200.
and rectangle of size 300*200.
graphics.DrawRectangle(Pens.Black, 0, 0, 300, 200);
When I rotate rectangle in userControl by 30 degree, I get rotated rectangle but it is outsized.
PointF center = new PointF(150,100);
graphics.FillRectangle(Brushes.Black, center.X, center.Y, 2, 2); // draw center point.
using (Matrix matrix = new Matrix())
{
matrix.RotateAt(30, center);
graphics.Transform = matrix;
graphics.DrawRectangle(Pens.Black, 0, 0, 300, 200);
graphics.ResetTransform();
}
I want to fit rectangle like actual result.Check Image here
Can anyone have solution about this.
Thanks.

It's more of a math question than programming one.
Calculate bouning box of any rectangle rotated by any angle in radians.
var newWidth= Math.Abs(height*Math.Sin(angle)) + Math.Abs(width*Math.Cos(angle))
var newHeight= Math.Abs(width*Math.Sin(angle)) + Math.Abs(height*Math.Cos(angle))
Calculate scale for x and y:
scaleX = width/newWidth;
scaleY = height/newHeight;
Apply it to your rectangle.
EDIT:
Applied to your example:
PointF center = new PointF(150, 100);
graphics.FillRectangle(Brushes.Black, center.X, center.Y, 2, 2); // draw center point.
var height = 200;
var width = 300;
var angle = 30;
var radians = angle * Math.PI / 180;
var boundingWidth = Math.Abs(height * Math.Sin(radians)) + Math.Abs(width * Math.Cos(radians));
var boundingHeight = Math.Abs(width * Math.Sin(radians)) + Math.Abs(height * Math.Cos(radians));
var scaleX = (float)(width / boundingWidth);
var scaleY = (float)(height / boundingHeight);
using (Matrix matrix = new Matrix())
{
matrix.Scale(scaleX, scaleY, MatrixOrder.Append);
matrix.Translate(((float)boundingWidth - width) / 2, ((float)boundingHeight - height) / 2);
matrix.RotateAt(angle, center);
graphics.Transform = matrix;
graphics.DrawRectangle(Pens.Black, 0, 0, width, height);
graphics.ResetTransform();
}

Related

How to use AddArc() method in C#

I have this little code to use AddArc() method in a label, but when I execute the code the label disappears. I believe it is the numbers I have used, I followed instructions from the Windows documentation and it had these parameters there too.
GraphicsPath gp = new GraphicsPath();
Rectangle rec = new Rectangle(20, 20, 50, 100);
gp.AddArc(rec, 0 , 180);
label2.Region = new Region(gp);
label2.Invalidate();
I used another code to make the correct way or curve in a text
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var center = new Point(Width / 2, Height / 2);
var radius = Math.Min(Width, Height) / 3;
var text = "Hello";//txtUp.Text;
var font = new Font(FontFamily.GenericSansSerif, 24, FontStyle.Bold);
for (var i = 0; i < text.Length; ++i)
{
var c = new String(text[i], 1);
var size = e.Graphics.MeasureString(c, font);
var charRadius = radius + size.Height;
var angle = (((float)i / text.Length) - 2);
var x = (int)(center.X + Math.Cos(angle) * charRadius);
var y = (int)(center.Y + Math.Sin(angle) * charRadius);
e.Graphics.TranslateTransform(x, y);
e.Graphics.RotateTransform((float)(90 + 360 * angle / (2 * Math.PI)));
e.Graphics.DrawString(c, font, Brushes.Red, 0, 0);
e.Graphics.ResetTransform();
e.Graphics.DrawArc(new Pen(Brushes.Transparent, 2.0f), center.X - radius, center.Y - radius, radius * 2, radius * 2, 0, 360);
}
}
but it wont show in front of a panel is it possible.
This is what it looks like:
Is it possible to move that text in front of the green circle?

How do I determine the rotation point of a polygon (triangle)?

I would like to draw a thick, transparent arrow with an arrowhead:
Here's the code that draws the arrow shaft. Notice that I have to offset the rectangle so the calculations are done from the midpoint of the rectangle.
private void DrawMovementArrow(bool color, double StartX, double StartY, double EndX, double EndY)
{
SolidColorBrush partiallyTransparentSolidColorBrush;
Rectangle myRectangle = new Rectangle();
// This will be replaced by piece size
int width = 35;
myRectangle.Width = width;
// Apparently necessary to offset the drawing of the path so that the point is in the center of the path; not the edge.
StartX -= width / 2;
EndX -= width / 2;
myRectangle.Height = Map.EuclideanDistance(StartX, StartY, EndX, EndY) ;
int angle = CalculateAngle(StartX , StartY , EndX , EndY );
// This selects the midpoint of edge of the rectangle to rotate around (weird system)
myRectangle.RenderTransformOrigin = new Point(0.5, 0);
angle = angle - 180;
RotateTransform rotateTransform1 = new RotateTransform(angle, 0 , 0 );
myRectangle.RenderTransform = rotateTransform1;
if (color)
partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.Blue);
else
partiallyTransparentSolidColorBrush = new SolidColorBrush(Colors.Red);
partiallyTransparentSolidColorBrush.Opacity = 0.4;
myRectangle.Fill = partiallyTransparentSolidColorBrush;
MovementCanvas1.Children.Clear();
MovementCanvas1.Children.Add(myRectangle);
Canvas.SetTop(myRectangle, StartY);
Canvas.SetLeft(myRectangle, StartX);
DrawArrowhead(color, EndX, EndY, angle + 90, width);
ShowUnitCenter(MovementArrowList[0]);
}
Note that this code selects a point in the middle of the edge to rotate the rectangle:
// This selects the midpoint of edge of the rectangle to rotate around (weird system)
myRectangle.RenderTransformOrigin = new Point(0.5, 0);
The problem is that I can't find that point with the arrowhead (triangle). Here's the code that draws the arrowhead:
public void DrawArrowhead(bool color, double x, double y, int angle, int width)
{
x += width /2 ;
width = width + (width / 2);
//Add the Polygon Element
Polygon myPolygon = new Polygon();
myPolygon.Opacity = 0.4;
if (color)
{
myPolygon.Fill = new SolidColorBrush(Colors.Blue);
myPolygon.Stroke = System.Windows.Media.Brushes.Blue;
}
else
{
myPolygon.Fill = new SolidColorBrush(Colors.Red);
myPolygon.Stroke = System.Windows.Media.Brushes.Red;
}
myPolygon.StrokeThickness = 0;
RotateTransform rotateTransform1 = new RotateTransform(angle, 0, 0);
myPolygon.RenderTransform = rotateTransform1;
// This selects the midpoint of edge of the triangle to rotate around (weird system)
myPolygon.RenderTransformOrigin = new Point(0.0, 0.5);
System.Windows.Point Point1 = new System.Windows.Point(0, 0);
System.Windows.Point Point2 = new System.Windows.Point(width / 2, width / 2);
System.Windows.Point Point3 = new System.Windows.Point(0,width);
PointCollection myPointCollection = new PointCollection();
myPointCollection.Add(Point1);
myPointCollection.Add(Point2);
myPointCollection.Add(Point3);
myPolygon.Points = myPointCollection;
MovementCanvas1.Children.Add(myPolygon);
Canvas.SetTop(myPolygon, y );
Canvas.SetLeft(myPolygon, x );
}
Note the myPointCollection that creates the triangle. The problem is that I've tried almost every conceivable combination of values in RenderTransformOrigin to find the point that (center bottom of triangle) to use for the rotation point. Nothing seems to be working out.
Can anybody suggest the correct value?
Edit Solved
I solved it by changing the points of the triangle. That was easier than trying to figure out the rotation point.
Changing the points that made up the triangle solved the problem. This was easier than trying to find the rotation point.

Properly rotate an image

How to I rotate an image without it showing like this?
Here's my Rotation Method:
public static Bitmap RotateImageN(Bitmap bmp, float angle)
{
Bitmap rotatedImage = new Bitmap(bmp.Width, bmp.Height);
using (Graphics g = Graphics.FromImage(rotatedImage))
{
// Set the rotation point to the center in the matrix
g.TranslateTransform(bmp.Width / 2, bmp.Height / 2);
// Rotate
g.RotateTransform(angle);
// Restore rotation point in the matrix
g.TranslateTransform(-bmp.Width / 2, -bmp.Height / 2);
// Draw the image on the bitmap
g.DrawImage(bmp, new Point(0, 0));
}
return rotatedImage;
}
Edit: After trying Loocid's Code
Your rotatedImage Bitmap needs to be big enough to accommodate the rotated image.
Say you rotated your original image by 30° you need to get the size of the bounding box like so:
Using some basic trig:
x = L*cos(30 * π / 180) + w*cos(60 * π / 180)
y = L*sin(30 * π / 180) + w*sin(60 * π / 180)
Therefore change the start of your code to:
var x = bmp.Width * Math.Cos(angle * Math.PI / 180) + bmp.Height * Math.Cos((90-angle) * Math.PI / 180)
var y = bmp.Width * Math.Sin(angle * Math.PI / 180) + bmp.Height * Math.Sin((90-angle) * Math.PI / 180)
Bitmap rotatedImage = new Bitmap(x, y);
The issue occurs in the rotating is related to the bounding box. It is clipping the edge because of the image you provided does not fit into the area that you have given.
I also faced this issue. So I tried a solution from here.
Adding the code that works for me.
public static Bitmap RotateImageN(Bitmap bitmap, float angle)
{
Matrix matrix = new Matrix();
matrix.Translate(bitmap.Width / -2, bitmap.Height / -2, MatrixOrder.Append);
matrix.RotateAt(angle, new System.Drawing.Point(0, 0), MatrixOrder.Append);
using (GraphicsPath graphicsPath = new GraphicsPath())
{
graphicsPath.AddPolygon(new System.Drawing.Point[] { new System.Drawing.Point(0, 0), new System.Drawing.Point(bitmap.Width, 0), new System.Drawing.Point(0, bitmap.Height) });
graphicsPath.Transform(matrix);
System.Drawing.PointF[] points = graphicsPath.PathPoints;
Rectangle rectangle = boundingBox(bitmap, matrix);
Bitmap resultBitmap = new Bitmap(rectangle.Width, rectangle.Height);
using (Graphics gDest = Graphics.FromImage(resultBitmap))
{
Matrix mDest = new Matrix();
mDest.Translate(resultBitmap.Width / 2, resultBitmap.Height / 2, MatrixOrder.Append);
gDest.Transform = mDest;
gDest.DrawImage(bitmap, points);
return resultBitmap;
}
}
}
private static Rectangle boundingBox(Image image, Matrix matrix)
{
GraphicsUnit graphicsUnit = new GraphicsUnit();
Rectangle boundingRectangle = Rectangle.Round(image.GetBounds(ref graphicsUnit));
Point topLeft = new Point(boundingRectangle.Left, boundingRectangle.Top);
Point topRight = new Point(boundingRectangle.Right, boundingRectangle.Top);
Point bottomRight = new Point(boundingRectangle.Right, boundingRectangle.Bottom);
Point bottomLeft = new Point(boundingRectangle.Left, boundingRectangle.Bottom);
Point[] points = new Point[] { topLeft, topRight, bottomRight, bottomLeft };
GraphicsPath graphicsPath = new GraphicsPath(points, new byte[] { (byte)PathPointType.Start, (byte)PathPointType.Line, (byte)PathPointType.Line, (byte)PathPointType.Line });
graphicsPath.Transform(matrix);
return Rectangle.Round(graphicsPath.GetBounds());
}

Align text to center in System.Drawing.RectangleF

I am trying to create a captcha image. I am generating a random string and rotating the text with a random angle and trying to create a byte array. Below is my code snippet:
Image img = Image.FromFile(#"C:\Images\BackGround.jpg");
RectangleF myRect = new RectangleF(0, 0, width, height);
objGraphics.DrawImage(img, myRect);
Matrix myMatrix = new Matrix();
int i = 0;
StringFormat formatter = new StringFormat();
formatter.Alignment = StringAlignment.Center;
for (i = 0; i <= myString.Length - 1; i++)
{
myMatrix.Reset();
int charLenght = myString.Length;
float x = width / (charLenght + 1) * i;
float y = height / 30F;
myMatrix.RotateAt(oRandom.Next(-40, 40), new PointF(x, y));
objGraphics.Transform = myMatrix;
objGraphics.DrawString(myString.Substring(i, 1), MyFont, MyFontEmSizes, MyFontStyles,
MySolidBrush, x, Math.Max(width, height) / 50, formatter );
objGraphics.ResetTransform();
}
Every thing is working fine, except that, the first character in my final image on the web page is crossing my left border of the rectangle. How can I align my text to the center of the rectangle?
Thanks.

How does GraphicsPath.AddArc use the startAngle and sweepAngle parameters?

I am trying to use System.Drawing.Drawing2D.GraphicsPath.AddArc to draw an arc of an ellipse starting at 0 degrees and sweeping to 135 degrees.
The issue I am running in to is that for an ellipse, the arc drawn does not match up with what I would expect.
For example, the following code generates the image below. The green circles are where I would expect the end points of the arc to be using the formula for a point along an ellipse. My formula works for circles but not for ellipses.
Does this have something to do with polar versus Cartesian coordinates?
private PointF GetPointOnEllipse(RectangleF bounds, float angleInDegrees)
{
float a = bounds.Width / 2.0F;
float b = bounds.Height / 2.0F;
float angleInRadians = (float)(Math.PI * angleInDegrees / 180.0F);
float x = (float)(( bounds.X + a ) + a * Math.Cos(angleInRadians));
float y = (float)(( bounds.Y + b ) + b * Math.Sin(angleInRadians));
return new PointF(x, y);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle circleBounds = new Rectangle(250, 100, 500, 500);
e.Graphics.DrawRectangle(Pens.Red, circleBounds);
System.Drawing.Drawing2D.GraphicsPath circularPath = new System.Drawing.Drawing2D.GraphicsPath();
circularPath.AddArc(circleBounds, 0.0F, 135.0F);
e.Graphics.DrawPath(Pens.Red, circularPath);
PointF circlePoint = GetPointOnEllipse(circleBounds, 135.0F);
e.Graphics.DrawEllipse(Pens.Green, new RectangleF(circlePoint.X - 5, circlePoint.Y - 5, 10, 10));
Rectangle ellipseBounds = new Rectangle(50, 100, 900, 500);
e.Graphics.DrawRectangle(Pens.Blue, ellipseBounds);
System.Drawing.Drawing2D.GraphicsPath ellipticalPath = new System.Drawing.Drawing2D.GraphicsPath();
ellipticalPath.AddArc(ellipseBounds, 0.0F, 135.0F);
e.Graphics.DrawPath(Pens.Blue, ellipticalPath);
PointF ellipsePoint = GetPointOnEllipse(ellipseBounds, 135.0F);
e.Graphics.DrawEllipse(Pens.Green, new RectangleF(ellipsePoint.X - 5, ellipsePoint.Y - 5, 10, 10));
}
I was getting confused about how GraphicsPath.AddArc worked & I couldn't find any decent diagrams, so I drew one. Just in case anyone else has been suffering similarly! http://imgur.com/lNBewKZ
GraphicsPath.AddArc does exactly what you ask it to do -- it the arc up to a line projecting from the ellipse center, at an exact angle of 135 degrees clockwise from the x axis.
Unfortunately, this doesn't help when you're using the angle as a direct proportion of a pie chart slice you want to draw. To find out the angle B you need to use with AddArc, given an angle A that works on a circle, in radians, use:
B = Math.Atan2(sin(A) * height / width, cos(A))
Where width and height are those of the ellipse.
In your sample code, try adding the following at the end of Form1_Paint:
ellipticalPath = new System.Drawing.Drawing2D.GraphicsPath();
ellipticalPath.AddArc(
ellipseBounds,
0.0F,
(float) (180.0 / Math.PI * Math.Atan2(
Math.Sin(135.0 * Math.PI / 180.0) * ellipseBounds.Height / ellipseBounds.Width,
Math.Cos(135.0 * Math.PI / 180.0))));
e.Graphics.DrawPath(Pens.Black, ellipticalPath);
The result should look as follows:
alt text http://img216.imageshack.us/img216/1905/arcs.png

Categories

Resources