@@ -5689,19 +5689,27 @@ private static (T2, T) CalculateCircumCircle(int i, int j, int k, NativeArray<T2
56895689 var ( pA , pB , pC ) = ( positions [ i ] , positions [ j ] , positions [ k ] ) ;
56905690 return ( utils . CircumCenter ( pA , pB , pC ) , utils . Cast ( CircumRadiusSq ( pA , pB , pC ) ) ) ;
56915691 }
5692- private static bool ccw ( T2 a , T2 b , T2 c ) => utils . greater (
5693- utils . mul ( utils . diff ( utils . Y ( c ) , utils . Y ( a ) ) , utils . diff ( utils . X ( b ) , utils . X ( a ) ) ) ,
5694- utils . mul ( utils . diff ( utils . Y ( b ) , utils . Y ( a ) ) , utils . diff ( utils . X ( c ) , utils . X ( a ) ) )
5695- ) ;
5692+ private static int ccw ( T2 a , T2 b , T2 c ) =>
5693+ utils . greater ( Orient2dFast ( a , b , c ) , utils . EPSILON ( ) ) ? 1 :
5694+ utils . less ( Orient2dFast ( a , b , c ) , utils . neg ( utils . EPSILON ( ) ) ) ? - 1 :
5695+ 0
5696+ ;
56965697 /// <summary>
5697- /// Returns <see langword="true"/> if edge (<paramref name="a0 "/>, <paramref name="a1 "/>) intersects
5698- /// (<paramref name="b0 "/>, <paramref name="b1 "/>), <see langword="false"/> otherwise.
5698+ /// Returns <see langword="true"/> if edge (<paramref name="a "/>, <paramref name="b "/>) intersects
5699+ /// (<paramref name="c "/>, <paramref name="d "/>), <see langword="false"/> otherwise.
56995700 /// </summary>
57005701 /// <remarks>
57015702 /// This method will not catch intersecting collinear segments. See unit tests for more details.
57025703 /// Segments intersecting only at their endpoints may or may not return <see langword="true"/>, depending on their orientation.
57035704 /// </remarks>
5704- internal static bool EdgeEdgeIntersection ( T2 a0 , T2 a1 , T2 b0 , T2 b1 ) => ccw ( a0 , a1 , b0 ) != ccw ( a0 , a1 , b1 ) && ccw ( b0 , b1 , a0 ) != ccw ( b0 , b1 , a1 ) ;
5705+ // NOTE:
5706+ // The commonly used edge–edge intersection check found in the literature
5707+ // may fail when using single-precision (float2) calculations:
5708+ // ccw(a, b, c) ≠ ccw(a, b, d) ∧ ccw(c, d, a) ≠ ccw(c, d, b)
5709+ // Since we do not care about intersecting–collinear cases in this check,
5710+ // the algorithm can be implemented using imul:
5711+ // ccw(a, b, c) · ccw(a, b, d) < 0 ∧ ccw(c, d, a) · ccw(c, d, b) < 0
5712+ internal static bool EdgeEdgeIntersection ( T2 a , T2 b , T2 c , T2 d ) => ccw ( a , b , c ) * ccw ( a , b , d ) < 0 && ccw ( c , d , a ) * ccw ( c , d , b ) < 0 ;
57055713 internal static bool IsConvexQuadrilateral ( T2 a , T2 b , T2 c , T2 d ) => true
57065714 && utils . greater ( utils . abs ( Orient2dFast ( a , c , b ) ) , utils . EPSILON ( ) )
57075715 && utils . greater ( utils . abs ( Orient2dFast ( a , c , d ) ) , utils . EPSILON ( ) )
@@ -5715,7 +5723,8 @@ private static TBig Orient2dFast(T2 a, T2 b, T2 c) => utils.diff(
57155723 ) ;
57165724 internal static bool PointLineSegmentIntersection ( T2 a , T2 b0 , T2 b1 ) => true
57175725 && utils . le ( utils . abs ( Orient2dFast ( a , b0 , b1 ) ) , utils . EPSILON ( ) )
5718- && math . all ( utils . ge ( a , utils . min ( b0 , b1 ) ) & utils . le ( a , utils . max ( b0 , b1 ) ) ) ;
5726+ && math . all ( utils . ge ( a , utils . min ( b0 , b1 ) ) & utils . le ( a , utils . max ( b0 , b1 ) ) )
5727+ ;
57195728 }
57205729
57215730 /// <summary>
@@ -6155,6 +6164,7 @@ internal interface IUtils<T, T2, TBig> where T : unmanaged where T2 : unmanaged
61556164 T2 max ( T2 v , T2 w ) ;
61566165 T2 min ( T2 v , T2 w ) ;
61576166 TBig mul ( T a , T b ) ;
6167+ TBig neg ( TBig v ) ;
61586168 T2 neg ( T2 v ) ;
61596169 T2 normalizesafe ( T2 v ) ;
61606170#pragma warning restore IDE1006
@@ -6253,6 +6263,7 @@ static float pseudoAngle(float dx, float dy)
62536263 public readonly float2 max ( float2 v , float2 w ) => math . max ( v , w ) ;
62546264 public readonly float2 min ( float2 v , float2 w ) => math . min ( v , w ) ;
62556265 public readonly float mul ( float a , float b ) => a * b ;
6266+ public readonly float neg ( float v ) => - v ;
62566267 public readonly float2 neg ( float2 v ) => - v ;
62576268 public readonly float2 normalizesafe ( float2 v ) => math . normalizesafe ( v ) ;
62586269 }
@@ -6350,6 +6361,7 @@ static double pseudoAngle(double dx, double dy)
63506361 public readonly double2 max ( double2 v , double2 w ) => math . max ( v , w ) ;
63516362 public readonly double2 min ( double2 v , double2 w ) => math . min ( v , w ) ;
63526363 public readonly double mul ( double a , double b ) => a * b ;
6364+ public readonly double neg ( double v ) => - v ;
63536365 public readonly double2 neg ( double2 v ) => - v ;
63546366 public readonly double2 normalizesafe ( double2 v ) => math . normalizesafe ( v ) ;
63556367 }
@@ -6455,6 +6467,7 @@ static double pseudoAngle(int dx, int dy)
64556467 public readonly int2 max ( int2 v , int2 w ) => math . max ( v , w ) ;
64566468 public readonly int2 min ( int2 v , int2 w ) => math . min ( v , w ) ;
64576469 public readonly long mul ( int a , int b ) => ( long ) a * b ;
6470+ public readonly long neg ( long v ) => - v ;
64586471 public readonly int2 neg ( int2 v ) => - v ;
64596472 public readonly int2 normalizesafe ( int2 v ) => throw new NotImplementedException ( ) ;
64606473 }
@@ -6553,6 +6566,7 @@ static fp pseudoAngle(fp dx, fp dy)
65536566 public readonly fp2 max ( fp2 v , fp2 w ) => fpmath . max ( v , w ) ;
65546567 public readonly fp2 min ( fp2 v , fp2 w ) => fpmath . min ( v , w ) ;
65556568 public readonly fp mul ( fp a , fp b ) => a * b ;
6569+ public readonly fp neg ( fp v ) => - v ;
65566570 public readonly fp2 neg ( fp2 v ) => - v ;
65576571 public readonly fp2 normalizesafe ( fp2 v ) => fpmath . normalizesafe ( v ) ;
65586572 }
0 commit comments