Draw custom ellipse in winform - c#

In System.Drawing and System.Drawing.Drawing2D, I can only draw horizontal or vertical shape. Now i want to draw custom shape.
Given the coordinate of points A, B, C, D. I want to draw an ellipse like the blue one in the picture.

The example below is taken from MSDN:
private void RotateTransformAngle(PaintEventArgs e)
{
// Set world transform of graphics object to translate.
e.Graphics.TranslateTransform(100.0F, 0.0F);
// Then to rotate, prepending rotation matrix.
e.Graphics.RotateTransform(30.0F);
// Draw rotated, translated ellipse to screen.
e.Graphics.DrawEllipse(new Pen(Color.Blue, 3), 0, 0, 200, 80);
}

The correct solution involves:
Calculating the center
using Graphics.TranslateTransform to move the center to the origin
Calculating the Size and the Location of the bounding Rectangle
using Graphics.RotateTransform to rotate the canvas
Drawing the ellipse with Graphics.DrawEllipse
Resetting the Graphcis object
This does take a little Math but will produce real and fine ellipses..
For fun you also may want to play with a cheap, fake solution: I uses the DrawClosedCurve method with a tension.
To test I added a TrackBar set with a Maximum of 100.
Values of around 80, i.e. Tensions of around 0.8f create pretty nice ellipsoids:
private void panel1_Paint(object sender, PaintEventArgs e)
{
List<Point> points1 = new List<Point>()
{ new Point(300, 100), new Point(500, 300), new Point(400, 500), new Point(200, 300) };
List<Point> points2 = new List<Point>()
{ new Point(100, 100), new Point(500, 100), new Point(500, 400), new Point(100, 400) };
e.Graphics.DrawClosedCurve(Pens.Red, points1.ToArray(),
(float)(trackBar1.Value / 100f), System.Drawing.Drawing2D.FillMode.Alternate);
e.Graphics.DrawClosedCurve(Pens.Blue, points2.ToArray(),
(float)(trackBar1.Value / 100f), System.Drawing.Drawing2D.FillMode.Alternate);
}

Related

rotating Graphics/ image in c#

I have the following code which i wrote to try and rotate a bitmap(this is a test) the idea is to take a bitmap and rotate it by some amount of degrees and then draw it on the screen using win forms
protected override void OnDoubleClick(EventArgs e)
{
base.OnDoubleClick(e);
Graphics g = this.CreateGraphics();
Bitmap b = new Bitmap(path);
g.Clear(Color.White);
imagePosition = Cursor.Position;
b = RotateImage(b, 45);
g.DrawImage(b, new Point(100, 100));
}
public Bitmap RotateImage(Bitmap b, float angle)
{
Bitmap returnBitmap = new Bitmap(b.Width, b.Height);
returnBitmap.SetResolution(b.HorizontalResolution, b.VerticalResolution);
Graphics g = Graphics.FromImage(returnBitmap);
g.TranslateTransform((float)b.Width / 2, (float)b.Height / 2);
g.RotateTransform(angle);
g.TranslateTransform(-(float)b.Width / 2, -(float)b.Height / 2);
g.DrawImage(b, new Point(0, 0));
return returnBitmap;
}
this is the image before rotation
and this is the image after rotating 45 degrees like was shown in the code
The reason it's getting clipped is that there isn't enough space to display it rotated. The diagonal is longer than the sides (Pythagoras).
You need to make more space for the image, then it should display OK. How you do that will depend on what the image is contained in.

Matrix Transform of Rectangle after changing its bounds

I have a shape, for example a Rectangle which has the following bounds:
X = 100
Y = 100
Width = 100
Height = 100
I apply the following rotation to this rectangle using a new Matrix:
X = 100
Y = 100
Angle = 45
var transform = new Matrix();
transform.RotateAt(angle, point);
So the new Matrix has the following value:
0.7071068, 0.7071067, -0.7071067, 0.7071068, 150, -62.13202
I use this Matrix when I draw the Rectangle with Graphic:
protected override void OnPaint(PaintEventArgs e)
{
...
e.Graphic.Transform = transform;
g.DrawRectangle(Pen, bounds.X, bounds.Y, bounds.Width, bounds.Height);
}
The problem is the following: at a certain point I need to draw the same Rectangle but shifted by a certain offset, for example (50, 50). I have stored the Matrix transform and the Rectangle bounds. If I change only the bounds (adding the offset) the new Rectangle will be drawn in a wrong position, probably due to the previous rotation point.
How I have to change the Matrix in order to draw my Rectangle in the "right" position? that is, how can I retreive the right rotation point and the old rotation angle?
Try to add translation to the matrix using MatrixOrder.Prepend.
For offset (50, 50) it'll be:
transform.Translate(50, 50, MatrixOrder.Prepend);
Or create a separate matrix for this case:
var transformWithOffset = new Matrix();
transformWithOffset.Translate(50, 50);
transformWithOffset.RotateAt(angle, point);

Centering rotated graphicPath using the Matrix object in C#

