@@ -88,7 +88,7 @@ private InternalPath(PointData[] points, bool isClosedPath)
8888 /// <summary>
8989 /// the orrientateion of an point form a line
9090 /// </summary>
91- private enum Orientation
91+ internal enum Orientation
9292 {
9393 /// <summary>
9494 /// Point is colienear
@@ -189,6 +189,40 @@ public int FindIntersections(PointF start, PointF end, Span<PointF> buffer)
189189 /// <param name="intersectionRule">Intersection rule types</param>
190190 /// <returns>number of intersections hit</returns>
191191 public int FindIntersections ( PointF start , PointF end , Span < PointF > buffer , IntersectionRule intersectionRule )
192+ {
193+ Orientation [ ] orientations = ArrayPool < Orientation > . Shared . Rent ( buffer . Length ) ;
194+ try
195+ {
196+ Span < Orientation > orientationsSpan = orientations . AsSpan ( 0 , buffer . Length ) ;
197+ var position = this . FindIntersectionsWithOrientation ( start , end , buffer , orientationsSpan ) ;
198+
199+ var activeBuffer = buffer . Slice ( 0 , position ) ;
200+ var activeOrientationsSpan = orientationsSpan . Slice ( 0 , position ) ;
201+
202+ // intersection rules only really apply to closed paths
203+ if ( intersectionRule == IntersectionRule . Nonzero && this . closedPath )
204+ {
205+ position = ApplyNonZeroIntersectionRules ( activeBuffer , activeOrientationsSpan ) ;
206+ }
207+
208+ return position ;
209+ }
210+ finally
211+ {
212+ ArrayPool < Orientation > . Shared . Return ( orientations ) ;
213+ }
214+ }
215+
216+ /// <summary>
217+ /// Based on a line described by <paramref name="start" /> and <paramref name="end" />
218+ /// populates a buffer for all points on the path that the line intersects.
219+ /// </summary>
220+ /// <param name="start">The start.</param>
221+ /// <param name="end">The end.</param>
222+ /// <param name="buffer">The buffer.</param>
223+ /// <param name="orientationsSpan">The buffer for storeing the orientation of each intersection.</param>
224+ /// <returns>number of intersections hit</returns>
225+ public int FindIntersectionsWithOrientation ( PointF start , PointF end , Span < PointF > buffer , Span < Orientation > orientationsSpan )
192226 {
193227 if ( this . points . Length < 2 )
194228 {
@@ -212,8 +246,7 @@ public int FindIntersections(PointF start, PointF end, Span<PointF> buffer, Inte
212246 Vector2 lastPoint = MaxVector ;
213247
214248 PassPointData [ ] precaclulate = ArrayPool < PassPointData > . Shared . Rent ( this . points . Length ) ;
215- Orientation [ ] orientations = ArrayPool < Orientation > . Shared . Rent ( this . points . Length ) ;
216- Span < Orientation > orientationsSpan = orientations . AsSpan ( 0 , this . points . Length ) ;
249+
217250 Span < PassPointData > precaclulateSpan = precaclulate . AsSpan ( 0 , this . points . Length ) ;
218251
219252 try
@@ -341,48 +374,52 @@ public int FindIntersections(PointF start, PointF end, Span<PointF> buffer, Inte
341374 distances [ i ] = Vector2 . DistanceSquared ( startVector , buffer [ i ] ) ;
342375 }
343376
344- QuickSort . Sort ( distances , buffer . Slice ( 0 , position ) , orientationsSpan . Slice ( 0 , position ) ) ;
345-
346- // intersection rules only really apply to closed paths
347- if ( intersectionRule == IntersectionRule . Nonzero && this . closedPath )
348- {
349- int newpositions = 0 ;
350- int tracker = 0 ;
351- for ( int i = 0 ; i < position ; i ++ )
352- {
353- bool include = tracker == 0 ;
354- switch ( orientationsSpan [ i ] )
355- {
356- case Orientation . Clockwise :
357- tracker ++ ;
358- break ;
359- case Orientation . Counterclockwise :
360- tracker -- ;
361- break ;
362- case Orientation . Colinear :
363- default :
364- break ;
365- }
366-
367- if ( include || tracker == 0 )
368- {
369- buffer [ newpositions ] = buffer [ i ] ;
370- newpositions ++ ;
371- }
372- }
373-
374- position = newpositions ;
375- }
377+ var activeBuffer = buffer . Slice ( 0 , position ) ;
378+ var activeOrientationsSpan = orientationsSpan . Slice ( 0 , position ) ;
379+ QuickSort . Sort ( distances , activeBuffer , activeOrientationsSpan ) ;
376380
377381 return position ;
378382 }
379383 finally
380384 {
381- ArrayPool < Orientation > . Shared . Return ( orientations ) ;
382385 ArrayPool < PassPointData > . Shared . Return ( precaclulate ) ;
383386 }
384387 }
385388
389+ internal static int ApplyNonZeroIntersectionRules ( Span < PointF > buffer , Span < Orientation > orientationsSpan )
390+ {
391+ int newpositions = 0 ;
392+ int tracker = 0 ;
393+ int diff = 0 ;
394+ for ( int i = 0 ; i < buffer . Length ; i ++ )
395+ {
396+ bool include = tracker == 0 ;
397+ switch ( orientationsSpan [ i ] )
398+ {
399+ case Orientation . Counterclockwise :
400+ diff = 1 ;
401+ break ;
402+ case Orientation . Clockwise :
403+ diff = - 1 ;
404+ break ;
405+ case Orientation . Colinear :
406+ default :
407+ diff *= - 1 ;
408+ break ;
409+ }
410+
411+ tracker += diff ;
412+
413+ if ( include || tracker == 0 )
414+ {
415+ buffer [ newpositions ] = buffer [ i ] ;
416+ newpositions ++ ;
417+ }
418+ }
419+
420+ return newpositions ;
421+ }
422+
386423 /// <summary>
387424 /// Determines if the specified point is inside or outside the path.
388425 /// </summary>
0 commit comments