@@ -15,6 +15,7 @@ namespace SixLabors.Shapes
1515 /// </summary>
1616 public static class Outliner
1717 {
18+ private const double MiterOffsetDelta = 20 ;
1819 private const float ScalingFactor = 1000.0f ;
1920
2021 /// <summary>
@@ -59,15 +60,34 @@ public static IPath GenerateOutline(this IPath path, float width, float[] patter
5960 /// <param name="startOff">Weather the first item in the pattern is on or off.</param>
6061 /// <returns>A new path representing the outline.</returns>
6162 public static IPath GenerateOutline ( this IPath path , float width , ReadOnlySpan < float > pattern , bool startOff )
63+ => GenerateOutline ( path , width , pattern , startOff , JointStyle . Square , EndCapStyle . Butt ) ;
64+
65+ /// <summary>
66+ /// Generates a outline of the path with alternating on and off segments based on the pattern.
67+ /// </summary>
68+ /// <param name="path">the path to outline</param>
69+ /// <param name="width">The final width outline</param>
70+ /// <param name="pattern">The pattern made of multiples of the width.</param>
71+ /// <param name="startOff">Weather the first item in the pattern is on or off.</param>
72+ /// <param name="jointStyle">The style to render the joints.</param>
73+ /// <param name="patternSectionCapStyle">The style to render between sections of the specified pattern.</param>
74+ /// <returns>A new path representing the outline.</returns>
75+ public static IPath GenerateOutline ( this IPath path , float width , ReadOnlySpan < float > pattern , bool startOff , JointStyle jointStyle = JointStyle . Square , EndCapStyle patternSectionCapStyle = EndCapStyle . Butt )
6276 {
6377 if ( pattern . Length < 2 )
6478 {
6579 return path . GenerateOutline ( width ) ;
6680 }
6781
82+ var style = Convert ( jointStyle ) ;
83+ var patternSectionCap = Convert ( patternSectionCapStyle ) ;
84+
6885 IEnumerable < ISimplePath > paths = path . Flatten ( ) ;
6986
70- var offset = new ClipperOffset ( ) ;
87+ var offset = new ClipperOffset ( )
88+ {
89+ MiterLimit = MiterOffsetDelta
90+ } ;
7191
7292 var buffer = new List < IntPoint > ( 3 ) ;
7393 foreach ( ISimplePath p in paths )
@@ -103,7 +123,7 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
103123 // we now inset a line joining
104124 if ( online )
105125 {
106- offset . AddPath ( buffer , JoinType . jtSquare , EndType . etOpenButt ) ;
126+ offset . AddPath ( buffer , style , patternSectionCap ) ;
107127 }
108128
109129 online = ! online ;
@@ -138,7 +158,7 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
138158
139159 if ( online )
140160 {
141- offset . AddPath ( buffer , JoinType . jtSquare , EndType . etOpenButt ) ;
161+ offset . AddPath ( buffer , style , patternSectionCap ) ;
142162 }
143163
144164 online = ! online ;
@@ -158,9 +178,25 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
158178 /// <param name="path">the path to outline</param>
159179 /// <param name="width">The final width outline</param>
160180 /// <returns>A new path representing the outline.</returns>
161- public static IPath GenerateOutline ( this IPath path , float width )
181+ public static IPath GenerateOutline ( this IPath path , float width ) => GenerateOutline ( path , width , JointStyle . Square , EndCapStyle . Butt ) ;
182+
183+ /// <summary>
184+ /// Generates a solid outline of the path.
185+ /// </summary>
186+ /// <param name="path">the path to outline</param>
187+ /// <param name="width">The final width outline</param>
188+ /// <param name="jointStyle">The style to render the joints.</param>
189+ /// <param name="endCapStyle">The style to render the end caps of open paths (ignored on closed paths).</param>
190+ /// <returns>A new path representing the outline.</returns>
191+ public static IPath GenerateOutline ( this IPath path , float width , JointStyle jointStyle = JointStyle . Square , EndCapStyle endCapStyle = EndCapStyle . Butt )
162192 {
163- var offset = new ClipperOffset ( ) ;
193+ var offset = new ClipperOffset ( )
194+ {
195+ MiterLimit = MiterOffsetDelta
196+ } ;
197+
198+ var style = Convert ( jointStyle ) ;
199+ var openEndCapStyle = Convert ( endCapStyle ) ;
164200
165201 // Pattern can be applied to the path by cutting it into segments
166202 IEnumerable < ISimplePath > paths = path . Flatten ( ) ;
@@ -173,9 +209,9 @@ public static IPath GenerateOutline(this IPath path, float width)
173209 points . Add ( new IntPoint ( v . X * ScalingFactor , v . Y * ScalingFactor ) ) ;
174210 }
175211
176- EndType type = p . IsClosed ? EndType . etClosedLine : EndType . etOpenButt ;
212+ EndType type = p . IsClosed ? EndType . etClosedLine : openEndCapStyle ;
177213
178- offset . AddPath ( points , JoinType . jtSquare , type ) ;
214+ offset . AddPath ( points , style , type ) ;
179215 }
180216
181217 return ExecuteOutliner ( width , offset ) ;
@@ -204,5 +240,33 @@ private static IntPoint ToPoint(this Vector2 vector)
204240 {
205241 return new IntPoint ( vector . X * ScalingFactor , vector . Y * ScalingFactor ) ;
206242 }
243+
244+ private static JoinType Convert ( JointStyle style )
245+ {
246+ switch ( style )
247+ {
248+ case JointStyle . Round :
249+ return JoinType . jtRound ;
250+ case JointStyle . Miter :
251+ return JoinType . jtMiter ;
252+ case JointStyle . Square :
253+ default :
254+ return JoinType . jtSquare ;
255+ }
256+ }
257+
258+ private static EndType Convert ( EndCapStyle style )
259+ {
260+ switch ( style )
261+ {
262+ case EndCapStyle . Round :
263+ return EndType . etOpenRound ;
264+ case EndCapStyle . Square :
265+ return EndType . etOpenSquare ;
266+ case EndCapStyle . Butt :
267+ default :
268+ return EndType . etOpenButt ;
269+ }
270+ }
207271 }
208272}
0 commit comments