GPIGuide - Area and Polygon Primitives: Difference between revisions
Tag: Undo |
|||
(31 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{IBM-Reprint}} | |||
{{GPIGuide}} | |||
An area is one or more closed figures that can be drawn filled, outlined, or filled and outlined. If an area includes more than one figure, those figures can be separate or intersecting. | An area is one or more closed figures that can be drawn filled, outlined, or filled and outlined. If an area includes more than one figure, those figures can be separate or intersecting. | ||
Line 16: | Line 18: | ||
The following figure is an example of an area. | The following figure is an example of an area. | ||
[[ | [[File:GPIAreaPoly_00.png|400px|An Area]] | ||
This area comprises two hexagons, one completely enclosed by the other. The area is filled with the current area-fill pattern. | This area comprises two hexagons, one completely enclosed by the other. The area is filled with the current area-fill pattern. | ||
Line 101: | Line 101: | ||
The following figure shows the patterns from the base pattern symbol set. Applications can determine the current pattern set by calling GpiQueryPattern. | The following figure shows the patterns from the base pattern symbol set. Applications can determine the current pattern set by calling GpiQueryPattern. | ||
[[Image:1032_L3_PatternSymbolAttribu_1.png | [[Image:1032_L3_PatternSymbolAttribu_1.png|border|The Base Pattern Symbol Set]] | ||
The Base Pattern Symbol Set | |||
===Pattern Reference Point Attribute=== | ===Pattern Reference Point Attribute=== | ||
Line 109: | Line 107: | ||
The pattern reference point is the point from which the area's fill-pattern spreads horizontally and vertically. The lower-left corner of the pattern is aligned on this point. The pattern reference point has a default value of (0,0), and is expressed in world coordinates. Applications can determine the pattern reference point with GpiQueryPatternRefPoint. Applications can specify the pattern reference point with GpiSetPatternRefPoint; however, this should not be done inside an area. The pattern reference point does not have to be within the boundary of the area. The following figure shows an area that was filled using the default pattern reference point. | The pattern reference point is the point from which the area's fill-pattern spreads horizontally and vertically. The lower-left corner of the pattern is aligned on this point. The pattern reference point has a default value of (0,0), and is expressed in world coordinates. Applications can determine the pattern reference point with GpiQueryPatternRefPoint. Applications can specify the pattern reference point with GpiSetPatternRefPoint; however, this should not be done inside an area. The pattern reference point does not have to be within the boundary of the area. The following figure shows an area that was filled using the default pattern reference point. | ||
[[Image:1033_L3_PatternReferencePoin_2.png]] | [[Image:1033_L3_PatternReferencePoin_2.png|border|The Pattern Reference Point]] | ||
The pattern of diagonal lines is aligned with the pattern reference point (0,0). When the picture is displayed or printed, only the hexagon will be filled. | The pattern of diagonal lines is aligned with the pattern reference point (0,0). When the picture is displayed or printed, only the hexagon will be filled. | ||
Line 131: | Line 129: | ||
An application can change the appearance of a fill pattern by changing its alignment in an area primitive with GpiSetPatternRefPoint. When the default reference point is set, the operating system aligns the lower-left corner of the fill pattern with the point (0,0) in the application's world space and begins filling the area. If an application adjusts the pattern reference point to (3,2), The operating system aligns the lower-left corner of the fill pattern with the point (3,2) in the application's world space and begins filling the area. By moving the reference point from (0,0) to (3,2), the fill pattern appears shifted up two pels and to the right three pels. | An application can change the appearance of a fill pattern by changing its alignment in an area primitive with GpiSetPatternRefPoint. When the default reference point is set, the operating system aligns the lower-left corner of the fill pattern with the point (0,0) in the application's world space and begins filling the area. If an application adjusts the pattern reference point to (3,2), The operating system aligns the lower-left corner of the fill pattern with the point (3,2) in the application's world space and begins filling the area. By moving the reference point from (0,0) to (3,2), the fill pattern appears shifted up two pels and to the right three pels. | ||
===Custom Fill Patterns from a Bit Map=== | =====Custom Fill Patterns from a Bit Map===== | ||
To create a custom pattern from a hard-coded bit map, an application must use the following steps: | To create a custom pattern from a hard-coded bit map, an application must use the following steps: | ||
Line 140: | Line 138: | ||
The application can now draw the area. | The application can now draw the area. | ||
===Custom Fill Patterns from a Font Symbol=== | =====Custom Fill Patterns from a Font Symbol===== | ||
To create a custom pattern from a character or a symbol in a font: | To create a custom pattern from a character or a symbol in a font: | ||
Line 148: | Line 146: | ||
The application can now draw the area. | The application can now draw the area. | ||
===Area Colors and Mix Attributes=== | |||
The color attribute defines the color used to draw a primitive or an object. The mix attribute determines how the color of a primitive or an object is combined with the color of the drawing surface, or any other objects on the surface. Both attributes also are described in Color and Mix Attributes. | |||
The area color defines the color used to fill the output from any of the IBM OS/2 area functions, when necessary. The area primitive is the only primitive in which the color can be changed during the drawing of the area. Therefore, this attribute, more than the other area attributes, depends on the current value as described in Attribute Currentness. | |||
When a presentation space is created, the area color initial default is black. The pattern symbol initial default, explained previously, is solid. Areas are one of the primitives that have a foreground and background color. | |||
[[Image:GPIAreaPoly_03.png|border|Area Primitives]] | |||
Area primitives have both a color and background color attribute. The background color does not appear if the pattern symbol is solid, and the background color is undefined if the pattern symbol is a customized, multi-colored bit map. | |||
When a presentation space is created, the area mix attribute initial default is FM_OVERPAINT. The overpaint mix attribute specifies that the area color is not to be modified by the color of the drawing surface. If the area mix attribute is changed, the area color is mixed with colors that are already on the drawing surface. | |||
When the pattern symbol is solid, the color that fills the area, if necessary, is the current area foreground color. If the pattern symbol is changed to be a pattern of vertical lines, for example, the color of those lines is the current area foreground color. Inside of the area bracket, there can be other colors if these colors are the current color for primitives such as lines or arcs, that are drawn within the area bracket. These colors are not specifically defined or influenced by the area foreground color. | |||
The area background color initial default is CLR_BACKGROUND. Usually this is defined by the application to the same color as the drawing surface. If the pattern symbol is solid, the area background color does not appear. If the pattern symbol is changed to be a pattern of vertical lines, for example, the color in between those lines is the current area background color. | |||
The area background mix attribute initial default is BM_LEAVEALONE. The leave-alone background mix attribute specifies that the area background color is not drawn. This means that for a nonsolid pattern symbol, the drawing-surface color or the color of an object, not created by the area bracket, but on the drawing surface, shows through the nonsolid pattern. The area background color, for nonsolid pattern symbols, appears only if the background mix attribute is changed to overpaint, BM_OVERPAINT. | |||
If you have customized the pattern symbol with a bit map, the color definitions of the area primitive change. The foreground color corresponds to the color of the pels that are specified ON in the fill-pattern bit map. The background color corresponds to the color of the pels that are specified OFF in the fill-pattern bit map. The foreground and background mix attribute do not change. | |||
Note: Background color and mix attribute only apply to monochrome (2-color) fill patterns. The bit set to 0 is defined as the background and the bit set to 1 is defined as the foreground. A multi-colored bit map is unaffected by the background color and mix attributes. | |||
To specify a new color or mix attribute call GpiSetAttrs. This function accepts as input the type of primitive, for example PRIM_AREA, a list of attributes that are to be changed, a list of attributes that are to be set to their default values, and the values for the attributes that are to be changed. GpiSetAttrs is useful to specify colors and mix attributes just for a specific data structure -for example the AREABUNDLE structure. GpiSetAttrs also provides some protection against invalid colors. | |||
To determine the current area color and mix attribute, call GpiQueryAttrs. This function accepts as input the primitive type and the attributes in question. It returns as output an array of values for the specifically queried attributes. | |||
To reset the default area color and mix attribute, just as with any other attribute specified in the AREABUNDLE. data structure, call GpiSetDefAttrs. This function accepts as input the type of primitive, for example PRIM_AREA, the attributes to be changed, and the values that will become the new default values. The changing of default values is important when working with segments. Changing the default values during a series of drawing functions is not recommended. | |||
The area color and mix attribute also can be specified with: | |||
* [[GpiSetColor]] | |||
* [[GpiSetMix]] | |||
* [[GpiSetBackColor]] | |||
* [[GpiSetBackMix]] | |||
However, these functions have the disadvantage of specifying the foreground and background color or mix attribute for all primitive BUNDLE data structures that have the respective component. | |||
There are four queries that determine the color and mix attribute as specified by GpiSet... functions: | |||
* [[GpiQueryColor]] | |||
* [[GpiQueryMix]] | |||
* [[GpiQueryBackColor]] | |||
* [[GpiQueryBackMix]] | |||
If the area color, area background color, mix attribute, or background mix attribute were specified individually, the aforementioned queries can return a value inconsistent with the current area attribute. | |||
===Area Brackets=== | |||
Areas also are referred to as area brackets, because the functions that create and define the area always are "bracketed" by the two functions, [[GpiBeginArea]] and [[GpiEndArea]]. Only one area is defined between these two functions. However, within the area, there can be any number of adjacent, intersecting, or completely separate area primitives. | |||
[[GpiBeginArea]] signals the start of a group of primitives that define the boundary of the area. The current position is not changed by [[GpiBeginArea]], although it is updated by any drawing instructions that follow. | |||
If you call [[GpiSetCurrentPosition]] or [[GpiMove]] within an area definition, the current figure is closed automatically, and a new figure is started at the current position by the next line or curve. A figure in the area, whose start and end points are not the same, is closed by drawing a straight line from the current position to the start position of the figure. | |||
[[GpiEndArea]] signals the end of an area definition and tells the operating system to draw the area. If an application does not close a figure before calling [[GpiEndArea]], the figure is closed automatically by drawing a straight line from the end point of the last line or curve to the start point of the current figure. The current position is always updated to the end point of the last line drawn. | |||
The functional sequence to draw an area could be: | |||
<pre> | |||
#include <os2.h> | |||
void fncAREA01(void){ | |||
#if 0 | |||
GpiBeginArea /* Starts the area bracket */ | |||
GpiSetCurrentPosition /* Set the start point of the outer hexagon. */ | |||
GpiPolyLine /* Draw the outer hexagon. */ | |||
GpiSetCurrentPosition /* Set the start point of the inner hexagon. */ | |||
GpiPolyLine /* Draw the inner hexagon. */ | |||
GpiEndArea /* End the area definition. */ | |||
#endif | |||
} | |||
</pre> | |||
An area bracket contains the functions that define an area. Only one area can be defined between "bracket" functions. | |||
Following the beginning of an area bracket, an application can define the shape and location of the area in world space by using the | |||
following line and arc functions: | |||
* [[GpiBox]] | |||
* [[GpiFullArc]] | |||
* [[GpiLine]] | |||
* [[GpiPartialArc]] | |||
* [[GpiPointArc]] | |||
* [[GpiPolyFillet]] | |||
* [[GpiPolyFilletSharp]] | |||
* [[GpiPolyLine]] | |||
* [[GpiPolySpline]] | |||
If an application calls either [[GpiBox]] or [[GpiFullArc]] inside an area, it must use the DRO_OUTLINE option. | |||
In addition to the drawing functions, an application also can use the following specification functions inside an area bracket: | |||
* [[GpiBeginElement]] | |||
* [[GpiCallSegmentMatrix]] | |||
* [[GpiComment]] | |||
* [[GpiElement]] | |||
* [[GpiEndArea]] | |||
* [[GpiEndElement]] | |||
* [[GpiGetData]] | |||
* [[GpiLabel]] | |||
* [[GpiMove]] | |||
* [[GpiOffsetElementPointer]] | |||
* [[GpiPop]] | |||
* [[GpiPutData]] | |||
* [[GpiSetArcParams]] | |||
* [[GpiSetAttrMode]] | |||
* [[GpiSetAttrs]] | |||
* [[GpiSetColor]] | |||
* [[GpiSetCurrentPosition]] | |||
* [[GpiSetEditMode]] | |||
* [[GpiSetElementPointer]] | |||
* [[GpiSetElementPointerAtLabel]] | |||
* [[GpiSetLineEnd]] | |||
* [[GpiSetLineJoin]] | |||
* [[GpiSetLineType]] | |||
* [[GpiSetLineWidth]] | |||
* [[GpiSetMix]] | |||
* [[GpiSetModelTransformMatrix]] | |||
* [[GpiSetSegmentTransformMatrix]] | |||
An application also can use the following query functions inside an area bracket: | |||
* [[GpiQueryArcParams]] | |||
* [[GpiQueryAttrMode]] | |||
* [[GpiQueryAttrs]] | |||
* [[GpiQueryBackColor]] | |||
* [[GpiQueryBackMix]] | |||
* [[GpiQueryBoundaryData]] | |||
* [[GpiQueryCharAngle]] | |||
* [[GpiQueryCharBox]] | |||
* [[GpiQueryCharDirection]] | |||
* [[GpiQueryCharMode]] | |||
* [[GpiQueryCharSet]] | |||
* [[GpiQueryCharShear]] | |||
* [[GpiQueryCharStringPos]] | |||
* [[GpiQueryCharStringPosAt]] | |||
* [[GpiQueryClipBox]] | |||
* [[GpiQueryClipRegion]] | |||
* [[GpiQueryColor]] | |||
* [[GpiQueryColorData]] | |||
* [[GpiQueryColorIndex]] | |||
* [[GpiQueryCp]] | |||
* [[GpiQueryCurrentPosition]] | |||
* [[GpiQueryDefaultViewMatrix]] | |||
* [[GpiQueryDefCharBox]] | |||
* [[GpiQueryDevice]] | |||
* [[GpiQueryDeviceBitmapFormats]] | |||
* [[GpiQueryEditMode]] | |||
* [[GpiQueryFontFileDescriptions]] | |||
* [[GpiQueryFontMetrics]] | |||
* [[GpiQueryFonts]] | |||
* [[GpiQueryGraphicsField]] | |||
* [[GpiQueryInitialSegmentAttrs]] | |||
* [[GpiQueryKerningPairs]] | |||
* [[GpiQueryLineEnd]] | |||
* [[GpiQueryLineJoin]] | |||
* [[GpiQueryLineType]] | |||
* [[GpiQueryLineWidth]] | |||
* [[GpiQueryLineWidthGeom]] | |||
* [[GpiQueryLogColorTable]] | |||
* [[GpiQueryMarker]] | |||
* [[GpiQueryMarkerBox]] | |||
* [[GpiQueryMarkerSet]] | |||
* [[GpiQueryMix]] | |||
* [[GpiQueryModelTransformMatrix]] | |||
* [[GpiQueryNearestColor]] | |||
* [[GpiQueryNumberSetIds]] | |||
* [[GpiQueryPageViewport]] | |||
* [[GpiQueryPattern]] | |||
* [[GpiQueryPatternRefPoint]] | |||
* [[GpiQueryPatternSet]] | |||
* [[GpiQueryPel]] | |||
* [[GpiQueryPickAperturePosition]] | |||
* [[GpiQueryPickApertureSize]] | |||
* [[GpiQueryRealColors]] | |||
* [[GpiQueryRegionBox]] | |||
* [[GpiQueryRegionRects]] | |||
* [[GpiQueryRGBColor]] | |||
* [[GpiQuerySegmentAttrs]] | |||
* [[GpiQuerySegmentNames]] | |||
* [[GpiQuerySegmentPriority]] | |||
* [[GpiQuerySegmentTransformMatrix]] | |||
* [[GpiQuerySetIds]] | |||
* [[GpiQueryStopDraw]] | |||
* [[GpiQueryTag]] | |||
* [[GpiQueryViewingLimits]] | |||
* [[GpiQueryViewingTransformMatrix]] | |||
* [[GpiQueryWidthTable]] | |||
===Area Bracket Attributes=== | |||
In addition to the attributes controlled by the AREABUNDLE data structure, there are two attributes that can be specified for each individual area bracket: | |||
* Area boundary | |||
* Area construction | |||
These bracket attributes affect how the area primitives inside the bracket are drawn. The concept of attribute currentness is especially important to areas and paths that contain multiple figures. | |||
===Area Boundaries=== | |||
An application specifies the area boundary when it calls GpiBeginArea. There are two options: | |||
* BA_BOUNDARY (the default) | |||
* BA_NOBOUNDARY. | |||
The BA_BOUNDARY value tells the programming interface to draw all outlines of the area primitives within the area bracket, using a line that conforms to the current LINEBUNDLE attributes. If the line attributes have not been changed, the default outline color is black on most displays and printers, and the default line style is solid. An application can change the line color and line styles within the area bracket. The interior of the area primitive is filled with the current pattern. | |||
To prevent the interface from outlining an area, an application can use the BA_NOBOUNDARY flag when calling GpiBeginArea. Only the interior fill pattern is visible. This value most often is used when an area contains many overlapping figures, and the interior lines are not desired. | |||
You could think of this option in terms similar to the outline and fill options discussed with boxes and full arcs. The BA_BOUNDARY value corresponds to DRO_OUTLINEFILL, and BA_NOBOUNDARY, to DRO_FILL. There is no distinct boundary value that corresponds to DRO_OUTLINE, the simple outline. To simulate this effect, OR the BA_NOBOUNDARY value with the appropriate area construction value when calling GpiBeginArea. | |||
===Area Construction=== | |||
An application specifies the area construction when it calls GpiBeginArea. There are two options: | |||
* BA_ALTERNATE (the default) | |||
* BA_WINDING. | |||
Construction modes also are called area-fill modes. They provide different ways of determining whether a given point is included in the filled area. Normally, the construction mode you use is a matter of personal preference. | |||
====Alternate Mode==== | |||
In alternate mode, the following occurs: | |||
* A point is included in the filled area if you have to cross an odd number of lines in the area when drawing a line from that point to infinity. | |||
* A point is not included in the filled area if you have to cross an even number of lines in the area when drawing a line from that point to infinity. | |||
In the example in the following figure, the inner hexagon is not shaded, because to draw a line from any point in the hexagon to infinity, you must cross two boundary lines. The remainder of the area is shaded, because to move outside the area, you need to cross only one boundary line. | |||
[[Image:GPIAreaPoly_04.png|border|Calculating Filled Areas Constructed in Alternate Mode ]] | |||
====Winding Mode==== | |||
In winding mode, the direction in which the boundary lines in the area are drawn determines whether a given point is included in the filled area. The direction of a line depends on both the graphics functions used to draw it and the world coordinates that define it. For example, if the current position of a presentation space is (c,c), and GpiBox is called with the diagonally-opposite corner of the box specified as (d,d), GpiBox always draws the box in the following order: | |||
1. (xc.,yc.) to | |||
2. (xd.,yc.) to | |||
3. (xd.,yd.) to | |||
4. (xc.,yd.) and returning to | |||
5. (xc.,yc.). | |||
As illustrated in the following figure, in some cases the box is drawn in a counterclockwise direction. When either xd. is less than xc., or yd. is less than yc., but not both, a box is drawn clockwise. | |||
[[Image:GPIAreaPoly-05.png|border|The Box]] | |||
The current position is (3,2) and the specified corner is at (8,6). The box is drawn from (3,2) to (8,2) to (8,6) to (3,8) to (3,2). | |||
For the polyline primitive, the direction in which a line is drawn depends on the relative values of the end points of each line, so you can choose whether to draw in a clockwise or counterclockwise direction. | |||
To determine if a given point is included in the filled area, count the number of lines to be crossed to move from that point to infinity. For each boundary line drawn in one direction, add one to the tally. For each line drawn in the opposite direction, subtract one from the tally. A point is within the area if the result is nonzero. | |||
If two figures -for example, the hexagons in the following figure- are drawn in different directions, the tally for the inner hexagon is 0 and the area will look exactly as it does in alternate mode. | |||
[[Image:GPIAreaPoly_06.png|border|Area Constructed in Different Directions in Winding Mode]] | |||
If the two hexagons are drawn in the same direction, the result is 2, and the inner hexagon is shaded as shown in the following figure. | |||
[[Image:GPIAreaPoly_07.png|border|Area Constructed in the Same Direction in Winding Mode]] | |||
The boundary lines of the area in the previous figure have been drawn and are visible through the area-fill pattern. The boundary lines of an area primitive do not have to be drawn; but if they are, they are drawn according to the current line attributes. | |||
To vary the appearance of different parts of the boundary line, you can change the current line attributes during area definition. | |||
The boundary lines of an area are considered a part of the area's interior. Therefore, when you draw an area without boundary lines (BA_NOBOUNDARY), the area-fill pattern extends to include the boundaries of the area, and the area is the same size it would be if the boundary lines had been drawn. | |||
===Attribute Currentness=== | |||
Graphics functions that change attributes are valid within the area bracket. There are misconceptions, however, about which attributes are used when the figures are displayed in a window or drawn to the printer. | |||
Review the following functional sequence: | |||
{| class="wikitable" | |||
|- | |||
! Function !! Effect | |||
|- | |||
| [[GpiSetColor]] || Sets color to red. | |||
|- | |||
| [[GpiBeginArea]] || Opens area bracket | |||
|- | |||
| [[GpiLine]] || Draws a straight line | |||
|- | |||
| [[GpiSetColor]] || Sets color to green. | |||
|- | |||
| [[GpiPolyLine]] || Draws two additional lines to form a triangle. | |||
|- | |||
| [[GpiEndArea]] || Ends the area bracket and displays a picture. | |||
|} | |||
If you are displaying on a color monitor, the image appears as follows: | |||
The triangle has one red line, drawn with [[GpiLine]] and two green lines, drawn with [[GpiPolyLine]]. The interior of the triangle, if drawn, is red. Red is the color that was current when the area was defined and, therefore, is the current color for the area interior. In terms of the interior area, green is only the color that was current when the function that initiates drawing was called. | |||
If the application immediately opened a new area bracket, the interior of that bracket, if drawn, would be green. The color attribute for the second AREABUNDLE, is not "inherited" from the last AREABUNDLE drawn. | |||
==About Polygon Primitives== | ==About Polygon Primitives== | ||
Area brackets have the flexibility to draw any combination of curved or straight lines and combine the results into a closed figure. An advantage that polygons sometimes have over area brackets, however, is that they require fewer time-consuming calculations to provide that kind of flexibility. | |||
The operating system provides a function that enables you to draw multiple straight-line closed areas outside of an area bracket. Like bracket-generated areas, they can be adjacent, intersecting, or completely separate. | |||
The function is GpiPolygons and the set of objects it draws are called polygon primitives. A polygon primitive is any set of polygons with specified vertices that can be filled or filled and outlined. This function accepts as input the desired number of polygons, the POLYGON data structure for each polygon, and a boundary and construction option similar to those of the GpiBeginArea function. | |||
The purpose of GpiPolygons is to enable you to specify an area in such a way as to pass all of the area boundaries at once. This improves performance significantly because the operating system cannot process the accumulated primitives inside an area bracket until it reaches a GpiEndArea. GpiPolygons is not valid inside an area bracket because the figures it defines are areas already. | |||
Although GpiPolygons is limited to straight line figures, it retains a great deal of flexibility. The polygon data structure (POLYGON) contains the number of vertices, and the vertices themselves are in world coordinates. The collection of POLYGON structures accepted in a single GpiPolygons is not limited to one type of polygon. | |||
The drawing of the first polygon begins at the current position. For all subsequent polygons, all vertices must be explicitly defined. If the individual polygons are not completely defined, they are closed with a straight line drawn from the last defined vertex to the first. | |||
After the application has defined the polygons, they may be transformed and manipulated just as other primitives are. | |||
===Polygon Boundaries=== | |||
Applications have two options when specifying the polygon boundary: | |||
*POLYGON_BOUNDARY (the default) | |||
*POLYGON_NOBOUNDARY. | |||
The POLYGON_BOUNDARY value tells the PM programming interface to draw all outlines of the polygon primitives using a line that conforms to the current LINEBUNDLE attributes. If the line attributes have not been changed, the default outline color is black on most display devices and printers, and the default line style is solid. As the attributes cannot be changed within the context of GpiPolygons, all polygons are drawn with the same line. The interior of the polygons are filled with the pattern that conforms to the current AREABUNDLE attributes. | |||
To prevent PM from outlining an area, an application can use the POLYGON_NOBOUNDARY flag when calling GpiPolygons. Only the interior fill pattern is visible. This value is used most often when there are many overlapping polygons, and the interior lines are not desired. | |||
You might think of this option in terms similar to the outline and fill options discussed with boxes and full arcs. The POLYGON_BOUNDARY value corresponds to the DRO_OUTLINEFILL value, and POLYGON_NOBOUNDARY, to the DRO_FILL. There is no distinct boundary value that corresponds to DRO_OUTLINE, the simple outline. | |||
To simulate this effect, OR the POLYGON_NOBOUNDARY value with the appropriate polygon construction value, described below, when calling GpiPolygons. | |||
===Polygon Construction=== | |||
An application specifies the area construction when it calls GpiBeginArea. There are two options: | |||
*POLYGON_ALTERNATE (the default) | |||
*POLYGON_WINDING. | |||
As with area construction, in alternate mode: | |||
*A point is included in the filled polygon if you have to cross an odd number of lines in the set of polygons when drawing a line from that point to infinity. | |||
*A point is not included in the filled polygon if you have to cross an even number of lines in the set of polygons when drawing a line from that point to infinity. | |||
Also as with area construction, in winding mode, the direction in which the boundary lines of the polygons are drawn determines whether a given point is included in the filled polygon. Since the individual polygons drawn with GpiPolygons are generated by independent structures, the direction in which a polygon is drawn depends only on the vertices of that polygon. | |||
To determine if a given point is included in the filled polygon, count the number of lines to be crossed to move from that point to infinity. For each boundary line drawn in one direction add one to the tally. For each line drawn in the opposite direction, subtract one from the tally. A point is within the polygon if the result is nonzero. | |||
===Polygon Overlap=== | |||
An application specifies which pels are drawn when it calls GpiPolygons. There are two options: | |||
* POLYGON_INCL (the default) | |||
* POLYGON_EXCL. | |||
When the overlap value is POLYGON_INCL, the bottom right is included in the polygon. The value POLYGON_EXCL, the exclusive value, indicates that the bottom right is excluded from the polygon. This value acts in conjunction with the mix attribute in determining the appearance of a polygon, which is especially important for a group of overlapping or adjacent polygons. | |||
For example, [[GpiPolygons]] specifies a number of polygons. Two of the polygons share the vertex pair (6,7) and (9,7). When the polygons are drawn, if the overlap value was POLYGON_INCL, there are two distinct lines to be drawn from (6,7) to (9,7). A mix attribute other than FM_OVERPAINT could cause undesirable results as the line and drawing-surface colors mix. | |||
As with the polygon boundary and construction values, the overlap value can be ORed when calling GpiPolygons to create a specific effect. | |||
==Using Area and Polygon Primitives== | ==Using Area and Polygon Primitives== | ||
You can use area functions to: | |||
*Draw one or more closed figures | |||
*Create a custom fill pattern from a bit map | |||
*Create a custom fill pattern from a font character | |||
===Drawing a Single, Closed Figure=== | |||
The following figure shows an example of how to use area functions to draw a single closed figure that is filled with a vertical pattern using the alternate mode. The closed figure in this example is a 5-pointed star. | |||
<pre> | |||
#define INCL_GPI | |||
#include <os2.h> | |||
void fncAREA02(void){ | |||
POINTL aptl[5]; /* Structure for current position */ | |||
HPS hps; | |||
/* Initialize the array of points for the 5-pointed star. */ | |||
aptl[0].x = 400; aptl[0].y = 195; | |||
aptl[1].x = 40; aptl[1].y = 320; | |||
aptl[2].x = 260; aptl[2].y = 10; | |||
aptl[3].x = 260; aptl[3].y = 390; | |||
aptl[4].x = 37; aptl[4].y = 82; | |||
GpiSetPattern(hps, PATSYM_VERT);/* Set pattern outside bracket */ | |||
/* Draw the star. */ | |||
GpiBeginArea(hps, BA_ALTERNATE); | |||
GpiMove(hps, &aptl[4]); /* First and last point of star */ | |||
GpiPolyLine(hps, 5L, aptl); | |||
GpiEndArea(hps); | |||
} /* fncAREA02 */ | |||
</pre> | |||
===Drawing Multiple, Intersecting, Closed Figures=== | |||
The following figure is an example of how to use area functions to draw two intersecting boxes, filled, using the winding mode. | |||
<pre> | |||
#define INCL_GPI | |||
#include <os2.h> | |||
void fncAREA03(void){ | |||
POINTL ptl; /* Structure for current position */ | |||
HPS hps; | |||
GpiBeginArea(hps, BA_WINDING); | |||
ptl.x = 100; | |||
ptl.y = 50; | |||
GpiMove(hps, &ptl); | |||
ptl.x = 300; | |||
ptl.y = 250; | |||
GpiBox(hps, DRO_OUTLINE, &ptl, 0, 0); | |||
ptl.x = 180; | |||
ptl.y = 120; | |||
GpiMove(hps, &ptl); | |||
ptl.x = 380; | |||
ptl.y = 320; | |||
GpiBox(hps, DRO_OUTLINE, &ptl, 0, 0); | |||
GpiEndArea(hps); | |||
} /* fncAREA03 */ | |||
</pre> | |||
===Creating a Custom Fill Pattern from a Bit Map=== | |||
The following figure is an example of how to create a custom fill pattern by using a hard-coded bit map. In this example, the bit map creates a pattern of arrows. | |||
<pre> | |||
#define INCL_DOS | |||
#define INCL_GPI | |||
#define INCL_WIN | |||
#include <os2.h> | |||
LONG lcidCustom; /* Bit map tag */ | |||
HPS hps; | |||
VOID CreatePattern(VOID); | |||
VOID MyFunction(VOID){ | |||
CreatePattern(); | |||
GpiSetPatternSet(hps, lcidCustom); | |||
. | |||
. | |||
. | |||
} /* func */ | |||
VOID CreatePattern(VOID){ | |||
HBITMAP hbm; /* Bit map handle */ | |||
BITMAPINFOHEADER2 bmp2; /* Structure for bit map information */ | |||
PBITMAPINFO2 pbmi2; /* Pointer to structure for bit map data */ | |||
PRGB2 prgb2; /* Structure for color data */ | |||
ULONG cbBitmapInfo, cColors; | |||
BYTE abPattern[] = { 0xFF, 0xFF, 0xE7, 0xFF, | |||
0xE7, 0xFF, 0xC3, 0xFF, | |||
0xC3, 0xFF, 0x81, 0xFF, | |||
0x81, 0xFF, 0xE7, 0xFF, | |||
0xE7, 0xFF, 0xE7, 0xFF, | |||
0xE7, 0xFF, 0xE7, 0xFF, | |||
0xE7, 0xFF, 0xE7, 0xFF, | |||
0xE7, 0xFF, 0xFF, 0xFF | |||
}; | |||
lcidCustom = 1; /* Bit map tag */ | |||
bmp2.cbFix = (ULONG) sizeof(BITMAPINFOHEADER2); | |||
bmp2.cx = 8; /* Bit map is 8 pels wide */ | |||
bmp2.cy = 8; /* Bit map is 8 pels high */ | |||
bmp2.cPlanes = 1; /* One bit plane */ | |||
bmp2.cBitCount = 1; /* One bit per pel */ | |||
/* Use default values for the remainder of the structure. */ | |||
bmp2.ulCompression = 0; | |||
bmp2.cbImage = 0; | |||
bmp2.cxResolution = 0; | |||
bmp2.cyResolution = 0; | |||
bmp2.cclrUsed = 0; | |||
bmp2.cclrImportant = 0; | |||
bmp2.usUnits = 0; | |||
bmp2.usReserved = 0; | |||
bmp2.usRecording = 0; | |||
bmp2.usRendering = 0; | |||
bmp2.cSize1 = 0; | |||
bmp2.cSize2 = 0; | |||
bmp2.ulColorEncoding = 0; | |||
bmp2.ulIdentifier = 0; | |||
cColors = 1 << (bmp2.cBitCount * bmp2.cPlanes); | |||
cbBitmapInfo = sizeof(BITMAPINFO2) + (sizeof(RGB2) * cColors); | |||
DosAllocMem((PVOID)&pbmi2, cbBitmapInfo, | |||
PAG_COMMIT | PAG_READ | PAG_WRITE); | |||
pbmi2->cbFix = bmp2.cbFix; | |||
pbmi2->cx = bmp2.cx; | |||
pbmi2->cy = bmp2.cy; | |||
pbmi2->cPlanes = bmp2.cPlanes; | |||
pbmi2->cBitCount = bmp2.cBitCount; | |||
/* Use default values for the remainder of the structure. */ | |||
pbmi2->ulCompression = 0; | |||
pbmi2->cbImage = 0; | |||
pbmi2->cxResolution = 0; | |||
pbmi2->cyResolution = 0; | |||
pbmi2->cclrUsed = 0; | |||
pbmi2->cclrImportant = 0; | |||
pbmi2->usUnits = 0; | |||
pbmi2->usReserved = 0; | |||
pbmi2->usRecording = 0; | |||
pbmi2->usRendering = 0; | |||
pbmi2->cSize1 = 0; | |||
pbmi2->cSize2 = 0; | |||
pbmi2->ulColorEncoding = 0; | |||
pbmi2->ulIdentifier = 0; | |||
prgb2 = (PRGB2) (pbmi2 + 1); /* Set address to follow bmp2 */ | |||
/* Set bit map colors to black and white. */ | |||
prgb2[0].bBlue = 0; /* Color[0] = black */ | |||
prgb2[0].bGreen = 0; /* Color[0] = black */ | |||
prgb2[0].bRed = 0; /* Color[0] = black */ | |||
prgb2[0].fcOptions = 0; | |||
prgb2[1].bBlue = 255; /* Color[1] = white */ | |||
prgb2[1].bGreen = 255; /* Color[1] = white */ | |||
prgb2[1].bRed = 255; /* Color[1] = white */ | |||
prgb2[1].fcOptions = 0; | |||
/* Create a bit map and retrieve its handle. */ | |||
hbm = GpiCreateBitmap(hps, | |||
&bmp2, | |||
CBM_INIT, | |||
(PBYTE) abPattern, /* Array of bits */ | |||
pbmi2); | |||
/* Tag the bit map just created with a custom identifier (lcid). */ | |||
GpiSetBitmapId(hps, hbm, lcidCustom); | |||
} /* CreatePattern */ | |||
</pre> | |||
Creating a Custom Fill Pattern from a Bit Map | |||
===Creating a Custom Fill Pattern from a Font Character === | |||
The following figure is an example of how to create a custom fill pattern by using a character from a font. The fill pattern can be only an 8-by-8 bit map; as a result, not all of the character is used. | |||
<pre> | |||
#define INCL_GPI | |||
#define INCL_WIN | |||
#include <os2.h> | |||
HPS hps; /* Presentation-space handle */ | |||
LONG lcidCustom; /* Font identifier */ | |||
FONTMETRICS afm[80]; | |||
FATTRS fat; | |||
VOID LoadFont(VOID); | |||
void fncAREA05(void){ | |||
LoadFont(); | |||
GpiSetPatternSet(hps, lcidCustom); | |||
GpiSetPattern(hps, 'o'); /* Use lowercase 'o' as fill */ | |||
. | |||
. | |||
. | |||
} /* fncAREA05 */ | |||
VOID LoadFont(VOID){ | |||
LONG cFonts = 0; | |||
LONG cPublicFonts, i; | |||
lcidCustom = 1; | |||
/* Determine the number of loaded public fonts. */ | |||
cPublicFonts = GpiQueryFonts(hps, QF_PUBLIC, NULL, (PLONG) &cFonts, | |||
(LONG) (sizeof(FONTMETRICS)), NULL); | |||
/* Load the metrics for all public fonts into afm. */ | |||
GpiQueryFonts(hps, QF_PUBLIC, NULL, (PLONG) &cPublicFonts, | |||
(LONG) (sizeof(FONTMETRICS)), afm); | |||
/* Get the first image font with a point size larger than 8. */ | |||
for (i = 0; ((afm[i].fsDefn & FM_DEFN_OUTLINE) || | |||
afm[i].lEmHeight <= 8) && i < cPublicFonts; i++); | |||
/* Load the FATTRS structure with the required metrics. */ | |||
fat.usRecordLength = sizeof(fat); | |||
fat.fsSelection = 0; | |||
fat.lMatch = afm[i].lMatch; | |||
StringCopy(fat.szFacename, afm[i].szFacename); | |||
fat.idRegistry = 0; | |||
fat.usCodePage = 0; | |||
fat.lMaxBaselineExt = 0; | |||
fat.lAveCharWidth = 0; | |||
fat.fsType = 0; | |||
fat.fsFontUse = 0; | |||
/* Select this font and assign it a custom lcid. */ | |||
GpiCreateLogFont(hps, NULL, lcidCustom, &fat); | |||
GpiSetCharSet(hps, lcidCustom); | |||
} /* LoadFont */ | |||
</pre> | |||
Creating a Custom Fill Pattern from a Font Character | |||
[[Category:GPIGuide]] |
Latest revision as of 18:00, 14 May 2025
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
An area is one or more closed figures that can be drawn filled, outlined, or filled and outlined. If an area includes more than one figure, those figures can be separate or intersecting.
A polygon , too, is one or more closed figures that can be drawn filled, outlined, or filled and outlined. Polygons, unlike areas, are limited to figures with straight edges. Polygons also can be separate or intersecting.
The following topics are related to information in this chapter:
- Presentation spaces
- Line and arc primitives
- Color and mix attributes
- Fonts
- Bit maps
- Paths
About Area Primitives
Applications can create, outline, and fill areas and can create custom-fill patterns from bit maps or font symbols. Some graphics functions are not valid within an area definition. For example, you cannot include marker, image, or character-string primitives in an area definition.
The following figure is an example of an area.
This area comprises two hexagons, one completely enclosed by the other. The area is filled with the current area-fill pattern.
Attributes of Area Primitives
The attributes of the area primitive are contained in a data structure called AREABUNDLE. These attributes are:
- Pattern symbol
- Pattern reference point
- Pattern set
- Foreground color
- Background color
- Foreground mix attribute
- Background mix mode
When an application creates a presentation space, the area attributes are set to the default values shown in the following table.
- Area Attribute Default Values
Attribute | Default Value | Function that Redefines Attribute |
---|---|---|
Pattern symbol | solid | GpiSetPattern |
Pattern reference point | (0,0) | GpiSetPatternRefPoint |
Pattern set | LCID_DEFAULT | GpiSetPatternSet |
Foreground color | Black | GpiSetAttrs (ABB_COLOR) |
Background color | Clear | GpiSetAttrs (ABB_BACK_COLOR) |
Foreground mix | Overpaint | GpiSetAttrs (ABB_MIX_MODE) |
Background mix | Leave alone | GpiSetAttrs (ABB_BACK_MIX_MODE) |
Note: If the default (LCID_DEFAULT) for pattern set is changed, the base pattern set cannot be reselected with GpiSetPatternSet.
Pattern Symbol Attribute
The current pattern symbol, also called the symbol point code, is selected from the current pattern set with GpiSetPattern. The pattern symbol selected for the specified presentation space is used as the subsequent fill pattern until a new symbol is selected. Applications must not call GpiSetPattern while in an area or a path. If the current pattern set specifies a bit map, this attribute is ignored.
The following table describes the pattern symbols provided by the PM programming interface in a base pattern set. These symbols are not necessarily available from other pattern sets.
- The Base Pattern Set
Symbol | Identifier | Long Value |
---|---|---|
Solid shading decreasing in dots per inch through PATSYM_DENSE8 | PATSYM_DENSE1 through PATSYM_DENSE8 | 1L - 8L |
Vertical lines | PATSYM_VERT | 9L |
Horizontal lines | PATSYM_HORIZ | 10L |
Lines bottom left to top right | PATSYM_DIAG1 | 11L |
Lines bottom left to middle right | PATSYM_DIAG2 | 12L |
Lines top left to bottom right | PATSYM_DIAG3 | 13L |
Lines top left to middle right | PATSYM_DIAG4 | 14L |
No shading | PATSYM_NOSHADE | 15L |
Solid shading | PATSYM_SOLID | 16L |
Alternate pels | PATSYM_HALFTONE | 17L |
Cartesian grid | PATSYM_HATCH | 18L |
Diagonal crosshatch | PATSYM_DIAGHATCH | 19L |
Blank (often called the clear pattern) | PATSYM_BLANK | 64L |
The default pattern symbol (PATSYM_DEFAULT) is identical to the PATSYM_SOLID symbol, and has a long value of 0L. The error pattern symbol (PATSYM_ERROR) has a long value of -1L.
The following figure shows the patterns from the base pattern symbol set. Applications can determine the current pattern set by calling GpiQueryPattern.
Pattern Reference Point Attribute
The pattern reference point is the point from which the area's fill-pattern spreads horizontally and vertically. The lower-left corner of the pattern is aligned on this point. The pattern reference point has a default value of (0,0), and is expressed in world coordinates. Applications can determine the pattern reference point with GpiQueryPatternRefPoint. Applications can specify the pattern reference point with GpiSetPatternRefPoint; however, this should not be done inside an area. The pattern reference point does not have to be within the boundary of the area. The following figure shows an area that was filled using the default pattern reference point.
The pattern of diagonal lines is aligned with the pattern reference point (0,0). When the picture is displayed or printed, only the hexagon will be filled.
Use of the default reference point causes the diagonal lines of the pattern to intersect the area boundary at specific points. If you change the reference point to (0,4), for example, the pattern shifts upward, and the points of intersection with the area boundary are different. Although the reference point is outside the area, when an application displays or prints the picture, only the area is filled.
Pattern Set Attribute
When you create a presentation space, the current pattern set and other area attributes are set to the default. The current pattern-a black solid, as described earlier- is specified from the supplied pattern set. (The supplied set of pattern symbols contains image or raster patterns only.) An area primitive is filled by repeating this pattern vertically and horizontally within the area boundary.
Default Pattern Set
The standard pattern set contains patterns of solid shading with decreasing intensity, and patterns of vertical, horizontal, and diagonal lines. If the default pattern set is changed with GpiSetDefAttrs, its patterns are not accessible. The patterns from the default set can be recovered by specifying GpiSetDefAttrs with the value LCID_DEFAULT, (0).
Customizing Pattern Sets
An application can create custom patterns by using bit maps or characters and symbols from an image font. When designing custom patterns, consider that the operating system uses only the first eight bits in the first eight rows, starting with the lower-left corner of the bit map. The cell size of an image font used as a fill pattern might be too large to include the complete character or symbol.
An application can change the appearance of a fill pattern by changing its alignment in an area primitive with GpiSetPatternRefPoint. When the default reference point is set, the operating system aligns the lower-left corner of the fill pattern with the point (0,0) in the application's world space and begins filling the area. If an application adjusts the pattern reference point to (3,2), The operating system aligns the lower-left corner of the fill pattern with the point (3,2) in the application's world space and begins filling the area. By moving the reference point from (0,0) to (3,2), the fill pattern appears shifted up two pels and to the right three pels.
Custom Fill Patterns from a Bit Map
To create a custom pattern from a hard-coded bit map, an application must use the following steps: 1. Create or load a bit map to obtain a bit-map handle; for example, use GpiLoadBitmap. 2. Call GpiSetBitmapId (ID) to tag the bit map with a local identifier (lcid) from 1 to 254. 3. Call GpiSetPatternSet (ID) or GpiSetAttrs (ABB_SET) to set the current fill pattern.
The application can now draw the area.
Custom Fill Patterns from a Font Symbol
To create a custom pattern from a character or a symbol in a font: 1. Create a logical image font and assign it an ID; for example use GpiCreateLogFont. 2. Call GpiSetPatternSet (ID) or GpiSetAttrs (ABB_SET), passing it the local identifier for the font. 3. Call GpiSetPattern, passing the value of the code point for a character or symbol in the font.
The application can now draw the area.
Area Colors and Mix Attributes
The color attribute defines the color used to draw a primitive or an object. The mix attribute determines how the color of a primitive or an object is combined with the color of the drawing surface, or any other objects on the surface. Both attributes also are described in Color and Mix Attributes.
The area color defines the color used to fill the output from any of the IBM OS/2 area functions, when necessary. The area primitive is the only primitive in which the color can be changed during the drawing of the area. Therefore, this attribute, more than the other area attributes, depends on the current value as described in Attribute Currentness.
When a presentation space is created, the area color initial default is black. The pattern symbol initial default, explained previously, is solid. Areas are one of the primitives that have a foreground and background color.
Area primitives have both a color and background color attribute. The background color does not appear if the pattern symbol is solid, and the background color is undefined if the pattern symbol is a customized, multi-colored bit map.
When a presentation space is created, the area mix attribute initial default is FM_OVERPAINT. The overpaint mix attribute specifies that the area color is not to be modified by the color of the drawing surface. If the area mix attribute is changed, the area color is mixed with colors that are already on the drawing surface.
When the pattern symbol is solid, the color that fills the area, if necessary, is the current area foreground color. If the pattern symbol is changed to be a pattern of vertical lines, for example, the color of those lines is the current area foreground color. Inside of the area bracket, there can be other colors if these colors are the current color for primitives such as lines or arcs, that are drawn within the area bracket. These colors are not specifically defined or influenced by the area foreground color.
The area background color initial default is CLR_BACKGROUND. Usually this is defined by the application to the same color as the drawing surface. If the pattern symbol is solid, the area background color does not appear. If the pattern symbol is changed to be a pattern of vertical lines, for example, the color in between those lines is the current area background color.
The area background mix attribute initial default is BM_LEAVEALONE. The leave-alone background mix attribute specifies that the area background color is not drawn. This means that for a nonsolid pattern symbol, the drawing-surface color or the color of an object, not created by the area bracket, but on the drawing surface, shows through the nonsolid pattern. The area background color, for nonsolid pattern symbols, appears only if the background mix attribute is changed to overpaint, BM_OVERPAINT.
If you have customized the pattern symbol with a bit map, the color definitions of the area primitive change. The foreground color corresponds to the color of the pels that are specified ON in the fill-pattern bit map. The background color corresponds to the color of the pels that are specified OFF in the fill-pattern bit map. The foreground and background mix attribute do not change.
Note: Background color and mix attribute only apply to monochrome (2-color) fill patterns. The bit set to 0 is defined as the background and the bit set to 1 is defined as the foreground. A multi-colored bit map is unaffected by the background color and mix attributes.
To specify a new color or mix attribute call GpiSetAttrs. This function accepts as input the type of primitive, for example PRIM_AREA, a list of attributes that are to be changed, a list of attributes that are to be set to their default values, and the values for the attributes that are to be changed. GpiSetAttrs is useful to specify colors and mix attributes just for a specific data structure -for example the AREABUNDLE structure. GpiSetAttrs also provides some protection against invalid colors.
To determine the current area color and mix attribute, call GpiQueryAttrs. This function accepts as input the primitive type and the attributes in question. It returns as output an array of values for the specifically queried attributes.
To reset the default area color and mix attribute, just as with any other attribute specified in the AREABUNDLE. data structure, call GpiSetDefAttrs. This function accepts as input the type of primitive, for example PRIM_AREA, the attributes to be changed, and the values that will become the new default values. The changing of default values is important when working with segments. Changing the default values during a series of drawing functions is not recommended.
The area color and mix attribute also can be specified with:
However, these functions have the disadvantage of specifying the foreground and background color or mix attribute for all primitive BUNDLE data structures that have the respective component.
There are four queries that determine the color and mix attribute as specified by GpiSet... functions:
If the area color, area background color, mix attribute, or background mix attribute were specified individually, the aforementioned queries can return a value inconsistent with the current area attribute.
Area Brackets
Areas also are referred to as area brackets, because the functions that create and define the area always are "bracketed" by the two functions, GpiBeginArea and GpiEndArea. Only one area is defined between these two functions. However, within the area, there can be any number of adjacent, intersecting, or completely separate area primitives.
GpiBeginArea signals the start of a group of primitives that define the boundary of the area. The current position is not changed by GpiBeginArea, although it is updated by any drawing instructions that follow.
If you call GpiSetCurrentPosition or GpiMove within an area definition, the current figure is closed automatically, and a new figure is started at the current position by the next line or curve. A figure in the area, whose start and end points are not the same, is closed by drawing a straight line from the current position to the start position of the figure.
GpiEndArea signals the end of an area definition and tells the operating system to draw the area. If an application does not close a figure before calling GpiEndArea, the figure is closed automatically by drawing a straight line from the end point of the last line or curve to the start point of the current figure. The current position is always updated to the end point of the last line drawn.
The functional sequence to draw an area could be:
#include <os2.h> void fncAREA01(void){ #if 0 GpiBeginArea /* Starts the area bracket */ GpiSetCurrentPosition /* Set the start point of the outer hexagon. */ GpiPolyLine /* Draw the outer hexagon. */ GpiSetCurrentPosition /* Set the start point of the inner hexagon. */ GpiPolyLine /* Draw the inner hexagon. */ GpiEndArea /* End the area definition. */ #endif }
An area bracket contains the functions that define an area. Only one area can be defined between "bracket" functions. Following the beginning of an area bracket, an application can define the shape and location of the area in world space by using the following line and arc functions:
- GpiBox
- GpiFullArc
- GpiLine
- GpiPartialArc
- GpiPointArc
- GpiPolyFillet
- GpiPolyFilletSharp
- GpiPolyLine
- GpiPolySpline
If an application calls either GpiBox or GpiFullArc inside an area, it must use the DRO_OUTLINE option. In addition to the drawing functions, an application also can use the following specification functions inside an area bracket:
- GpiBeginElement
- GpiCallSegmentMatrix
- GpiComment
- GpiElement
- GpiEndArea
- GpiEndElement
- GpiGetData
- GpiLabel
- GpiMove
- GpiOffsetElementPointer
- GpiPop
- GpiPutData
- GpiSetArcParams
- GpiSetAttrMode
- GpiSetAttrs
- GpiSetColor
- GpiSetCurrentPosition
- GpiSetEditMode
- GpiSetElementPointer
- GpiSetElementPointerAtLabel
- GpiSetLineEnd
- GpiSetLineJoin
- GpiSetLineType
- GpiSetLineWidth
- GpiSetMix
- GpiSetModelTransformMatrix
- GpiSetSegmentTransformMatrix
An application also can use the following query functions inside an area bracket:
- GpiQueryArcParams
- GpiQueryAttrMode
- GpiQueryAttrs
- GpiQueryBackColor
- GpiQueryBackMix
- GpiQueryBoundaryData
- GpiQueryCharAngle
- GpiQueryCharBox
- GpiQueryCharDirection
- GpiQueryCharMode
- GpiQueryCharSet
- GpiQueryCharShear
- GpiQueryCharStringPos
- GpiQueryCharStringPosAt
- GpiQueryClipBox
- GpiQueryClipRegion
- GpiQueryColor
- GpiQueryColorData
- GpiQueryColorIndex
- GpiQueryCp
- GpiQueryCurrentPosition
- GpiQueryDefaultViewMatrix
- GpiQueryDefCharBox
- GpiQueryDevice
- GpiQueryDeviceBitmapFormats
- GpiQueryEditMode
- GpiQueryFontFileDescriptions
- GpiQueryFontMetrics
- GpiQueryFonts
- GpiQueryGraphicsField
- GpiQueryInitialSegmentAttrs
- GpiQueryKerningPairs
- GpiQueryLineEnd
- GpiQueryLineJoin
- GpiQueryLineType
- GpiQueryLineWidth
- GpiQueryLineWidthGeom
- GpiQueryLogColorTable
- GpiQueryMarker
- GpiQueryMarkerBox
- GpiQueryMarkerSet
- GpiQueryMix
- GpiQueryModelTransformMatrix
- GpiQueryNearestColor
- GpiQueryNumberSetIds
- GpiQueryPageViewport
- GpiQueryPattern
- GpiQueryPatternRefPoint
- GpiQueryPatternSet
- GpiQueryPel
- GpiQueryPickAperturePosition
- GpiQueryPickApertureSize
- GpiQueryRealColors
- GpiQueryRegionBox
- GpiQueryRegionRects
- GpiQueryRGBColor
- GpiQuerySegmentAttrs
- GpiQuerySegmentNames
- GpiQuerySegmentPriority
- GpiQuerySegmentTransformMatrix
- GpiQuerySetIds
- GpiQueryStopDraw
- GpiQueryTag
- GpiQueryViewingLimits
- GpiQueryViewingTransformMatrix
- GpiQueryWidthTable
Area Bracket Attributes
In addition to the attributes controlled by the AREABUNDLE data structure, there are two attributes that can be specified for each individual area bracket:
- Area boundary
- Area construction
These bracket attributes affect how the area primitives inside the bracket are drawn. The concept of attribute currentness is especially important to areas and paths that contain multiple figures.
Area Boundaries
An application specifies the area boundary when it calls GpiBeginArea. There are two options:
- BA_BOUNDARY (the default)
- BA_NOBOUNDARY.
The BA_BOUNDARY value tells the programming interface to draw all outlines of the area primitives within the area bracket, using a line that conforms to the current LINEBUNDLE attributes. If the line attributes have not been changed, the default outline color is black on most displays and printers, and the default line style is solid. An application can change the line color and line styles within the area bracket. The interior of the area primitive is filled with the current pattern.
To prevent the interface from outlining an area, an application can use the BA_NOBOUNDARY flag when calling GpiBeginArea. Only the interior fill pattern is visible. This value most often is used when an area contains many overlapping figures, and the interior lines are not desired.
You could think of this option in terms similar to the outline and fill options discussed with boxes and full arcs. The BA_BOUNDARY value corresponds to DRO_OUTLINEFILL, and BA_NOBOUNDARY, to DRO_FILL. There is no distinct boundary value that corresponds to DRO_OUTLINE, the simple outline. To simulate this effect, OR the BA_NOBOUNDARY value with the appropriate area construction value when calling GpiBeginArea.
Area Construction
An application specifies the area construction when it calls GpiBeginArea. There are two options:
- BA_ALTERNATE (the default)
- BA_WINDING.
Construction modes also are called area-fill modes. They provide different ways of determining whether a given point is included in the filled area. Normally, the construction mode you use is a matter of personal preference.
Alternate Mode
In alternate mode, the following occurs:
- A point is included in the filled area if you have to cross an odd number of lines in the area when drawing a line from that point to infinity.
- A point is not included in the filled area if you have to cross an even number of lines in the area when drawing a line from that point to infinity.
In the example in the following figure, the inner hexagon is not shaded, because to draw a line from any point in the hexagon to infinity, you must cross two boundary lines. The remainder of the area is shaded, because to move outside the area, you need to cross only one boundary line.
Winding Mode
In winding mode, the direction in which the boundary lines in the area are drawn determines whether a given point is included in the filled area. The direction of a line depends on both the graphics functions used to draw it and the world coordinates that define it. For example, if the current position of a presentation space is (c,c), and GpiBox is called with the diagonally-opposite corner of the box specified as (d,d), GpiBox always draws the box in the following order:
1. (xc.,yc.) to 2. (xd.,yc.) to 3. (xd.,yd.) to 4. (xc.,yd.) and returning to 5. (xc.,yc.).
As illustrated in the following figure, in some cases the box is drawn in a counterclockwise direction. When either xd. is less than xc., or yd. is less than yc., but not both, a box is drawn clockwise.
The current position is (3,2) and the specified corner is at (8,6). The box is drawn from (3,2) to (8,2) to (8,6) to (3,8) to (3,2).
For the polyline primitive, the direction in which a line is drawn depends on the relative values of the end points of each line, so you can choose whether to draw in a clockwise or counterclockwise direction.
To determine if a given point is included in the filled area, count the number of lines to be crossed to move from that point to infinity. For each boundary line drawn in one direction, add one to the tally. For each line drawn in the opposite direction, subtract one from the tally. A point is within the area if the result is nonzero.
If two figures -for example, the hexagons in the following figure- are drawn in different directions, the tally for the inner hexagon is 0 and the area will look exactly as it does in alternate mode.
If the two hexagons are drawn in the same direction, the result is 2, and the inner hexagon is shaded as shown in the following figure.
The boundary lines of the area in the previous figure have been drawn and are visible through the area-fill pattern. The boundary lines of an area primitive do not have to be drawn; but if they are, they are drawn according to the current line attributes.
To vary the appearance of different parts of the boundary line, you can change the current line attributes during area definition.
The boundary lines of an area are considered a part of the area's interior. Therefore, when you draw an area without boundary lines (BA_NOBOUNDARY), the area-fill pattern extends to include the boundaries of the area, and the area is the same size it would be if the boundary lines had been drawn.
Attribute Currentness
Graphics functions that change attributes are valid within the area bracket. There are misconceptions, however, about which attributes are used when the figures are displayed in a window or drawn to the printer.
Review the following functional sequence:
Function | Effect |
---|---|
GpiSetColor | Sets color to red. |
GpiBeginArea | Opens area bracket |
GpiLine | Draws a straight line |
GpiSetColor | Sets color to green. |
GpiPolyLine | Draws two additional lines to form a triangle. |
GpiEndArea | Ends the area bracket and displays a picture. |
If you are displaying on a color monitor, the image appears as follows:
The triangle has one red line, drawn with GpiLine and two green lines, drawn with GpiPolyLine. The interior of the triangle, if drawn, is red. Red is the color that was current when the area was defined and, therefore, is the current color for the area interior. In terms of the interior area, green is only the color that was current when the function that initiates drawing was called.
If the application immediately opened a new area bracket, the interior of that bracket, if drawn, would be green. The color attribute for the second AREABUNDLE, is not "inherited" from the last AREABUNDLE drawn.
About Polygon Primitives
Area brackets have the flexibility to draw any combination of curved or straight lines and combine the results into a closed figure. An advantage that polygons sometimes have over area brackets, however, is that they require fewer time-consuming calculations to provide that kind of flexibility.
The operating system provides a function that enables you to draw multiple straight-line closed areas outside of an area bracket. Like bracket-generated areas, they can be adjacent, intersecting, or completely separate.
The function is GpiPolygons and the set of objects it draws are called polygon primitives. A polygon primitive is any set of polygons with specified vertices that can be filled or filled and outlined. This function accepts as input the desired number of polygons, the POLYGON data structure for each polygon, and a boundary and construction option similar to those of the GpiBeginArea function.
The purpose of GpiPolygons is to enable you to specify an area in such a way as to pass all of the area boundaries at once. This improves performance significantly because the operating system cannot process the accumulated primitives inside an area bracket until it reaches a GpiEndArea. GpiPolygons is not valid inside an area bracket because the figures it defines are areas already.
Although GpiPolygons is limited to straight line figures, it retains a great deal of flexibility. The polygon data structure (POLYGON) contains the number of vertices, and the vertices themselves are in world coordinates. The collection of POLYGON structures accepted in a single GpiPolygons is not limited to one type of polygon.
The drawing of the first polygon begins at the current position. For all subsequent polygons, all vertices must be explicitly defined. If the individual polygons are not completely defined, they are closed with a straight line drawn from the last defined vertex to the first.
After the application has defined the polygons, they may be transformed and manipulated just as other primitives are.
Polygon Boundaries
Applications have two options when specifying the polygon boundary:
- POLYGON_BOUNDARY (the default)
- POLYGON_NOBOUNDARY.
The POLYGON_BOUNDARY value tells the PM programming interface to draw all outlines of the polygon primitives using a line that conforms to the current LINEBUNDLE attributes. If the line attributes have not been changed, the default outline color is black on most display devices and printers, and the default line style is solid. As the attributes cannot be changed within the context of GpiPolygons, all polygons are drawn with the same line. The interior of the polygons are filled with the pattern that conforms to the current AREABUNDLE attributes.
To prevent PM from outlining an area, an application can use the POLYGON_NOBOUNDARY flag when calling GpiPolygons. Only the interior fill pattern is visible. This value is used most often when there are many overlapping polygons, and the interior lines are not desired.
You might think of this option in terms similar to the outline and fill options discussed with boxes and full arcs. The POLYGON_BOUNDARY value corresponds to the DRO_OUTLINEFILL value, and POLYGON_NOBOUNDARY, to the DRO_FILL. There is no distinct boundary value that corresponds to DRO_OUTLINE, the simple outline.
To simulate this effect, OR the POLYGON_NOBOUNDARY value with the appropriate polygon construction value, described below, when calling GpiPolygons.
Polygon Construction
An application specifies the area construction when it calls GpiBeginArea. There are two options:
- POLYGON_ALTERNATE (the default)
- POLYGON_WINDING.
As with area construction, in alternate mode:
- A point is included in the filled polygon if you have to cross an odd number of lines in the set of polygons when drawing a line from that point to infinity.
- A point is not included in the filled polygon if you have to cross an even number of lines in the set of polygons when drawing a line from that point to infinity.
Also as with area construction, in winding mode, the direction in which the boundary lines of the polygons are drawn determines whether a given point is included in the filled polygon. Since the individual polygons drawn with GpiPolygons are generated by independent structures, the direction in which a polygon is drawn depends only on the vertices of that polygon.
To determine if a given point is included in the filled polygon, count the number of lines to be crossed to move from that point to infinity. For each boundary line drawn in one direction add one to the tally. For each line drawn in the opposite direction, subtract one from the tally. A point is within the polygon if the result is nonzero.
Polygon Overlap
An application specifies which pels are drawn when it calls GpiPolygons. There are two options:
- POLYGON_INCL (the default)
- POLYGON_EXCL.
When the overlap value is POLYGON_INCL, the bottom right is included in the polygon. The value POLYGON_EXCL, the exclusive value, indicates that the bottom right is excluded from the polygon. This value acts in conjunction with the mix attribute in determining the appearance of a polygon, which is especially important for a group of overlapping or adjacent polygons.
For example, GpiPolygons specifies a number of polygons. Two of the polygons share the vertex pair (6,7) and (9,7). When the polygons are drawn, if the overlap value was POLYGON_INCL, there are two distinct lines to be drawn from (6,7) to (9,7). A mix attribute other than FM_OVERPAINT could cause undesirable results as the line and drawing-surface colors mix.
As with the polygon boundary and construction values, the overlap value can be ORed when calling GpiPolygons to create a specific effect.
Using Area and Polygon Primitives
You can use area functions to:
- Draw one or more closed figures
- Create a custom fill pattern from a bit map
- Create a custom fill pattern from a font character
Drawing a Single, Closed Figure
The following figure shows an example of how to use area functions to draw a single closed figure that is filled with a vertical pattern using the alternate mode. The closed figure in this example is a 5-pointed star.
#define INCL_GPI #include <os2.h> void fncAREA02(void){ POINTL aptl[5]; /* Structure for current position */ HPS hps; /* Initialize the array of points for the 5-pointed star. */ aptl[0].x = 400; aptl[0].y = 195; aptl[1].x = 40; aptl[1].y = 320; aptl[2].x = 260; aptl[2].y = 10; aptl[3].x = 260; aptl[3].y = 390; aptl[4].x = 37; aptl[4].y = 82; GpiSetPattern(hps, PATSYM_VERT);/* Set pattern outside bracket */ /* Draw the star. */ GpiBeginArea(hps, BA_ALTERNATE); GpiMove(hps, &aptl[4]); /* First and last point of star */ GpiPolyLine(hps, 5L, aptl); GpiEndArea(hps); } /* fncAREA02 */
Drawing Multiple, Intersecting, Closed Figures
The following figure is an example of how to use area functions to draw two intersecting boxes, filled, using the winding mode.
#define INCL_GPI #include <os2.h> void fncAREA03(void){ POINTL ptl; /* Structure for current position */ HPS hps; GpiBeginArea(hps, BA_WINDING); ptl.x = 100; ptl.y = 50; GpiMove(hps, &ptl); ptl.x = 300; ptl.y = 250; GpiBox(hps, DRO_OUTLINE, &ptl, 0, 0); ptl.x = 180; ptl.y = 120; GpiMove(hps, &ptl); ptl.x = 380; ptl.y = 320; GpiBox(hps, DRO_OUTLINE, &ptl, 0, 0); GpiEndArea(hps); } /* fncAREA03 */
Creating a Custom Fill Pattern from a Bit Map
The following figure is an example of how to create a custom fill pattern by using a hard-coded bit map. In this example, the bit map creates a pattern of arrows.
#define INCL_DOS #define INCL_GPI #define INCL_WIN #include <os2.h> LONG lcidCustom; /* Bit map tag */ HPS hps; VOID CreatePattern(VOID); VOID MyFunction(VOID){ CreatePattern(); GpiSetPatternSet(hps, lcidCustom); . . . } /* func */ VOID CreatePattern(VOID){ HBITMAP hbm; /* Bit map handle */ BITMAPINFOHEADER2 bmp2; /* Structure for bit map information */ PBITMAPINFO2 pbmi2; /* Pointer to structure for bit map data */ PRGB2 prgb2; /* Structure for color data */ ULONG cbBitmapInfo, cColors; BYTE abPattern[] = { 0xFF, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xC3, 0xFF, 0xC3, 0xFF, 0x81, 0xFF, 0x81, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF }; lcidCustom = 1; /* Bit map tag */ bmp2.cbFix = (ULONG) sizeof(BITMAPINFOHEADER2); bmp2.cx = 8; /* Bit map is 8 pels wide */ bmp2.cy = 8; /* Bit map is 8 pels high */ bmp2.cPlanes = 1; /* One bit plane */ bmp2.cBitCount = 1; /* One bit per pel */ /* Use default values for the remainder of the structure. */ bmp2.ulCompression = 0; bmp2.cbImage = 0; bmp2.cxResolution = 0; bmp2.cyResolution = 0; bmp2.cclrUsed = 0; bmp2.cclrImportant = 0; bmp2.usUnits = 0; bmp2.usReserved = 0; bmp2.usRecording = 0; bmp2.usRendering = 0; bmp2.cSize1 = 0; bmp2.cSize2 = 0; bmp2.ulColorEncoding = 0; bmp2.ulIdentifier = 0; cColors = 1 << (bmp2.cBitCount * bmp2.cPlanes); cbBitmapInfo = sizeof(BITMAPINFO2) + (sizeof(RGB2) * cColors); DosAllocMem((PVOID)&pbmi2, cbBitmapInfo, PAG_COMMIT | PAG_READ | PAG_WRITE); pbmi2->cbFix = bmp2.cbFix; pbmi2->cx = bmp2.cx; pbmi2->cy = bmp2.cy; pbmi2->cPlanes = bmp2.cPlanes; pbmi2->cBitCount = bmp2.cBitCount; /* Use default values for the remainder of the structure. */ pbmi2->ulCompression = 0; pbmi2->cbImage = 0; pbmi2->cxResolution = 0; pbmi2->cyResolution = 0; pbmi2->cclrUsed = 0; pbmi2->cclrImportant = 0; pbmi2->usUnits = 0; pbmi2->usReserved = 0; pbmi2->usRecording = 0; pbmi2->usRendering = 0; pbmi2->cSize1 = 0; pbmi2->cSize2 = 0; pbmi2->ulColorEncoding = 0; pbmi2->ulIdentifier = 0; prgb2 = (PRGB2) (pbmi2 + 1); /* Set address to follow bmp2 */ /* Set bit map colors to black and white. */ prgb2[0].bBlue = 0; /* Color[0] = black */ prgb2[0].bGreen = 0; /* Color[0] = black */ prgb2[0].bRed = 0; /* Color[0] = black */ prgb2[0].fcOptions = 0; prgb2[1].bBlue = 255; /* Color[1] = white */ prgb2[1].bGreen = 255; /* Color[1] = white */ prgb2[1].bRed = 255; /* Color[1] = white */ prgb2[1].fcOptions = 0; /* Create a bit map and retrieve its handle. */ hbm = GpiCreateBitmap(hps, &bmp2, CBM_INIT, (PBYTE) abPattern, /* Array of bits */ pbmi2); /* Tag the bit map just created with a custom identifier (lcid). */ GpiSetBitmapId(hps, hbm, lcidCustom); } /* CreatePattern */
Creating a Custom Fill Pattern from a Bit Map
Creating a Custom Fill Pattern from a Font Character
The following figure is an example of how to create a custom fill pattern by using a character from a font. The fill pattern can be only an 8-by-8 bit map; as a result, not all of the character is used.
#define INCL_GPI #define INCL_WIN #include <os2.h> HPS hps; /* Presentation-space handle */ LONG lcidCustom; /* Font identifier */ FONTMETRICS afm[80]; FATTRS fat; VOID LoadFont(VOID); void fncAREA05(void){ LoadFont(); GpiSetPatternSet(hps, lcidCustom); GpiSetPattern(hps, 'o'); /* Use lowercase 'o' as fill */ . . . } /* fncAREA05 */ VOID LoadFont(VOID){ LONG cFonts = 0; LONG cPublicFonts, i; lcidCustom = 1; /* Determine the number of loaded public fonts. */ cPublicFonts = GpiQueryFonts(hps, QF_PUBLIC, NULL, (PLONG) &cFonts, (LONG) (sizeof(FONTMETRICS)), NULL); /* Load the metrics for all public fonts into afm. */ GpiQueryFonts(hps, QF_PUBLIC, NULL, (PLONG) &cPublicFonts, (LONG) (sizeof(FONTMETRICS)), afm); /* Get the first image font with a point size larger than 8. */ for (i = 0; ((afm[i].fsDefn & FM_DEFN_OUTLINE) || afm[i].lEmHeight <= 8) && i < cPublicFonts; i++); /* Load the FATTRS structure with the required metrics. */ fat.usRecordLength = sizeof(fat); fat.fsSelection = 0; fat.lMatch = afm[i].lMatch; StringCopy(fat.szFacename, afm[i].szFacename); fat.idRegistry = 0; fat.usCodePage = 0; fat.lMaxBaselineExt = 0; fat.lAveCharWidth = 0; fat.fsType = 0; fat.fsFontUse = 0; /* Select this font and assign it a custom lcid. */ GpiCreateLogFont(hps, NULL, lcidCustom, &fat); GpiSetCharSet(hps, lcidCustom); } /* LoadFont */
Creating a Custom Fill Pattern from a Font Character