Title: Draw lines with gaps to show they are passing under other lines in C#
This example shows how to draw lines with gaps in them to show that they are passing under other lines. It seems like there must be a name for this, but I couldn't find it so I'm calling them "cut lines." (If you know the "official" name for this, please email me.)
You could calculate where two lines intersect and then break the line on the bottom into two pieces, shortening them a bit so they leave a gap where the upper line is supposed to be. If you had many lines, you might then need to break the pieces into smaller pieces and so on until you finish examining every pair of lines for intersections. That should all work, but it sounds like a lot of trouble.
Fortunately there's a much simpler way to draw lines with gaps like this. Loop through the lines in bottom-to-top order. For each line, first draw it with a slightly thicker pen that uses the background color. That creates a channel for the line through the lines below it. Then draws the line with its usual pen.
To make this slightly easier, I created the following method to draw lines.
// Draw a line segment in the indicated color.
private void DrawLine(Graphics gr, Pen bg_pen, Pen fg_pen,
Point start_point, Point end_point)
{
if (bg_pen != null)
gr.DrawLine(bg_pen, start_point, end_point);
gr.DrawLine(fg_pen, start_point, end_point);
}
If the background pen bg_pen is not null, the method draws the line using that pen. It then draws the line again using the foreground pen fg_pen.
The following code shows how the program's Paint event handler uses this method to draw lines.
private void picLines_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Draw the previously saved lines.
Pen bg_pen = null;
if (chkUseCuts.Checked) bg_pen = new Pen(picLines.BackColor, 8);
using (Pen fg_pen = new Pen(Color.Blue, 4))
{
for (int i = 0; i < StartPoints.Count; i++)
{
DrawLine(e.Graphics, bg_pen, fg_pen,
StartPoints[i], EndPoints[i]);
}
// Draw the new line if there is one.
if (Drawing)
{
fg_pen.Color = Color.Red;
DrawLine(e.Graphics, bg_pen, fg_pen,
NewStartPoint, NewEndPoint);
}
}
if (bg_pen != null) bg_pen.Dispose();
}
This code defines the bg_pen variable to hold the background pen and sets it to null. Then if you have checked the program's Use Cuts box, the method sets the pen equal to a new eight-pixel-wide pen using the drawing's background color.
The code then creates a four-pixel-wide blue pen.
Next the method loops through the line segments whose end points are stored in the StartPoints and EndPoints lists. For each segment, the code simply calls the earlier DrawLine method to draw the line above the previous lines.
If you are in the middle of drawing a new line, the program changes the foreground pen's color to red and draws the new line so far.
Finally, if the background pen is not null, the code calls its Dispose method. It is important to call the Dispose method of any object that has such a method so it can free up resources that are limited on the system. Pens and brushes are two common items that have a Dispose method.
If you define an object inside a using statement, as the code does with the foreground brush, then the program automatically calls its Dispose method when the using block ends.
Unfortunately this technique is harder to apply to more complicated objects such as self-overlapping polygons (like a star) or mutually overlapping objects (like interlocked circles). In those cases, you will probably need to draw all of the objects and then go back and draw just their points of intersections using the new technique. For an example that does something like this, see the post Draw interlocked circles in C#.
Download the example to experiment with it and to see additional details.
|