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 "device_context", the code to commence a path is shown below.

begin_path(device_context);

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.

draw_angle_arc draw_line_to draw_lines
draw_arc move_to draw_lines_to
draw_arc_to draw_sector draw_polygons
draw_chord draw_splines draw_polylines
close_figure draw_splines_to draw_rectangle
draw_ellipse polydraw draw_rounded_rectangle
extended_text_out draw_polygon text_out

A figure is automatically closed and a new figure commenced upon setting a new position via the function move_to. A figure may be closed manually using the function close_figure. 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 pen_style. The three options applicable to ending lines are shown in the table below.

end_round line ends are rounded with a semi-circle.
end_flat The line is left unaltered at the end.
end_square 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.

join_round A semi-circle is used to join adjacent lines.
join_bevel Adjacent lines are cut with a line.
join_mitre Adjacent lines are mitred.

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

Inside the window data structure, two arrays are declared to specify the various combinations of ends and joins - as shown below.

struct window_data
{
    int ends[3];
    int joins[3];
    int width_of_client,
        height_of_client;

    window_data()
    {
        ends[0] = pen_style::end_round;
        ends[1] = pen_style::end_square;
        ends[2] = pen_style::end_flat;
        joins[0] = pen_style::join_round;
        joins[1] = pen_style::join_bevel;
        joins[2] = pen_style::join_mitre;
    }

};

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

   case message::paint:
    {
        window_data* data = (window_data*)get_window_pointer(window_handle, 0);
        paint paint_structure;
        handle device_context = begin_paint(window_handle, &paint_structure);

        set_mapping_mode(device_context, unit::anisotropic);
        set_window_extent(device_context, 100, 100);
        set_viewport_extent(device_context, data->width_of_client, data->height_of_client);

        logical_brush logical_brush_select;

        logical_brush_select.style = brush_style::solid;
        logical_brush_select.color = icolor(128, 128, 128);
        logical_brush_select.hatch = 0;

        for (int i = 0; i < 3; i++)
        {
            select_object(device_context,
                extended_create_pen(pen_style::solid | pen_style::geometric |
                    data->ends[i] | data->joins[i],
                    10,
                    &logical_brush_select));

            begin_path(device_context);

            move_to(device_context, 10 + 30 * i, 25);
            draw_line_to(device_context, 20 + 30 * i, 75);
            draw_line_to(device_context, 30 + 30 * i, 25);

            end_path(device_context);

            stroke_path(device_context);

            delete_object(select_object(device_context,
                get_standard_object(standard_pen::black)));

            move_to(device_context, 10 + 30 * i, 25);
            draw_line_to(device_context, 20 + 30 * i, 75);
            draw_line_to(device_context, 30 + 30 * i, 25);
        }

        end_paint(window_handle, &paint_structure);
    }
    break;

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.