@@ -245,164 +245,151 @@ public int FindIntersectionsWithOrientation(
245245 int position = 0 ;
246246 Vector2 lastPoint = MaxVector ;
247247
248- int max = this . points . Length ;
249- Span < PassPointData > precaclulateSpan ;
250- PassPointData [ ] precaclulate = null ;
251-
252- // Avoid pool overhead for short numbers.
248+ // Avoid pool overhead for short runs.
253249 // This method can be called in high volume.
254- unsafe
255- {
256- if ( max < ( 1024 / sizeof ( PassPointData ) ) )
250+ int pointsLength = this . points . Length ;
251+ int maxStackSize = 1024 / Unsafe . SizeOf < PassPointData > ( ) ;
252+ PassPointData [ ] rentedFromPool = null ;
253+ Span < PassPointData > buffer =
254+ pointsLength > maxStackSize
255+ ? ( rentedFromPool = ArrayPool < PassPointData > . Shared . Rent ( pointsLength ) )
256+ : stackalloc PassPointData [ maxStackSize ] ;
257+
258+ Span < PassPointData > precalculate = buffer . Slice ( 0 , pointsLength ) ;
259+
260+ // Pre calculate relative orientations X places ahead and behind
261+ Vector2 startToEnd = end - start ;
262+ PointOrientation prevOrientation = CalulateOrientation ( startToEnd , this . points [ polyCorners - 1 ] . Point - end ) ;
263+ PointOrientation nextOrientation = CalulateOrientation ( startToEnd , this . points [ 0 ] . Point - end ) ;
264+ PointOrientation nextPlus1Orientation = CalulateOrientation ( startToEnd , this . points [ 1 ] . Point - end ) ;
265+
266+ // iterate over all points and precalculate data about each, pre cacluating it relative orientation
267+ for ( int i = 0 ; i < polyCorners && count > 0 ; i ++ )
268+ {
269+ ref Segment edge = ref this . points [ i ] . Segment ;
270+
271+ // shift all orientations along but one place and fill in the last one
272+ PointOrientation pointOrientation = nextOrientation ;
273+ nextOrientation = nextPlus1Orientation ;
274+ nextPlus1Orientation = CalulateOrientation ( startToEnd , this . points [ WrapArrayIndex ( i + 2 , this . points . Length ) ] . Point - end ) ;
275+
276+ // should this point cause the last matched point to be excluded
277+ bool removeLastIntersection = nextOrientation == PointOrientation . Collinear &&
278+ pointOrientation == PointOrientation . Collinear &&
279+ nextPlus1Orientation != prevOrientation &&
280+ ( this . closedPath || i > 0 ) &&
281+ ( IsOnSegment ( target , edge . Start ) || IsOnSegment ( target , edge . End ) ) ;
282+
283+ // is there any chance the segments will intersection (do their bounding boxes touch)
284+ bool doIntersect = false ;
285+ if ( pointOrientation == PointOrientation . Collinear || pointOrientation != nextOrientation )
257286 {
258- PassPointData * points = stackalloc PassPointData [ max ] ;
259- precaclulateSpan = new Span < PassPointData > ( points , max ) ;
287+ doIntersect = ( edge . Min . X - Epsilon ) <= target . Max . X &&
288+ ( edge . Max . X + Epsilon ) >= target . Min . X &&
289+ ( edge . Min . Y - Epsilon ) <= target . Max . Y &&
290+ ( edge . Max . Y + Epsilon ) >= target . Min . Y ;
260291 }
261- else
292+
293+ precalculate [ i ] = new PassPointData
262294 {
263- precaclulate = ArrayPool < PassPointData > . Shared . Rent ( max ) ;
264- precaclulateSpan = precaclulate . AsSpan ( 0 , this . points . Length ) ;
265- }
295+ RemoveLastIntersectionAndSkip = removeLastIntersection ,
296+ RelativeOrientation = pointOrientation ,
297+ DoIntersect = doIntersect
298+ } ;
299+
300+ prevOrientation = pointOrientation ;
266301 }
267302
268- try
303+ // seed the last point for deduping at begining of closed line
304+ if ( this . closedPath )
269305 {
270- // Pre calculate relative orientations X places ahead and behind
271- Vector2 startToEnd = end - start ;
272- PointOrientation prevOrientation = CalulateOrientation ( startToEnd , this . points [ polyCorners - 1 ] . Point - end ) ;
273- PointOrientation nextOrientation = CalulateOrientation ( startToEnd , this . points [ 0 ] . Point - end ) ;
274- PointOrientation nextPlus1Orientation = CalulateOrientation ( startToEnd , this . points [ 1 ] . Point - end ) ;
306+ int prev = polyCorners - 1 ;
275307
276- // iterate over all points and precalculate data about each, pre cacluating it relative orientation
277- for ( int i = 0 ; i < polyCorners && count > 0 ; i ++ )
308+ if ( precalculate [ prev ] . DoIntersect )
278309 {
279- ref Segment edge = ref this . points [ i ] . Segment ;
280-
281- // shift all orientations along but one place and fill in the last one
282- PointOrientation pointOrientation = nextOrientation ;
283- nextOrientation = nextPlus1Orientation ;
284- nextPlus1Orientation = CalulateOrientation ( startToEnd , this . points [ WrapArrayIndex ( i + 2 , this . points . Length ) ] . Point - end ) ;
285-
286- // should this point cause the last matched point to be excluded
287- bool removeLastIntersection = nextOrientation == PointOrientation . Collinear &&
288- pointOrientation == PointOrientation . Collinear &&
289- nextPlus1Orientation != prevOrientation &&
290- ( this . closedPath || i > 0 ) &&
291- ( IsOnSegment ( target , edge . Start ) || IsOnSegment ( target , edge . End ) ) ;
292-
293- // is there any chance the segments will intersection (do their bounding boxes touch)
294- bool doIntersect = false ;
295- if ( pointOrientation == PointOrientation . Collinear || pointOrientation != nextOrientation )
296- {
297- doIntersect = ( edge . Min . X - Epsilon ) <= target . Max . X &&
298- ( edge . Max . X + Epsilon ) >= target . Min . X &&
299- ( edge . Min . Y - Epsilon ) <= target . Max . Y &&
300- ( edge . Max . Y + Epsilon ) >= target . Min . Y ;
301- }
302-
303- precaclulateSpan [ i ] = new PassPointData
304- {
305- RemoveLastIntersectionAndSkip = removeLastIntersection ,
306- RelativeOrientation = pointOrientation ,
307- DoIntersect = doIntersect
308- } ;
309-
310- prevOrientation = pointOrientation ;
310+ lastPoint = FindIntersection ( this . points [ prev ] . Segment , target ) ;
311311 }
312+ }
312313
313- // seed the last point for deduping at begining of closed line
314- if ( this . closedPath )
315- {
316- int prev = polyCorners - 1 ;
314+ for ( int i = 0 ; i < polyCorners && count > 0 ; i ++ )
315+ {
316+ int next = WrapArrayIndex ( i + 1 , this . points . Length ) ;
317317
318- if ( precaclulateSpan [ prev ] . DoIntersect )
318+ if ( precalculate [ i ] . RemoveLastIntersectionAndSkip )
319+ {
320+ if ( position > 0 )
319321 {
320- lastPoint = FindIntersection ( this . points [ prev ] . Segment , target ) ;
322+ position -- ;
323+ count ++ ;
321324 }
325+
326+ continue ;
322327 }
323328
324- for ( int i = 0 ; i < polyCorners && count > 0 ; i ++ )
329+ if ( precalculate [ i ] . DoIntersect )
325330 {
326- int next = WrapArrayIndex ( i + 1 , this . points . Length ) ;
327-
328- if ( precaclulateSpan [ i ] . RemoveLastIntersectionAndSkip )
331+ Vector2 point = FindIntersection ( this . points [ i ] . Segment , target ) ;
332+ if ( point != MaxVector )
329333 {
330- if ( position > 0 )
334+ if ( lastPoint . Equivalent ( point , Epsilon2 ) )
331335 {
332- position -- ;
333- count ++ ;
334- }
336+ lastPoint = MaxVector ;
335337
336- continue ;
337- }
338+ int last = WrapArrayIndex ( i - 1 + polyCorners , polyCorners ) ;
338339
339- if ( precaclulateSpan [ i ] . DoIntersect )
340- {
341- Vector2 point = FindIntersection ( this . points [ i ] . Segment , target ) ;
342- if ( point != MaxVector )
343- {
344- if ( lastPoint . Equivalent ( point , Epsilon2 ) )
340+ // hit the same point a second time do we need to remove the old one if just clipping
341+ if ( this . points [ next ] . Point . Equivalent ( point , Epsilon ) )
345342 {
346- lastPoint = MaxVector ;
347-
348- int last = WrapArrayIndex ( i - 1 + polyCorners , polyCorners ) ;
349-
350- // hit the same point a second time do we need to remove the old one if just clipping
351- if ( this . points [ next ] . Point . Equivalent ( point , Epsilon ) )
352- {
353- next = i ;
354- }
343+ next = i ;
344+ }
355345
356- if ( this . points [ last ] . Point . Equivalent ( point , Epsilon ) )
357- {
358- last = i ;
359- }
346+ if ( this . points [ last ] . Point . Equivalent ( point , Epsilon ) )
347+ {
348+ last = i ;
349+ }
360350
361- PointOrientation side = precaclulateSpan [ next ] . RelativeOrientation ;
362- PointOrientation side2 = precaclulateSpan [ last ] . RelativeOrientation ;
351+ PointOrientation side = precalculate [ next ] . RelativeOrientation ;
352+ PointOrientation side2 = precalculate [ last ] . RelativeOrientation ;
363353
364- if ( side != side2 )
365- {
366- // differnet side we skip adding as we are passing through it
367- continue ;
368- }
354+ if ( side != side2 )
355+ {
356+ // differnet side we skip adding as we are passing through it
357+ continue ;
369358 }
370-
371- // only need to track this during odd non zero rulings
372- orientations [ position ] = precaclulateSpan [ i ] . RelativeOrientation ;
373- intersections [ position ] = point ;
374- position ++ ;
375- count -- ;
376359 }
377360
378- lastPoint = point ;
379- }
380- else
381- {
382- lastPoint = MaxVector ;
361+ // only need to track this during odd non zero rulings
362+ orientations [ position ] = precalculate [ i ] . RelativeOrientation ;
363+ intersections [ position ] = point ;
364+ position ++ ;
365+ count -- ;
383366 }
384- }
385367
386- Vector2 startVector = start ;
387- Span < float > distances = stackalloc float [ position ] ;
388- for ( int i = 0 ; i < position ; i ++ )
368+ lastPoint = point ;
369+ }
370+ else
389371 {
390- distances [ i ] = Vector2 . DistanceSquared ( startVector , intersections [ i ] ) ;
372+ lastPoint = MaxVector ;
391373 }
374+ }
392375
393- Span < PointF > activeBuffer = intersections . Slice ( 0 , position ) ;
394- Span < PointOrientation > activeOrientationsSpan = orientations . Slice ( 0 , position ) ;
395- SortUtility . Sort ( distances , activeBuffer , activeOrientationsSpan ) ;
396-
397- return position ;
376+ Vector2 startVector = start ;
377+ Span < float > distances = stackalloc float [ position ] ;
378+ for ( int i = 0 ; i < distances . Length ; i ++ )
379+ {
380+ distances [ i ] = Vector2 . DistanceSquared ( startVector , intersections [ i ] ) ;
398381 }
399- finally
382+
383+ Span < PointF > activeBuffer = intersections . Slice ( 0 , position ) ;
384+ Span < PointOrientation > activeOrientationsSpan = orientations . Slice ( 0 , position ) ;
385+ SortUtility . Sort ( distances , activeBuffer , activeOrientationsSpan ) ;
386+
387+ if ( rentedFromPool != null )
400388 {
401- if ( precaclulate != null )
402- {
403- ArrayPool < PassPointData > . Shared . Return ( precaclulate ) ;
404- }
389+ ArrayPool < PassPointData > . Shared . Return ( rentedFromPool ) ;
405390 }
391+
392+ return position ;
406393 }
407394
408395 internal static int ApplyNonZeroIntersectionRules ( Span < PointF > intersections , Span < PointOrientation > orientations )
0 commit comments