Title: Let the user draw a smooth curve in C#
This example lets the user click points to draw a smooth curve. When the user clicks the left mouse button, the program adds a point to the curve. When the user clicks the right button, the program stops drawing the current curve. If the user then clicks the left button again, the program starts drawing a new smooth curve.
The following code shows variables that the program uses to keep track of what it is doing and how it should draw the curve whether it is in progress or a finished curve.
// True when we are drawing.
private bool Drawing = true;
// The currently selected points.
private List<Point> Points = new List<Point>();
// The curve's tension.
private float Tension = 0.5f;
The variable Drawing is true while the program is defining a new smooth curve. Initially it is true.
The Points list holds the points that define the current smooth curve.
The Tension variable stores the tension parameter that is used when drawing the smooth curve. The program allows the user to select values between 0.0 and 5.0. Smaller values make the curve lie more closely to straight lines connecting the points. Larger values make the curve smoother when it
The following MouseClick event handler executes whenever the user clicks a mouse button.
// The user clicked. Add a point,
// stop drawing, or start a new curve.
private void picCanvas_MouseClick(object sender, MouseEventArgs e)
{
// See if we are currently drawing.
if (Drawing)
{
// See if this is the left or right mouse button.
if (e.Button == MouseButtons.Left)
{
// Left button. Add a new point.
Points.Add(e.Location);
}
else
{
// Right button. Stop drawing.
Drawing = false;
}
}
else
{
// We are not drawing. Start a new curve.
Drawing = true;
Points = new List<Point>();
// Add a new point.
Points.Add(e.Location);
}
// Redraw.
picCanvas.Refresh();
}
This code is somewhat long but relatively straightforward. If the program is currently drawing a smooth curve, then it determines which button is being clicked. If the user clicked the left button, then the code adds a new point to the Points list. If the user clicked the right button, then the code sets Drawing to false to indicate that it is done drawing the current curve.
If the program is not currently drawing, then it sets Points to a new list and adds the clicked point to the list to start a new curve.
In any case, the code refreshes the picCanvas PictureBox. That makes the following Paint event handler execute to draw the smooth curve.
// Draw the curve and its points.
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Draw the curve.
if (Points.Count > 1)
{
// Make a pen to use.
using (Pen pen = new Pen(Color.Blue))
{
// See if we're currently drawing.
if (Drawing)
{
// Use a dashed pen.
pen.DashPattern = new float[] { 5, 5 };
}
// Draw the curve.
e.Graphics.DrawCurve(pen, Points.ToArray(), Tension);
}
}
// Draw the points.
if (Drawing && (Points.Count > 0))
{
const int r = 4;
foreach (Point point in Points)
{
Rectangle rect = new Rectangle(
point.X - r, point.Y - r, 2 * r, 2 * r);
e.Graphics.FillRectangle(Brushes.White, rect);
e.Graphics.DrawRectangle(Pens.Black, rect);
}
}
}
This code sets the Graphics object's SmoothingMode to produce smooth curves. Then, if the Points list contains more than one point, the code draws the curve. To do that, it creates a new blue pen. If the user is still drawing the curve, the code sets the pen's DashPattern to draw 5 pixels and then skip 5 pixels. (You could simply set the pen's DashStyle to Dash, but that produces very small dashes so I think this code produces a better result.) The code then draws the curve, passing the DrawCurve method the pen, the points (converted into an array), and the tension.
Having drawn the curve, the code then draws the points. If the user is still drawing the curve and the Points list contains at least one point, then the code loops through the Points list. For each point, it creates a rectangle at the point's position, fills the rectangle with white, and then outlines the point in black.
The program's last piece is the following event handler, which execute whenever the user adjusts the tension scroll bar.
// Adjust the curve's tension.
private void scrTension_Scroll(object sender, ScrollEventArgs e)
{
Tension = scrTension.Value / 10f;
lblTension.Text = Tension.ToString();
picCanvas.Refresh();
}
This code gets the scroll bar's value and divides it by 10. That allows the user to select values to the nearest tenth. The scroll bar has the following properties.
- Minimum = 0
- Maximum = 59
- SmallChange = 1
- LargeChange = 10
The event handler divides the scroll bar's value by 10 to allow the user to select tenths. That means the LargeChange value (which is used when the user clicked between the scrollbar's thumb and arrows) adjust the value by 10, which is converted into 1 unit of tension.
Because of a weirdness in the way scroll bars work, the user can interactively select values between Minimum and Maximum - LargeChange + 1, so in this example that means the user can select scroll bar values between 0 and 59 - 10 + 1 = 50. After dividing by 10, that means the user can select tension values between 0 and 5.
After it divides the scroll bar value by 10 to get tension to the nearest tenth, the scrTension event handler displays the tension in the lblTension label ad then refreshes the PictureBox.
Download the example program to experiment with the program.
Download the example to experiment with it and to see additional details.
|