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.
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.
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.