I have a method which is to draw a polygon, and then rotate that polygon 90 degrees to the right so that its original top point is now pointing towards the right.
This is the code to draw the polygon(triangle) how ever I'm lost on how to rotate this.
Point[] points = new Point[3];
points[0] = new Point((int)top, (int)top);
points[1] = new Point((int)top - WIDTH / 2, (int)top + HEIGHT);
points[2] = new Point((int)top + WIDTH / 2, (int)top + HEIGHT);
paper.FillPolygon(normalBrush, points);
Thanks in advance.
http://msdn.microsoft.com/en-us/library/s0s56wcf.aspx#Y609
public void RotateExample(PaintEventArgs e)
{
Pen myPen = new Pen(Color.Blue, 1);
Pen myPen2 = new Pen(Color.Red, 1);
// Draw the rectangle to the screen before applying the transform.
e.Graphics.DrawRectangle(myPen, 150, 50, 200, 100);
// Create a matrix and rotate it 45 degrees.
Matrix myMatrix = new Matrix();
myMatrix.Rotate(45, MatrixOrder.Append);
// Draw the rectangle to the screen again after applying the
// transform.
e.Graphics.Transform = myMatrix;
e.Graphics.DrawRectangle(myPen2, 150, 50, 200, 100);
}
You can use TransformPoints method of Matrix class to just rotate the points
See this informative Wikipedia article for a great explanation of rotation matrices. When rotating 90 degrees we note that cos 90 collapses into zero yielding the following simple transformation where x' and y' are your rotated coordinates and x and y are the previous coordinates.
x' = -y
y' = x
Applying this simple replacement on your example yields the following code. I've also used a shorthand collection initializer expression for added readability.
var points = new[]
{
new Point(-(int) top, (int) top),
new Point((int) -(top + HEIGHT), (int) top - WIDTH/2),
new Point((int) -(top + HEIGHT), (int) top + WIDTH/2)
};
paper.FillPolygon(normalBrush, points);
I also recommend reading up on linear algebra using for example Anton Rorres, et al.
You can rotate your polygon if you rotate every point. You also have to find out your rotation center O. Probably you want to use your polygon center as rotation center.
Related
Let's have a triangle with sides AB = 80, BC = 50, CA = 40.
It is necessary to draw a triangle whose sides would be equal to these values.Tried to do it via AddPolygon, but I think it's not quite the right solution
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (index == 1)
{
Point[] myArray =
{
new Point(80, 50),
new Point(50, 40),
new Point(40, 80),
};
GraphicsPath Path = new GraphicsPath();
Path.AddPolygon(myArray);
Pen P = new Pen(Color.Black, 5);
e.Graphics.DrawPath(P, Path);
}
}
Since numbers represent lengths, not coordinates, they cannot be used in the API directly: you need to do some math before you start drawing.
First, let's decide on the location and orientation of our triangle: vertex A would be at (0, 0), and side AB would lie on the X axis, so point B would be at (80, 0). Now it's all about figuring out the location of point C. You can figure it out by solving two equations together:
(x-80)2 + y2 = 402
x2 + y2 = 502
The math is easy enough for a seventh grader who's good at math, so I wouldn't bore you with the solution. It yields x=45.62 and y=20.45. Plug these numbers into your program to draw your triangle.
Obviously, this draws the triangle in only one, easy-to-do, orientation. To move the triangle, adjust coordinates of its vertices by the same number. Rotating is a lot trickier; you would need to look it up in your favorite book on analytic geometry.
I'm using the following code to Transform a small rectangle coordinates to a larger one ie: A rectangle position on a small image to the same position on the larger resolution of the same image
Rectangle ConvertToLargeRect(Rectangle smallRect, Size largeImageSize, Size smallImageSize)
{
double xScale = (double)largeImageSize.Width / smallImageSize.Width;
double yScale = (double)largeImageSize.Height / smallImageSize.Height;
int x = (int)(smallRect.X * xScale + 0.5);
int y = (int)(smallRect.Y * yScale + 0.5);
int right = (int)(smallRect.Right * xScale + 0.5);
int bottom = (int)(smallRect.Bottom * yScale + 0.5);
return new Rectangle(x, y, right - x, bottom - y);
}
But there seems to be a problem with some images.The transformed rectangle coordinates seems to be off the image.
UPDATE:
img.Draw(rect, new Bgr(232, 3, 3), 2);
Rectangle transret= ConvertToLargeRect(rect, orgbitmap.Size, bit.Size);
target = new Bitmap(transret.Width, transret.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawImage(orgbitmap, new Rectangle(0, 0, target.Width, target.Height),
transret, GraphicsUnit.Pixel);
}
Rectangle Drawn on small resolution Image
{X=190,Y=2,Width=226,Height=286}
Rectangle Transformed into Orginal Large Resolution Image {X=698,Y=7,Width=830,Height=931}
Original Image
First of all, if you resize the shape it shouldn't move position. That's not what one would expect out of enlarging a shape. This means the X,Y point of the top-left corner shouldn't be transformed.
Second, you shouldn't be adding 0.5 manually to operations, that's not a clean way to proceed. Use the ceiling function as suggested by #RezaAghaei
Third, you should not substract X/Y from the height/width, your calculations should be done as width * scale.
Please correct those mistakes, and if it doesn't work I'll update the answer with extra steps.
I am drawing a line from centre of png image to top in below code:
private string ProcessImage(string fileIn)
{
var sourceImage = System.Drawing.Image.FromFile(fileIn);
var fileName = Path.GetFileName(fileIn);
var finalPath = Server.MapPath(#"~/Output/" + fileName);
int x = sourceImage.Width / 2;
int y = sourceImage.Height / 2;
using (var g = Graphics.FromImage(sourceImage))
{
g.DrawLine(new Pen(Color.Black, (float)5), new Point(x, 0), new Point(x, y));
}
sourceImage.Save(finalPath);
return #"~/Output/" + fileName;
}
This works fine and I have a line that is 90 degrees from centre of image.
Now what I need is instead of 90 degree perpendicular line, I would like to accept the degree from user input. If user enters 45 degree the line should be drawn at 45 degrees from centre of png image.
Please guide me in the right direction.
Thanks
Let's assume you have the angle you want in a float angle all you need to do is to insert these three lines before drawing the line:
g.TranslateTransform(x, y); // move the origin to the rotation point
g.RotateTransform(angle); // rotate
g.TranslateTransform(-x, -y); // move back
g.DrawLine(new Pen(Color.Black, (float)5), new Point(x, 0), new Point(x, y));
If you want to draw more stuff without the rotation call g.ResetTranform() !
I want to crop from an image using user-drawn rectangles on a canvas. The rectangles can be moved, re-sized, and rotated.
When the user selects "Get Cropped Image", the area inside the rectangle should be saved in a second image location on the page, which I can do perfectly well, so long as the rectangle is not rotated. (Straight-forward use of CroppedBitmap.) However, when the rectangle is at an angle I do not know how to perform the crop.
This is what I want to do (forgive my poor MS Paint skills):
My questions are:
1) How do I correctly track or calculate the points of the rectangle?
and,
2) Once I have the points, how do I crop the rotated rectangle?
EDIT:
Thanks to user Rotem, I believe that I have the answer to the second question. Using code modified from the following answers: Answer 1, Answer 2, I am seeing good results. Unfortunately, I am still unable to track the correct location points for the rectangle, so I cannot fully test this as of yet.
public static Bitmap CropRotatedRect(Bitmap source, System.Drawing.Rectangle rect, float angle, bool HighQuality)
{
Bitmap result = new Bitmap((int)rect.Width, (int)rect.Height);
using (Graphics g = Graphics.FromImage(result))
{
g.InterpolationMode = HighQuality ? InterpolationMode.HighQualityBicubic : InterpolationMode.Default;
using (Matrix mat = new Matrix())
{
mat.Translate(-rect.Location.X, -rect.Location.Y);
mat.RotateAt(-(angle), rect.Location);
g.Transform = mat;
g.DrawImage(source, new System.Drawing.Point(0, 0));
}
}
return result;
}
EDIT:
The answer to the first point is much easier than I had originally thought. You can always get the top-left corner of the rectangle by calling—
double top = Canvas.GetTop(rect);
double left = Canvas.GetLeft(rect);
You can then calculate the rest of the points using the width and the height—
Point topLeft = new Point(left, top);
Point topRight = new Point(left + rect.Width, top);
Point bottomLeft = new Point(left, top + rect.Height);
Point bottomRight = new Point(left + rect.Width, top + rect.Height);
Point centerPoint = new Point(left + (rect.Width / 2), top + (rect.Height / 2));
If your rectangle is rotated, then you have to translate these points to determine where they truly lie on the canvas—
public Point TranslatePoint(Point center, Point p, double angle)
{
// get the point relative to (0, 0) by subtracting the center of the rotated shape.
Point relToOrig = new Point(p.X - center.X, p.Y - center.Y);
double angleInRadians = angle * Math.PI / 180;
double sinOfA = Math.Sin(angleInRadians);
double cosOfA = Math.Cos(angleInRadians);
Point translatedPoint = new Point(relToOrig.X * cosOfA - relToOrig.Y * sinOfA,
relToOrig.X * sinOfA + relToOrig.Y * cosOfA);
return new Point(translatedPoint.X + center.X, translatedPoint.Y + center.Y);
}
Once you are able to translate the top-left corner, you can use Rotem's cropping method. You can also calculate the position of the rest of the rectangle, so you are able to determine if the rectangle is within the bounds of the image, if it is touching an edge, or any other thing that you might want to do in regards to the position.
I discovered the answer to my own question(s), and made the appropriate edits along the way. Please see above for the answer.
I'd like to ask whether it is possible to shear object without actually moving it. Here's the code I'm doing it right now
Matrix matrix = new Matrix();
matrix.Shear(2, 0);
g.Transform = matrix ;
g.DrawRectangle(Pens.Black, new Rectangle(200, 200, 100, 100));
g.ResetTransform();
The Shear factors are relative to the origin of the coordinate system.
So to keep the shear result at the 'same' location you need to add a translation matrix.
Create a translation that moves the point that should be static to the origin of the coordinate system. In the example the static point is (200,300) so the translation is (-200, -300)
apply the translation
Shear
create the inverse of the translation. In the example: (200, 300)
apply the inverse translation
BTW: Make sure you Dispose the matrices and other GDI+ objects!!
Matrix matrix = new Matrix();
matrix.Translate(200, 300);
matrix.Shear(2, 0);
matrix.Translate(-200, -300);
g.Transform = matrix ;
g.DrawRectangle(Pens.Black, new Rectangle(200, 200, 100, 100));
g.ResetTransform();
Or
using (var g = this.CreateGraphics())
{
using(Matrix translation = new Matrix(),
reverseTranslation = translation.Clone(),
sheer = new Matrix()
combination = new Matrix())
{
translation.Translate(200, 300);
reverseTranslation.Invert();
sheer.Shear(2, 0);
combination.Multiply(translation);
combination.Multiply(sheer);
combination.Multiply(reverseTranslation);
g.Transform = combination;
g.DrawRectangle(Pens.Black, new Rectangle(200, 200, 100, 100));
g.ResetTransform();
g.DrawRectangle(Pens.Black, new Rectangle(200, 200, 100, 100));
}
}
This is what you need to do:
Translate the lower-left corner of your rectangle to the origin.
Let the offset be (-dX, -dY).
Apply your shear transform.
Apply the inverse translation to your rectangle, i.e., (dX, dY).