I am writing a library that will create a graphihc path (In the shape of a polygon or rectangle) and rotate it but I want the rotated shape to be centered within its bounding rectangle. I have tried almost everything to get the shape to rotate on its center but it cutting off at the edges.
Below is some smaple code I have written to try to accomplish this
GraphicsPath path = new GraphicsPath();
path.AddPolygon(new Point[] { new Point(0, 0), new Point(100, 0), new Point(100, 100), new Point(0, 100) });
Matrix m = new Matrix();
Matrix m2 = new Matrix();
m2.Rotate(30);
m.Translate(-((path.GetBounds(m2).Width) / 2), -((path.GetBounds(m2).Height) / 2));
m.Rotate(30, MatrixOrder.Append);
m.Translate(((path.GetBounds(m2).Width)/2), ((path.GetBounds(m2).Height)/2), MatrixOrder.Append);
path.Transform(m);
Bitmap b = new Bitmap((int)path.GetBounds().Width, (int)path.GetBounds().Height);
Graphics g = Graphics.FromImage(b);
g.FillPath(Brushes.Blue, path);
b.Save(#"c:\aSSETS\sample3.png");
Please help. Thanks

Filling Color in a hexagon in WPF

I'm having problem in filling the hexagon using this code, when this code runs it draws only the outline of the hexagon that is "White", I want to fill the hexagon with a color but it is not working.
I have searched a lot and tried many things like drawingContext.Drawing() , drawingBrush, etc.
Am I missing something in this code? This is the code:
public void DrawHexagon(DrawingContext drawingContext)
{
GeometryGroup hexaKey = new GeometryGroup();
//making lines for hexagon
hexaKey.Children.Add(
new LineGeometry(new Point(X1, Y1), new Point(X2, Y2)));
hexaKey.Children.Add(
new LineGeometry(new Point(X2, Y2), new Point(X3, Y3)));
hexaKey.Children.Add(
new LineGeometry(new Point(X3, Y3), new Point(X4, Y4)));
hexaKey.Children.Add(
new LineGeometry(new Point(X4, Y4), new Point(X5, Y5)));
hexaKey.Children.Add(
new LineGeometry(new Point(X5, Y5), new Point(X6, Y6)));
hexaKey.Children.Add(
new LineGeometry(new Point(X6, Y6), new Point(X1, Y1)));
//
// Create a GeometryDrawing.
//
GeometryDrawing hexaKeyDrawing = new GeometryDrawing();
hexaKeyDrawing.Geometry = hexaKey;
// Paint the drawing with a gradient.
hexaKeyDrawing.Brush =new SolidColorBrush(Colors.Red);
// Outline the drawing with a solid color.
hexaKeyDrawing.Pen = new Pen(Brushes.White, 2);
drawingContext.DrawGeometry(hexaKeyDrawing.Brush, hexaKeyDrawing.Pen, hexaKeyDrawing.Geometry);
}
LineGeometry doesn't have a way to fill... they're just lines. You need a path. The MSDN has an example
An example, how to fill hexagons: http://www.codeproject.com/Articles/14948/Hexagonal-grid-for-games-and-other-projects-Part-1
In your example you have a number of LineGeometry instances inside a GeometryGroup inside a GeometryDrawing.
First, I'd link to bring to your attention that you're not actually using the GeometryDrawing. In your example you've used it solely as a place holder for your GemetryGroup.
Ignoring this the problem is that LineGeometry instances were not intended to draw shapes and GeometryGroup is not able to realize that your 6 LineSegments together form a closed shape.
Despair not however as there is a way to accomplish what you want: PathGeometry. This geometry essentially defines the contour of a region that may be filled! This contour may is defined by a starting point and a series of PathSegments.
private Point GetExtremity(Point center, double radius, double orientation)
{
return new Point(
center.X + Math.Cos(orientation) * radius,
center.Y + Math.Sin(orientation) * radius
);
}
public void DrawUniformShape(DrawingContext context, Brush brush, Pen pen, Point center, double radius, int sides, double orientationRadians)
{
context.DrawGeometry(
brush,
pen,
new PathGeometry(
Enumerable.Repeat(
new PathFigure(
GetExtremity(center, radius, orientationRadians),
from vertex in Enumerable.Range(1, sides - 1)
let angle = orientationRadians + vertex * 2 * Math.PI / sides
select new LineSegment(GetExtremity(center, radius, angle), true),
true
),
1
)
)
);
}
public void DrawBarnColouredHexagon(DrawingContext context, Point center, double radius, double orientation)
{
DrawUniformShape(
context,
Brushes.Red,
new Pen(Brushes.White, 2),
center,
radius,
6,
0
);
}

Strange rotation in C# graphics

I am using OnPaint method in my class Class1 : Panel.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
}
to rotate and draw rectangle I am using
Matrix m = new Matrix();
m.RotateAt(90, rotationPoint);
g.Transform = m;
g.FillRectangle(Brushes.Black, rectangle)
the problem is, that rotation isn't working as I want it to.
Red square is rotation point and it's located in the middle-top of rectangle. How to set x, y and rotation point so rotation would work properly?
After rotating at 90 degress it should look like this
red pixel is still at the same location.
Rotation point is not the point, which you want to rotate. It is point, around which graphics is rotated. So if you draw a rectangle on the top of the graphics and want to rotate it (rectangle) - then you should set rotation point as center of graphics and rotate image to 90 degrees.
Here is example, that does almost what you want:
base.OnPaint(e);
var g = e.Graphics;
var width = g.VisibleClipBounds.Width;
var height = g.VisibleClipBounds.Height;
var rotationPoint = new PointF(width / 2, height / 2); ;
// draw center point
g.FillRectangle(Brushes.Red, new RectangleF(rotationPoint.X - 5, rotationPoint.Y - 5, 10, 10));
using (var path = new GraphicsPath())
{
var rectangle = new RectangleF((width - 10) / 2, 0, 10, 10);
var m = new Matrix();
m.RotateAt(90, rotationPoint);
path.AddRectangle(rectangle);
path.Transform(m);
// draw rotated point
g.FillPath(Brushes.Black, path);
}

Categories

Resources