33
44using System ;
55using System . Collections . Generic ;
6- using System . Linq ;
76using System . Numerics ;
8- using System . Runtime . InteropServices ;
9- using ClipperLib ;
7+ using SixLabors . ImageSharp . Drawing . Shapes . PolygonClipper ;
108
119namespace SixLabors . ImageSharp . Drawing
1210{
@@ -16,7 +14,6 @@ namespace SixLabors.ImageSharp.Drawing
1614 public static class OutlinePathExtensions
1715 {
1816 private const double MiterOffsetDelta = 20 ;
19- private const float ScalingFactor = 1000.0f ;
2017
2118 /// <summary>
2219 /// Generates a outline of the path with alternating on and off segments based on the pattern.
@@ -77,17 +74,10 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
7774 return path . GenerateOutline ( width , jointStyle : jointStyle ) ;
7875 }
7976
80- JoinType style = Convert ( jointStyle ) ;
81- EndType patternSectionCap = Convert ( patternSectionCapStyle ) ;
82-
8377 IEnumerable < ISimplePath > paths = path . Flatten ( ) ;
8478
85- var offset = new ClipperOffset ( )
86- {
87- MiterLimit = MiterOffsetDelta
88- } ;
89-
90- var buffer = new List < IntPoint > ( 3 ) ;
79+ var offset = new ClipperOffset ( MiterOffsetDelta ) ;
80+ var buffer = new List < PointF > ( ) ;
9181 foreach ( ISimplePath p in paths )
9282 {
9383 bool online = ! startOff ;
@@ -116,13 +106,13 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
116106 float t = targetLength / distToNext ;
117107
118108 Vector2 point = ( currentPoint * ( 1 - t ) ) + ( targetPoint * t ) ;
119- buffer . Add ( currentPoint . ToPoint ( ) ) ;
120- buffer . Add ( point . ToPoint ( ) ) ;
109+ buffer . Add ( currentPoint ) ;
110+ buffer . Add ( point ) ;
121111
122112 // we now inset a line joining
123113 if ( online )
124114 {
125- offset . AddPath ( buffer , style , patternSectionCap ) ;
115+ offset . AddPath ( new ReadOnlySpan < PointF > ( buffer . ToArray ( ) ) , jointStyle , patternSectionCapStyle ) ;
126116 }
127117
128118 online = ! online ;
@@ -137,7 +127,7 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
137127 }
138128 else if ( distToNext <= targetLength )
139129 {
140- buffer . Add ( currentPoint . ToPoint ( ) ) ;
130+ buffer . Add ( currentPoint ) ;
141131 currentPoint = targetPoint ;
142132 i ++ ;
143133 targetLength -= distToNext ;
@@ -148,16 +138,16 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
148138 {
149139 if ( p . IsClosed )
150140 {
151- buffer . Add ( points [ 0 ] . ToPoint ( ) ) ;
141+ buffer . Add ( points [ 0 ] ) ;
152142 }
153143 else
154144 {
155- buffer . Add ( points [ points . Length - 1 ] . ToPoint ( ) ) ;
145+ buffer . Add ( points [ points . Length - 1 ] ) ;
156146 }
157147
158148 if ( online )
159149 {
160- offset . AddPath ( buffer , style , patternSectionCap ) ;
150+ offset . AddPath ( new ReadOnlySpan < PointF > ( buffer . ToArray ( ) ) , jointStyle , patternSectionCapStyle ) ;
161151 }
162152
163153 online = ! online ;
@@ -168,7 +158,7 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
168158 }
169159 }
170160
171- return ExecuteOutliner ( width , offset ) ;
161+ return offset . Execute ( width ) ;
172162 }
173163
174164 /// <summary>
@@ -189,67 +179,10 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
189179 /// <returns>A new path representing the outline.</returns>
190180 public static IPath GenerateOutline ( this IPath path , float width , JointStyle jointStyle = JointStyle . Square , EndCapStyle endCapStyle = EndCapStyle . Square )
191181 {
192- var offset = new ClipperOffset ( )
193- {
194- MiterLimit = MiterOffsetDelta
195- } ;
196-
197- JoinType style = Convert ( jointStyle ) ;
198- EndType openEndCapStyle = Convert ( endCapStyle ) ;
199-
200- // Pattern can be applied to the path by cutting it into segments
201- IEnumerable < ISimplePath > paths = path . Flatten ( ) ;
202- foreach ( ISimplePath p in paths )
203- {
204- ReadOnlySpan < Vector2 > vectors = MemoryMarshal . Cast < PointF , Vector2 > ( p . Points . Span ) ;
205- var points = new List < IntPoint > ( vectors . Length ) ;
206- foreach ( Vector2 v in vectors )
207- {
208- points . Add ( new IntPoint ( v . X * ScalingFactor , v . Y * ScalingFactor ) ) ;
209- }
210-
211- EndType type = p . IsClosed ? EndType . etClosedLine : openEndCapStyle ;
212-
213- offset . AddPath ( points , style , type ) ;
214- }
215-
216- return ExecuteOutliner ( width , offset ) ;
217- }
218-
219- private static ComplexPolygon ExecuteOutliner ( float width , ClipperOffset offset )
220- {
221- var tree = new List < List < IntPoint > > ( ) ;
222- offset . Execute ( ref tree , width * ScalingFactor / 2 ) ;
223- var polygons = new List < Polygon > ( ) ;
224- foreach ( List < IntPoint > pt in tree )
225- {
226- PointF [ ] points = pt . Select ( p => new PointF ( p . X / ScalingFactor , p . Y / ScalingFactor ) ) . ToArray ( ) ;
227- polygons . Add ( new Polygon ( new LinearLineSegment ( points ) ) ) ;
228- }
182+ var offset = new ClipperOffset ( MiterOffsetDelta ) ;
183+ offset . AddPath ( path , jointStyle , endCapStyle ) ;
229184
230- return new ComplexPolygon ( polygons . ToArray ( ) ) ;
185+ return offset . Execute ( width ) ;
231186 }
232-
233- private static IntPoint ToPoint ( this PointF vector )
234- => new IntPoint ( vector . X * ScalingFactor , vector . Y * ScalingFactor ) ;
235-
236- private static IntPoint ToPoint ( this Vector2 vector )
237- => new IntPoint ( vector . X * ScalingFactor , vector . Y * ScalingFactor ) ;
238-
239- private static JoinType Convert ( JointStyle style )
240- => style switch
241- {
242- JointStyle . Round => JoinType . jtRound ,
243- JointStyle . Miter => JoinType . jtMiter ,
244- _ => JoinType . jtSquare ,
245- } ;
246-
247- private static EndType Convert ( EndCapStyle style )
248- => style switch
249- {
250- EndCapStyle . Round => EndType . etOpenRound ,
251- EndCapStyle . Square => EndType . etOpenSquare ,
252- _ => EndType . etOpenButt ,
253- } ;
254187 }
255188}
0 commit comments