1111namespace SixLabors . ImageSharp . Drawing
1212{
1313 /// <summary>
14- /// Represents a complex polygon made up of one or more shapes overlayed on each other, where overlaps causes holes.
14+ /// Represents a complex polygon made up of one or more shapes overlayed on each other,
15+ /// where overlaps causes holes.
1516 /// </summary>
1617 /// <seealso cref="IPath" />
17- public sealed class ComplexPolygon : IPath , IInternalPathOwner
18+ public sealed class ComplexPolygon : IPath , IPathInternals , IInternalPathOwner
1819 {
1920 private readonly IPath [ ] paths ;
20- private List < InternalPath > internalPaths = null ;
21+ private readonly List < InternalPath > internalPaths ;
22+ private readonly int maxIntersections ;
2123
2224 /// <summary>
2325 /// Initializes a new instance of the <see cref="ComplexPolygon" /> class.
@@ -34,7 +36,10 @@ public ComplexPolygon(IEnumerable<IPath> paths)
3436 /// <param name="paths">The paths.</param>
3537 public ComplexPolygon ( params IPath [ ] paths )
3638 {
37- this . paths = paths ?? throw new ArgumentNullException ( nameof ( paths ) ) ;
39+ Guard . NotNull ( paths , nameof ( paths ) ) ;
40+
41+ this . paths = paths ;
42+ this . internalPaths = new List < InternalPath > ( this . paths . Length ) ;
3843
3944 if ( paths . Length > 0 )
4045 {
@@ -45,39 +50,45 @@ public ComplexPolygon(params IPath[] paths)
4550 float length = 0 ;
4651 int intersections = 0 ;
4752
48- foreach ( IPath s in this . paths )
53+ foreach ( IPath p in this . paths )
4954 {
50- length += s . Length ;
51- if ( s . Bounds . Left < minX )
55+ length += p . Length ;
56+ if ( p . Bounds . Left < minX )
5257 {
53- minX = s . Bounds . Left ;
58+ minX = p . Bounds . Left ;
5459 }
5560
56- if ( s . Bounds . Right > maxX )
61+ if ( p . Bounds . Right > maxX )
5762 {
58- maxX = s . Bounds . Right ;
63+ maxX = p . Bounds . Right ;
5964 }
6065
61- if ( s . Bounds . Top < minY )
66+ if ( p . Bounds . Top < minY )
6267 {
63- minY = s . Bounds . Top ;
68+ minY = p . Bounds . Top ;
6469 }
6570
66- if ( s . Bounds . Bottom > maxY )
71+ if ( p . Bounds . Bottom > maxY )
6772 {
68- maxY = s . Bounds . Bottom ;
73+ maxY = p . Bounds . Bottom ;
6974 }
7075
71- intersections += s . MaxIntersections ;
76+ foreach ( ISimplePath s in p . Flatten ( ) )
77+ {
78+ var ip = new InternalPath ( s . Points , s . IsClosed ) ;
79+ intersections += ip . PointCount ;
80+
81+ this . internalPaths . Add ( ip ) ;
82+ }
7283 }
7384
74- this . MaxIntersections = intersections ;
85+ this . maxIntersections = intersections ;
7586 this . Length = length ;
7687 this . Bounds = new RectangleF ( minX , minY , maxX - minX , maxY - minY ) ;
7788 }
7889 else
7990 {
80- this . MaxIntersections = 0 ;
91+ this . maxIntersections = 0 ;
8192 this . Length = 0 ;
8293 this . Bounds = RectangleF . Empty ;
8394 }
@@ -111,13 +122,8 @@ public ComplexPolygon(params IPath[] paths)
111122 /// </value>
112123 public RectangleF Bounds { get ; }
113124
114- /// <summary>
115- /// Gets the maximum number intersections that a shape can have when testing a line.
116- /// </summary>
117- /// <value>
118- /// The maximum intersections.
119- /// </value>
120- public int MaxIntersections { get ; }
125+ /// <inheritdoc/>
126+ int IPathInternals . MaxIntersections => this . maxIntersections ;
121127
122128 /// <summary>
123129 /// The distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
@@ -163,19 +169,17 @@ public PointInfo Distance(PointF point)
163169 }
164170
165171 /// <inheritdoc />
166- public int FindIntersections ( PointF start , PointF end , Span < PointF > intersections , Span < PointOrientation > orientations )
167- => this . FindIntersections ( start , end , intersections , orientations , IntersectionRule . OddEven ) ;
172+ int IPathInternals . FindIntersections ( PointF start , PointF end , Span < PointF > intersections , Span < PointOrientation > orientations )
173+ => ( ( IPathInternals ) this ) . FindIntersections ( start , end , intersections , orientations , IntersectionRule . OddEven ) ;
168174
169175 /// <inheritdoc />
170- public int FindIntersections (
176+ int IPathInternals . FindIntersections (
171177 PointF start ,
172178 PointF end ,
173179 Span < PointF > intersections ,
174180 Span < PointOrientation > orientations ,
175181 IntersectionRule intersectionRule )
176182 {
177- this . EnsureInternalPathsInitalized ( ) ;
178-
179183 int totalAdded = 0 ;
180184 foreach ( InternalPath ip in this . internalPaths )
181185 {
@@ -204,29 +208,6 @@ public int FindIntersections(
204208 return totalAdded ;
205209 }
206210
207- private void EnsureInternalPathsInitalized ( )
208- {
209- if ( this . internalPaths == null )
210- {
211- lock ( this . paths )
212- {
213- if ( this . internalPaths == null )
214- {
215- this . internalPaths = new List < InternalPath > ( this . paths . Length ) ;
216-
217- foreach ( IPath p in this . paths )
218- {
219- foreach ( ISimplePath s in p . Flatten ( ) )
220- {
221- var ip = new InternalPath ( s . Points , s . IsClosed ) ;
222- this . internalPaths . Add ( ip ) ;
223- }
224- }
225- }
226- }
227- }
228- }
229-
230211 /// <summary>
231212 /// Determines whether the <see cref="IPath" /> contains the specified point
232213 /// </summary>
@@ -267,7 +248,7 @@ public IPath Transform(Matrix3x2 matrix)
267248 int i = 0 ;
268249 foreach ( IPath s in this . Paths )
269250 {
270- shapes [ i ++ ] = s . Transform ( matrix ) ;
251+ shapes [ i ++ ] = ( IPath ) s . Transform ( matrix ) ;
271252 }
272253
273254 return new ComplexPolygon ( shapes ) ;
@@ -307,7 +288,7 @@ public IPath AsClosedPath()
307288 var paths = new IPath [ this . paths . Length ] ;
308289 for ( int i = 0 ; i < this . paths . Length ; i ++ )
309290 {
310- paths [ i ] = this . paths [ i ] . AsClosedPath ( ) ;
291+ paths [ i ] = ( IPath ) this . paths [ i ] . AsClosedPath ( ) ;
311292 }
312293
313294 return new ComplexPolygon ( paths ) ;
@@ -336,14 +317,12 @@ public SegmentInfo PointAlongPath(float distanceAlongPath)
336317 distanceAlongPath -= p . Length ;
337318 }
338319
320+ // TODO: Perf. Throwhelper
339321 throw new InvalidOperationException ( "Should not be possible to reach this line" ) ;
340322 }
341323
342324 /// <inheritdoc/>
343325 IReadOnlyList < InternalPath > IInternalPathOwner . GetRingsAsInternalPath ( )
344- {
345- this . EnsureInternalPathsInitalized ( ) ;
346- return this . internalPaths ;
347- }
326+ => this . internalPaths ;
348327 }
349328}
0 commit comments