g.FillPath(New SolidBrush(Color.Black), path)
the code will generate a new figure that looks like Figure 9.17.
FIGURE 9.16: A simple graphics path
FIGURE 9.17: A filled graphics path
Note: In a graphics path, all lines and curves are connected, even though you don't connect them explicitly. Objects like rectangle and circles may not be connected (unless you connect them explicitly) but they are still part of the path.
Shaped Forms and Graphics Paths
Graphics paths are very useful when you need to create shaped (non-rectangular) forms and controls. Using a graphics path, you can also write a form with a text-based shape. For example you can write a form application that looks like Figure 9.18, which includes a text string, two ellipses, and two rectangles.
Writing applications with shaped forms is easy if we use graphics paths. First we create a GraphicsPath object and add components (such as rectangles, ellipse, or text) to the path. Then we create a Region object from the graphics path and set it as the form's Region property. For example, Listing 9.10 adds text, two rectangles, and two ellipses to a graphics path, creates a Region object from this graphics path, and sets it as the Region property of the form. The output of this code will generate a form that looks like Figure 9.18.
LISTING 9.10: Using graphics paths to create shaped forms
Dim pathAs New GraphicsPath(FillMode.Alternate)
path.AddString("Close? Right Click!",New FontFamily("Verdana"),CInt(FontStyle.Bold), 50,New Point(0, 0), StringFormat.GenericDefault)
path.AddRectangle(New Rectangle(20, 70, 100, 100))
path.AddEllipse(New Rectangle(140, 70, 100, 100))
path.AddEllipse(New Rectangle(260, 70, 100, 100))
path.AddRectangle(New Rectangle(380, 70, 100, 100))
Dim rgn AsNew Region(path)
Me.Region = rgn
To test this code, create a Windows application and add this code to the form's load event handler.
FIGURE 9.18: A shaped form
GraphicsPath Properties and Methods
Let's examine the properties and methods of the GraphicsPath class before we start using them. Table 9.7 describes the properties.
The following code snippet read some of the GraphicsPath properties
' Getting
GraphicsPath properties
Dim fMode As
FillMode = path.FillMode
Dim data As
PathData = path.PathData
Dim pts As
PointF() = path.PathPoints
Dim ptsTypes As Byte() = path.PathTypes
Dim count As Integer = path.PointCount
TABLE 9.7: GraphicsPath properties
Property | Description |
FillMode | Represents the fill mode of a graphics path, which determines how the interior of a graphics path is filled. This property is a FillMode enumeration type and has two values: Alternate and Winding. |
PathData | Returns a PathData object containing pathdata for a graphics path. The path data of a graphics path is composed of arrays of points and types. The Points property of PathData returns an array of points, and the Types property returns an array of types of points. |
PathPoint | Represents all points in a path. |
PathTypes | Represents types of the corresponding points in the PathPoints array. |
PointCount | Represents the total number of items in PathPoints |
Alternate and Winding Modes
As defined in the MSDN documentation, the alternate mode specifies that areas are filled according to the even-odd parity rule. According to this rule, you can determine whether a test point is inside or outside a closed curve as follows: Draw a line from the test point to a point that is distant from the curve. If that line crosses the curve an odd number of times, the test point is inside the curve; otherwise the test point is outside the curve.
The Winding mode specifies that areas are filled according to the nonzero winding rule, which says that you can determine whether a test point is inside or outside a closed curve as follows: Draw a line from test point to a point that is distant from the curve. Count the number of times the curve crosses the test line from left to right, and the number of times the curve crosses the test line from right to left. If those two numbers are the same, the test point is outside the curve; otherwise the test point is inside the curve.
The GraphicsPath class provides more than a dozen add methods to add graphics objects to a path. Among these methods are AddArc, AddBezier, AddBeziers, AddCloseCurve, AddCurve, AddEllipse, AddLine, AddLines, AddPath, AddPie, AddPolygon, AddRectangle, AddRectangles, and AddString. These methods are used to add an arc, a Bezier, a set of Beziers, a close curve, a curve, an ellipse, a line, a set of lines, a path, a pie, a polygon, a rectangle, as set of rectangles, and a string respectively. Other methods, which don't belong to the add category, are described in Table 9.8.
Subpaths
A graphics path can contain many subpaths. Having subpaths provides better control over individual paths. An application can break a graphics path into subpaths by using the StartFigure method. It can close open subpaths by using the CloseFigure or CloseAllFigures methods. StartFigure starts a new subpath of a path, and CloseFigure closes the opened subpath. CloseAllFigures closes all subpaths of graphics paths.
Listing 9.11 uses the StartFigure method to create three subpaths, and the CloseFigure and CloseAllFigures methods to close open figures. The first path contains an arc and a line, the second path contains two lines and a curve and the third path contains two lines.
TABLE 9.8: Some GraphicsPath methods
Method | Description |
ClearMarkers | Clears all markers from a path if any were set with PathPointType.PathMarker. |
CloseAllFigures | Closes all open figures in a path. |
CloseFigure | Closes the current figure. |
Flatten | Approximates each curve in a path with a sequence of connected line segment. |
GetLastPoint | Returns the last point in the PathPoints array. |
Reset | Removes all points and types from a path and sets the fill mode to Alternative. |
Reverse | Reverse the order of points in the PathPoints array of a path. |
SetMarkers | Sets a marker on a path. |
StartFigure | Starts a new figure. |
Transform | Transforms a path by applying a matrix on the path. |
Warp | Applies a warp transformation. |
Widen | Replace a path with curves that enclose the area that is filled when the path is drawn by the specified pen. |
LISTING 9.11: Create Graphics subpaths
Private Sub SubPathMenu_Click(ByVal senderAs Object,ByVal e As System.EventArgs)
' Create a Graphics object
Dim gAs Graphics = Me.CreateGraphics()
g.Clear(Me.BackColor) ' Create a GrphicsPath object
Dim pathAs New GraphicsPath()
' Create an array of points
Dim ptsAs Point() = {New Point(40, 80), New Point(50, 70),New Point(70, 90), New Point(100, 120), New Point(80, 120)}
' Start first figure and add an arc and a line
path.StartFigure()
path.AddArc(250, 80, 100, 50, 30, -180)
path.AddLine(180, 220, 320, 80)
' Close first figure
path.CloseFigure()
' Start second figure and two lines and
' a curve and close all figures
path.StartFigure()
path.AddLine(50, 20, 5, 90)
path.AddLine(50, 150, 150, 180)
path.AddCurve(pts, 5)
path.CloseAllFigures()
' Create third figure and don't close it
path.StartFigure()
path.AddLine(200, 230, 250, 200)
path.AddLine(200, 230, 250, 270)
' Draw path
g.DrawPath(New Pen(Color.FromArgb(255, 255, 0, 0), 2), path)
' path.Reverse();
'path.Reset();
' Dispose of object
g.Dispose()
End Sub
Figure 9.19 shows the output from Listing 9.11. There are three unconnected subpaths.
The Reverse method can be used to reveres the order of points in a path, and the Reset method to remove (empty) all points from a path. The following code snipped shows how to use these two methods.
path.Reverse()
path.Reset()
The Graphics Path Iterator
As mentioned earlier, a graphics path is a set of graphics subpaths. We can determine the number of subpaths and the related data of a subpath by using the GraphicsPathIterator class. This class allows us to iterate through all the subpaths of a graphics path.
FIGURE 9.19: Three subpaths
The Count and SubpathCount properties of GraphicsPathIterator return the total number of points and the number of subpaths in a graphics path, respectively. The CopyData method can be used to copy the points of a path and their types. It returns the number of points, which is also the number of types copied.
The HasCurves method returns true if a path has curves in it; otherwise it returns false. The NextMarker method moves the iterator to the next marker in the path. The NextPathType method returns the starting and ending indices of the next group of data points that all have the same type.
The NextSubpath method returns the starting index, ending index, and a Boolean value of true if the subpath is closed (false if the subpath is open), and moves to the next subpath. The Rewind method resets the iterator to the beginning of the path.
Listing 9.12 creates and draws a graphics path and uses GraphicsPathIterator to find and show the data for all subpaths.
Listing 9.12: Iterating through subpaths
Private Sub GraphicsPathIterator_Paint(ByVal senderAs Object,ByVal e As System.Windows.Forms.PaintEventArgs)
' Get the Graphics object
Dim gAs Graphics = e.Graphics
' Create a rectangle
Dim rectAs New Rectangle(50, 50, 100, 50) ' Create a graphics path
Dim pathAs New GraphicsPath()
Dim ptsArrayAs PointF() = {New PointF(20, 20), New PointF(60, 12), New PointF(100, 20)}
' Add a curve, a rectangle, an ellipse, and a line
path.AddCurve(ptsArray)
path.AddRectangle(rect)
rect.Y += 60
path.AddEllipse(rect)
path.AddLine(120, 50, 220, 100)
' Draw path
g.DrawPath(Pens.Blue, path)
' Create a graphics path iterator
Dim pathIteratorAs New GraphicsPathIterator(path)
' Display total points and subpaths
Dim strAs String ="Total point = " + pathIterator.SubpathCount.ToString()
MessageBox.Show(str)
'Rewind
pathIterator.Rewind()
' Read all subpaths and their properties
For iAs Integer = 0 To pathIterator.SubpathCount - 1
Dim strIdxAs Integer, endIdx As Integer
Dim bClosedCurveAs Boolean
pathIterator.NextSubpath(strIdx, endIdx, bClosedCurve)
str = (("Start Index = " + strIdx.ToString() & " , End Index = ") + endIdx.ToString() & ", IsColose = ") + bClosedCurve.ToString()
MessageBox.Show(str)
Next
End Sub
Graphics Containers
Suppose that you have a surface with 100 different graphics objects (text, shapes, and images), and you want to anti-alias just one object, perhaps for performance reasons. Without graphics containers, you would have to create a Graphics object and set the SmoothingMode property to AntiAlias â€" which would set anti-aliasing for everything drawn on the object. How do you set the smoothing mode of only one particular object on a surface? That's where containers come in.
The Graphics class provides methods and properties to define the attributes of graphics objects. For example, you can set the rendering quality to text using the TextRenderingHint property. The smoothing mode represents the quality of the graphics objects, the compositing quality represents the quality of composite images, the compositing mode represents whether pixels from a source image overwrite or are combined with background pixels, and the interpolation mode represents how intermediate values between two endpoints are calculated. These attributes are set with the SmoothingMode, CompositingMode, CompositingQuality, and InterpolationMode properties â€" which are applicable for an entire Graphics object. For example, if you set the SmoothingMode property of a Graphics object to AntiAlias, all graphics objects attached to that Graphics object will be anti-aliased.
A graphics container is a temporary graphics object that acts as a canvas for graphics shapes, allowing an application to set a container property separately from the main Graphics object. An application can apply properties to a Graphics object within a container and these properties won't be available outside of that container. Thus we can selectively apply properties to Graphics objects.
In Figure 9.20, for example, a Graphics object includes three graphics container, each with different properties. These properties are not available outside of their containers. All graphics objects inside a container may be affected by the container property. It's also possible to have nested containers.
FIGURE 9.20: Nested containers
Graphics containers do not inherit their parent's settings. In Figure 9.20, for example, the Graphics object is a container whose compositing quality is set to high and whose smoothing mode is set to high-speed. The graphics containers won't have high-speed and high-quality rendering unless we set them within the container itself. The smoothing mode of graphics container A is set to anti-aliasing; that of graphics container B is set to high quality. Graphics container C is a nested container within graphics container A, with interpolation mode set to high.
Before we discuss graphics containers in more detail, let's take a look at graphics states.
Conclusion
Hope the article would have helped you in understanding and using Graphics Paths in GDI+. Read other articles on GDI+ on the website.