Title: Fill an ellipse with random lines in C#
As the title implies, this example draws an ellipse filled with random lines. It cannot simply draw the ellipse in the form's Paint event handler, however. That would make the program generate a new set of random lines every time the form refreshes and that produces a strange result.
The program uses the following code to generate the line data when the form loads or resizes.
// Drawing objects.
private const int EllipseMargin = 10;
private int EllipseCx, EllipseCy, EllipseWidth, EllipseHeight;
private List<PointF> LinePoints = null;
// Redraw on resize.
private void Form1_Load(object sender, EventArgs e)
{
this.ResizeRedraw = true;
// Make the initial drawing objects.
MakeDrawingObjects();
}
// The form has resized. Generate the drawing objects.
private void Form1_Resize(object sender, EventArgs e)
{
MakeDrawingObjects();
}
// Make the drawing objects.
private void MakeDrawingObjects()
{
// Calculate the ellipse parameters.
EllipseWidth = this.ClientSize.Width - 2 * EllipseMargin;
EllipseHeight = this.ClientSize.Height - 2 * EllipseMargin;
// Make random lines connecting points
// on the edge of the ellipse.
EllipseCx = this.ClientSize.Width / 2;
EllipseCy = this.ClientSize.Height / 2;
Random rand = new Random();
double circumference = 2 * Math.PI * Math.Sqrt(
(EllipseWidth * EllipseWidth +
EllipseHeight * EllipseHeight) / 2);
int num_points = (int)(circumference / 40);
LinePoints = new List<PointF>();
for (int i = 0; i < num_points; i++)
{
double theta1 = 2 * Math.PI * rand.NextDouble();
float x1 = (float)(EllipseCx +
Math.Cos(theta1) * EllipseWidth / 2);
float y1 = (float)(EllipseCy +
Math.Sin(theta1) * EllipseHeight / 2);
LinePoints.Add(new PointF(x1, y1));
double theta2 = 2 * Math.PI * rand.NextDouble();
float x2 = (float)(EllipseCx +
Math.Cos(theta2) * EllipseWidth / 2);
float y2 = (float)(EllipseCy +
Math.Sin(theta2) * EllipseHeight / 2);
LinePoints.Add(new PointF(x2, y2));
}
}
The MakeDrawingObjects method does all the work. It starts by calculating the ellipse's dimensions. It then uses the formula C = 2 * Pi * Sqrt(Width2 + Height2) to approximate the ellipse's circumference. It then divides the circumference by 40 to decide how many random lines to generate.
For each line, the program generates two random points on the ellipse's edge. See the code above for the the formulas it uses. These are basically the equations for points on a circle scaled by the ellipse's width and height in the X and Y directions.
Because this program generates points on the ellipse's edge, the lines don't extend beyond the edges of the ellipse so the code doesn't need to set any kind of drawing region before drawing the lines.
The following code shows how the program draws the ellipse and the lines.
// Draw the ellipse and lines.
private void Form1_Paint(object sender, PaintEventArgs e)
{
if ((EllipseWidth <= 0) || (EllipseHeight <= 0)) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Fill and outline the ellipse.
e.Graphics.FillEllipse(Brushes.LightBlue,
EllipseMargin, EllipseMargin, EllipseWidth, EllipseHeight);
e.Graphics.DrawEllipse(Pens.Blue,
EllipseMargin, EllipseMargin, EllipseWidth, EllipseHeight);
// Draw the lines.
e.Graphics.DrawLines(Pens.Blue, LinePoints.ToArray());
}
This code fills the ellipse and outlines it. It then calls DrawLines to draw the lines.
Because the Resize event handler calls MakeDrawingObjects, the program generates new lines whenever it resizes, which still produces a somewhat odd result. If you want to use the same lines, you can take a few different approaches. For example, you can simply remove the Resize event handler. You could scale the ellipse and its lines so they fill the form when it resizes. You could also store the angles used to generate the lines instead of the lines' end points. I'll leave those as exercises.
Download the example to experiment with it and to see additional details.
|