The code below is designed to work with a graphics object defined from lines. The format of the array of PathTypes of the GraphicsPath object being passed should be a single set of {0,1,1,.... all ones ...,129). This can be done by adding points using AddLines (of course), then closing the GraphicsPath figure.
I created a Classic Windows Forms Project with VB coding. It has a form, Form1, with one control: A 500x500 label, Label1.
The vbcode of the form is this:
Imports System.Drawing.Drawing2D
Public Class Form1
Private Sub Label1_Paint(sender As Object, e As PaintEventArgs) Handles Label1.Paint
Dim SamplePoints() As PointF = {New PointF(86, 132), New PointF(302, 106), New PointF(220, 190),
New PointF(410, 232), New PointF(242, 290), New PointF(374, 324), New PointF(352, 376),
New PointF(316, 330), New PointF(278, 390), New PointF(268, 340), New PointF(136, 216),
New PointF(184, 146)}
Dim gr0 As Graphics = e.Graphics
Dim pthx As GraphicsPath = New GraphicsPath
Dim pth2 As GraphicsPath
Dim pnx As Pen = New Pen(Color.Black, 1)
pthx.AddLines(SamplePoints)
pthx.CloseFigure()
pth2 = outlineGraphicsPath(pthx, 10, True)
gr0.FillPath(Brushes.Blue, pthx)
gr0.FillPath(Brushes.Red, pth2)
End Sub
End Class
I added a module to the project and used this code.
Imports System.Drawing.Drawing2D
Module Module1
Friend Function calcPositiveRadianTangent(x As Double, y As Double) As Double
Dim sn1 As Double
If (x = 0) And (y = 0) Then Return 0
sn1 = Math.Atan(y / x)
If x < 0 Then
Select Case y
Case 0
sn1 = Math.PI
Case Else
sn1 = Math.PI + sn1
End Select
ElseIf x > 0 Then
If y < 0 Then
sn1 = 2 * Math.PI + sn1
End If
Else
If y < 0 Then
sn1 = 3 * Math.PI / 2
End If
End If
Return sn1
End Function
Friend Function vertexOffsetPoints(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x3 As Double, y3 As Double, lineWidth As Double) As PointF()
Dim sn3, sn4, sn5, snbrg, sn6 As Double
Dim pts(2) As PointF
sn3 = calcPositiveRadianTangent(x2 - x1, y2 - y1)
sn5 = calcPositiveRadianTangent(x2 - x3, y2 - y3)
sn4 = Math.Abs((sn3 - sn5) / 2)
snbrg = (sn3 + sn5) / 2
sn6 = lineWidth / Math.Sin(sn4)
pts(0).X = sn6 * Math.Cos(snbrg) + x2
pts(0).Y = sn6 * Math.Sin(snbrg) + y2
pts(2).X = 2 * Math.Cos(snbrg) + x2 'for checking which side is inside
pts(2).Y = 2 * Math.Sin(snbrg) + y2
snbrg += Math.PI
pts(1).X = sn6 * Math.Cos(snbrg) + x2
pts(1).Y = sn6 * Math.Sin(snbrg) + y2
Return pts
End Function
Friend Function outlineGraphicsPath(pathIn As GraphicsPath, outlineThickness As Double, isOuter As Boolean) As GraphicsPath
Dim pthx As GraphicsPath = pathIn.Clone
Dim secondPoints(), secondPointSet() As PointF
Dim lt3 As Integer
ReDim secondPointSet(pthx.PathPoints.GetUpperBound(0))
For lt1 = 0 To pthx.PathPoints.GetUpperBound(0)
If lt1 = 0 Then
lt3 = pthx.PathPoints.GetUpperBound(0)
Else
lt3 = lt1 - 1
End If
secondPoints = vertexOffsetPoints(pthx.PathPoints(lt3).X, pthx.PathPoints(lt3).Y, pthx.PathPoints(lt1).X, pthx.PathPoints(lt1).Y, pthx.PathPoints((lt1 + 1) Mod pthx.PathPoints.Length).X, pthx.PathPoints((lt1 + 1) Mod pthx.PathPoints.Length).Y, outlineThickness)
If pthx.IsVisible(secondPoints(2).X, secondPoints(2).Y) Then
If isOuter Then
secondPointSet(lt1) = secondPoints(1)
Else
secondPointSet(lt1) = secondPoints(0)
End If
Else
If Not isOuter Then
secondPointSet(lt1) = secondPoints(1)
Else
secondPointSet(lt1) = secondPoints(0)
End If
End If
Next
pthx.AddLines(secondPointSet)
pthx.CloseFigure()
Return pthx
End Function
End Module
When the form starts it draws the figure.
This is the irregular polygon with the third parameter of outlineGraphicsPath set to True, creating a path that is then filled to render an outer line.
In this example the third parameter is set to False, and the line renders inside the GraphicsPath object. Notice that sharp corners inside can create protrusions that go through the figure, because the extended points surpass the line width.
That's about it.