Paths - Ends and Joins


Paths

A path is a sequence of lines and curves that is stored internally to the graphics subsystem. For a device context with handle "DeviceContext", the code to commence a path is shown below.

BeginPath(DeviceContext);

Subsequent to making this call, calls that produce lines and curves are stored in the device context rather than being rendered to the device. When complete, a path consists of a number of curvilinear figures. Figures may be generated via successive calls to the functions:

More generally, the following functions cause the generation of points within an open path.

DrawAngleArc DrawLineTo DrawLines
DrawArc MoveTo DrawLinesTo
DrawArcTo DrawSector DrawPolygons
DrawChord DrawSplines DrawPolylines
CloseFigure DrawSplinesTo DrawRectangle
DrawEllipse Polydraw DrawRoundedRectangle
TextOut - Extended DrawPolygon TextOut

A figure is automatically closed and a new figure commenced upon setting a new position via the function MoveTo. A figure may be closed manually using the function CloseFigure. After a figure has been closed, subsequent calls to curvilinear functions cause the generation of a new figure. Once a path has been completed, one of the five operations may be used on the path:

all of which destroy the path within the device context during execution.

Line Joins and Line Ends

The program of this section demonstrates the use of paths and line ends and joins. The options for joining and ending lines may be found in the enumeration PenStyle. The three options applicable to ending lines are shown in the table below.

EndRound Line ends are rounded with a semi-circle.
EndFlat The line is left unaltered at the end.
EndSquare A rectangle 1/2 the geometric width of the line extends beyond the end of the line.

The three options applicable to joining lines are shown in the table that follows.

JoinRound A semi-circle is used to join adjacent lines.
JoinBevel Adjacent lines are cut with a line.
EndSquare Adjacent lines are mitred.

To illustrate the different ends and joins, a program is used. The output of the program is shown below.

The portion of the program that performs the drawing is shown below.

void OnPaint(object source, PaintEventArgs e)
{
    DeviceContext deviceContext = new DeviceContext(this);

    deviceContext.MappingMode = Unit.Anisotropic;
    deviceContext.WindowExtent = new Point(100,100);
    deviceContext.ViewportExtent = new Point(W,H);

    Array<int> Ends = new Array<int>(){(int)PenStyle.EndRound,(int)PenStyle.EndSquare,(int)PenStyle.EndFlat};
    Array<int> Joins = new Array<int>() {(int)PenStyle.JoinRound,(int)PenStyle.JoinBevel,(int)PenStyle.JoinMitre};

    for (int i = 0; i < 3; i++)
    {
         deviceContext.Pen = new Pen((int)PenStyle.Solid | (int)PenStyle.Geometric | Ends[i] | Joins[i],
                                     10,
                                     new LogicalBrush((int)BrushStyle.Solid, 0x808080));

         deviceContext.BeginPath();
         deviceContext.CurrentPosition = new Point(10 + 30 * i, 25);
         deviceContext.DrawLineTo(20 + 30 * i, 75);
         deviceContext.DrawLineTo(30 + 30 * i, 25);
         deviceContext.EndPath();
         deviceContext.StrokePath();
         deviceContext.Pen = blackPen;
         deviceContext.CurrentPosition = new Point(10 + 30 * i, 25);
         deviceContext.DrawLineTo(20 + 30 * i, 75);
         deviceContext.DrawLineTo(30 + 30 * i, 25);
    }

}

A for loop containing 3 iterations is used to step through the arrays ends and joins whilst drawing a V shape inside a path. A pen with geometric width of 10 is used for the drawing. The path is stroked and the V shape is then drawn again using a cosmetic pen (which is of width 1). The variable i is also used to offset the V shapes.