Skip to content

Instantly share code, notes, and snippets.

@villares
Last active October 22, 2020 19:34
Show Gist options
  • Save villares/af485db805881af5964063587dfe8a0f to your computer and use it in GitHub Desktop.
Save villares/af485db805881af5964063587dfe8a0f to your computer and use it in GitHub Desktop.
FreyaHolmer's Mathfs ported to Processing Java!
// https://twitter.com/FreyaHolmer/status/1319278214087258112?s=20
// FROM: https://github.com/FreyaHolmer/Mathfs/
/*
TODO: YEAH INTERSECT IT IS HARD... IF ANYONE WANTS TO HELP...!
- CircleFromThreePoints() depends on LineSegment2D and Intersect...
- I have some lazy line segment intersection I could use
but Freya's has cool Rays and infinite lines...
- ...
- Then I'll port everything to Processing Python mode...
*/
class Circle {
PVector center;
float radius;
Circle( PVector center, float radius ) {
this.center = center;
this.radius = radius;
}
Circle(float x, float y, float radius) {
this.center = new PVector(x, y);
this.radius = radius;
}
void draw() {
circle(center.x, center.y, radius * 2);
}
float Area() {
return RadiusToArea(radius);
}
float Circumference() {
return RadiusToCircumference( radius );
}
float RadiusToArea( float r ) {
return r * r * ( 0.5f * TAU );
}
float AreaToRadius( float area ) {
return sqrt( 2 * area / TAU );
}
float AreaToCircumference( float area ) {
return sqrt( 2 * area / TAU ) * TAU;
}
float CircumferenceToArea( float c ) {
return c * c / ( 2 * TAU );
}
float RadiusToCircumference( float r ) {
return r * TAU;
}
float CircumferenceToRadius( float c ) {
return c / TAU;
}
}
//Circle CircleFromThreePoints( PVector a, PVector b, PVector c) {
// Line2D lineA = LineSegment2D.GetBisectorFast( a, b );
// Line2D lineB = LineSegment2D.GetBisectorFast( b, c );
// PVector center = Intersect.Lines( lineA, lineB);
// if (center != null) {
// return new Circle(center, PVector.dist(center, a );
// );
// }
// return null;
//}
Circle CircleFromTwoPoints( PVector a, PVector b ) {
return new Circle(PVector.add(a, b).div(2.0), PVector.dist( a, b ) / 2.0);
}
Circle CircleFromTwoPoints(float xa, float ya, float xb, float yb ) {
return CircleFromTwoPoints( new PVector(xa, ya), new PVector(xb, yb));
}
// 2D line math
class Line2D {
PVector origin;
PVector dir;
Line2D( PVector origin, PVector dir ) {
this.origin = origin;
this.dir = dir;
}
PVector GetPoint( float t ) {
return origin.add(dir.mult(t));
}
/// Projects a point onto an infinite line
/// "lineOrigin">Line origin
/// "lineDir">Line direction (does not have to be normalized)
/// "point">The point to project onto the line
PVector ProjectPointToLine( PVector lineOrigin, PVector lineDir, PVector point ) {
PVector coord = point.sub(lineOrigin);
float t = PVector.dot( lineDir, coord ) / PVector.dot( lineDir, lineDir );
return lineOrigin.add(lineDir.mult(t));
}
/// Projects a point onto an infinite line
/// "line">Line to project onto
/// "point">The point to project onto the line
PVector ProjectPointToLine( Line2D line, PVector point ) {
return ProjectPointToLine( line.origin, line.dir, point );
}
/// Returns the signed distance to a 2D plane
/// "planeOrigin">Plane origin
/// "planeNormal">Plane normal (has to be normalized for a true distance)
/// "point">The point to use when checking distance to the plane
float PointToPlaneSignedDistance( PVector planeOrigin, PVector planeNormal, PVector point ) {
return PVector.dot( point.sub(planeOrigin), planeNormal );
}
/// Returns the distance to a 2D plane
/// "planeOrigin">Plane origin
/// "planeNormal">Plane normal (has to be normalized for a true distance)
/// "point">The point to use when checking distance to the plane
float PointToPlaneDistance( PVector planeOrigin, PVector planeNormal, PVector point ) {
return abs( PointToPlaneSignedDistance( planeOrigin, planeNormal, point ) );
}
}
void setup(){
size(400, 400);
Circle c0 = new Circle(100, 100, 100);
c0.draw();
// Circle c1 = CircleFromTwoPoints(new PVector(100, 100), new PVector(200, 200));
Circle c1 = CircleFromTwoPoints(100, 100, 200, 200);
c1.draw();
}
@villares
Copy link
Author

image

@villares
Copy link
Author

Work in progres... In Java I don't have "out" parameters (reminds me of VAR in Pascal!).
Vector2 -> PVector
I'm going with null (non-intersecting) or PVector (intersection), I guess.

// static class Intersect {

  // These are used to see if an intersection t-value is valid for rays and line segments
  // If you want make on-vertex intersections not count, you can tweak that here by changing comparisons
  // You can also add margin here if you want to technically count slightly outside/inside as an intersection or not
  // (Note that Line isn't range bound, so it's not here. It's always true)
  static boolean BoundsTestRay( float t ) { 
    return  t >= 0;
  }
  static boolean BoundsTestLineSegment( float t ) { 
    return  t >= 0 && t <= 1;
  }


  // internal
  static PVector GetLineLineTValues( PVector aToB, PVector aDir, PVector bDir) {
    float d = Determinant( aDir, bDir );
    if ( Abs( d ) < PARALLEL_DETERMINANT_THRESHOLD ) {
      return null;
    }

    tA = Determinant( aToB, bDir ) / d;
    tB = Determinant( aToB, aDir ) / d;
    return new PVector(tA, tB);
  }

  // Naming order: Ray, LineSegment, Line, Circle

  //#region Rays

  /// Returns whether or not two rays intersect
  public static PVector Rays( Ray2D a, Ray2D b ) { 
    PVector t = GetLineLineTValues( PVector.sub(b.origin, a.origin), a.dir, b.dir ) 
      if (t !=null && BoundsTestRay( t.x ) && BoundsTestRay( t.y )) { 
      return PVector.add(aOrigin, PVector.mult(Dir, t.x));
    } else {
      return null;
    }
  }

  ///// Returns whether or not two rays intersect (PVector or null)
  public static PVector Rays( PVector aOrigin, PVector aDir, PVector bOrigin, PVector bDir ) { 
    PVector t = GetLineLineTValues(PVector.sub(b.origin, a.origin), aDir, bDir);
    if (t != null && BoundsTestRay( t.x ) && BoundsTestRay( t.y ) {
      return PVector.add(aOrigin, PVector.mult(Dir, t.x));
    } else {
      return null;
    }
  }

  ///// Returns the intersection point of two rays (if there is one)
  ///// "intersectionPoint">The point at which they intersect
  public static PVector Rays( Ray2D a, Ray2D b) { 
    return  Rays( a.origin, a.dir, b.origin, b.dir);
  }



  //#endregion

  //#region Ray-LineSegment

  /// Returns whether or not a ray and a line segment intersect
  public static boolean RayLineSegment( Ray2D ray, LineSegment2D lineSegment ) { 
    return  RayLineSegment( ray.origin, ray.dir, lineSegment.start, lineSegment.end );
  }

  /// Returns whether or not a ray and a line segment intersect
  public static boolean RayLineSegment( PVector rayOrigin, PVector rayDir, PVector lineSegStart, PVector lineSegEnd ) { 
    return  GetLineLineTValues( lineSegStart - rayOrigin, rayDir, lineSegEnd, out float tA, out float tB ) && BoundsTestRay( tA ) && BoundsTestLineSegment( tB );
  }

  /// Returns the intersection point of a ray and a line segment (if there is one)
  /// "intersectionPoint">The point at which they intersect
  public static boolean RayLineSegment( PVector rayOrigin, PVector rayDir, PVector lineSegStart, PVector lineSegEnd, out PVector intersectionPoint ) {
    if ( GetLineLineTValues( lineSegStart - rayOrigin, rayDir, lineSegEnd - lineSegStart, out float tA, out float tB ) && BoundsTestRay( tA ) && BoundsTestLineSegment( tB ) ) {
      intersectionPoint = rayOrigin + rayDir * tA;
      return true;
    }

    intersectionPoint = default;
    return false;
  }

  /// Returns the intersection point of a ray and a line segment (if there is one)
  /// "intersectionPoint">The point at which they intersect
  public static boolean RayLineSegment( Ray2D ray, LineSegment2D lineSegment, out PVector intersectionPoint ) { 
    return  RayLineSegment( ray.origin, ray.dir, lineSegment.start, lineSegment.end, out intersectionPoint );
  }

  //#endregion

  //#region Ray-Line

  /// Returns whether or not a ray and a line intersect
  public static boolean RayLine( Ray2D ray, Line2D line ) { 
    return  RayLine( ray.origin, ray.dir, line.origin, line.dir );
  }
  /// Returns whether or not a ray and a line intersect
  public static boolean RayLine( PVector rayOrigin, PVector rayDir, PVector lineOrigin, PVector lineDir ) { 
    return  GetLineLineTValue( lineOrigin - rayOrigin, rayDir, lineDir, out float tA ) && BoundsTestRay( tA );
  }

  /// Returns the intersection point of a ray and an infinite line (if there is one)
  /// "intersectionPoint">The point at which they intersect
  public static boolean RayLine( PVector rayOrigin, PVector rayDir, PVector lineOrigin, PVector lineDir, out PVector intersectionPoint ) {
    if ( GetLineLineTValue( lineOrigin - rayOrigin, rayDir, lineDir, out float tA ) && BoundsTestRay( tA ) ) {
      intersectionPoint = rayOrigin + rayDir * tA;
      return true;
    }

    intersectionPoint = default;
    return false;
  }

  /// Returns the intersection point of a ray and an infinite line (if there is one)
  /// "intersectionPoint">The point at which they intersect
  public static boolean RayLine( Ray2D ray, Line2D line, out PVector intersectionPoint ) { 
    return  RayLine( ray.origin, ray.dir, line.origin, line.dir, out intersectionPoint );
  }

  //#endregion

  //#region Ray-Circle

  ///// Returns the number of intersections and the points at which a ray and a circle intersect (if they exist)
  //public static int RayCircle( PVector rayOrigin, PVector rayDir, PVector circleCenter, float circleRadius, out PVector intsctPtA, out PVector intsctPtB ) { 
  //  return  GetLineCircleIntersectionPointsFiltered( rayOrigin, rayDir, circleCenter, circleRadius, t { 
  //    return  BoundsTestRay( t ), out intsctPtA, out intsctPtB );
  //  }

  //  /// Returns the number of intersections and the points at which a ray and a circle intersect (if they exist)
  //  public static int RayCircle( Ray2D ray, Circle circle, out PVector intsctPtA, out PVector intsctPtB ) { 
  //    return  GetLineCircleIntersectionPointsFiltered( ray.origin, ray.dir, circle.center, circle.radius, t { 
  //      return  BoundsTestRay( t ), out intsctPtA, out intsctPtB );
  //    }

  //    /// Returns the number of intersection points between ray and a circle
  //    public static int RayCircle( PVector rayOrigin, PVector rayDir, PVector circleCenter, float circleRadius ) { 
  //      return  GetLineCircleIntersectionCountFiltered( rayOrigin, rayDir, circleCenter, circleRadius, t { 
  //        return  BoundsTestRay( t ) );
  //      }

  //      /// Returns the number of intersection points between ray and a circle
  //      public static int RayCircle( Ray2D ray, Circle circle ) { 
  //        return  GetLineCircleIntersectionCountFiltered( ray.origin, ray.dir, circle.center, circle.radius, t { 
  //          return  BoundsTestRay( t ) );
  //        }

  //#endregion

  //#region LineSegments

  /// Returns the intersection point of two line segments (if there is one)
  /// "aStart">Line segment A start
  /// "aEnd">Line segment A end
  /// "bStart">Line segment B start
  /// "bEnd">Line segment B end
  /// "intersectionPoint">The point at which they intersect
  public static boolean LineSegments( PVector aStart, PVector aEnd, PVector bStart, PVector bEnd, out PVector intersectionPoint ) {
    PVector aDir = aEnd - aStart;
    PVector bDir = bEnd - bStart;
    PVector aToB = bStart - aStart;
    if ( GetLineLineTValues( aToB, aDir, bDir, out float tA, out float tB ) && BoundsTestLineSegment( tA ) && BoundsTestLineSegment( tB ) ) {
      intersectionPoint = aStart + tA * aDir;
      return true;
    }

    intersectionPoint = default;
    return false;
  }

  /// Returns the intersection point of two line segments (if there is one)
  /// "intersectionPoint">The point at which they intersect
  public static boolean LineSegments( LineSegment2D a, LineSegment2D b, out PVector intersectionPoint ) { 
    return  LineSegments( a.start, a.end, b.start, b.end, out intersectionPoint );
  }

  /// Returns whether or not two line segments intersect
  /// "aStart">Line segment A start
  /// "aEnd">Line segment A end
  /// "bStart">Line segment B start
  /// "bEnd">Line segment B end
  public static boolean LineSegments( PVector aStart, PVector aEnd, PVector bStart, PVector bEnd ) { 
    return  GetLineLineTValues( bStart - aStart, aEnd - aStart, bEnd - bStart, out float tA, out float tB ) && BoundsTestLineSegment( tA ) && BoundsTestLineSegment( tB );
  }

  /// Returns whether or not two line segments intersect
  public static boolean LineSegments( LineSegment2D a, LineSegment2D b ) { 
    return  LineSegments( a.start, a.end, b.start, b.end );
  }

  //#endregion

  //#region LineSegment-Line

  /// Returns the intersection point of a line segment and a line (if there is one)
  /// "lineSegStart">Line segment start
  /// "lineSegEnd">Line segment end
  /// "lineOrigin">Line start
  /// "lineDir">Line direction (does not have to be normalized)
  /// "intersectionPoint">The point at which they intersect
  public static boolean LineSegmentLine( PVector lineSegStart, PVector lineSegEnd, PVector lineOrigin, PVector lineDir, out PVector intersectionPoint ) {
    PVector aDir = lineSegEnd - lineSegStart;
    PVector aToB = lineOrigin - lineSegStart;

    if ( GetLineLineTValue( aToB, aDir, lineDir, out float tA ) && BoundsTestLineSegment( tA ) ) {
      intersectionPoint = lineSegStart + tA * aDir;
      return true;
    }

    intersectionPoint = default;
    return false;
  }

  /// Returns the intersection point of a line segment and a line (if there is one)
  /// "intersectionPoint">The point at which they intersect
  public static boolean LineSegmentLine( LineSegment2D lineSegment, Line2D line, out PVector intersectionPoint ) { 
    return  LineSegmentLine( lineSegment.start, lineSegment.end, line.origin, line.dir, out intersectionPoint );
  }

  /// Returns whether or not a line segment and a line intersect
  /// "lineSegStart">Line segment start
  /// "lineSegEnd">Line segment end
  /// "lineOrigin">Line start
  /// "lineDir">Line direction (does not have to be normalized)
  public static boolean LineSegmentLine( PVector lineSegStart, PVector lineSegEnd, PVector lineOrigin, PVector lineDir ) { 
    return  GetLineLineTValue( lineOrigin - lineSegStart, lineSegEnd - lineSegStart, lineDir, out float tA ) && BoundsTestLineSegment( tA );
  }

  /// Returns whether or not a line segment and a line intersect
  public static boolean LineSegmentLine( LineSegment2D lineSegment, Line2D line ) { 
    return  GetLineLineTValue( line.origin - lineSegment.start, lineSegment.end - lineSegment.start, line.dir, out float tA ) && BoundsTestLineSegment( tA );
  }

  //#endregion

  //#region LineSegment-Circle

  /// Returns the number of intersections and the points at which a line segment and a circle intersect (if they exist)
  public static int LineSegmentCircle( PVector lineStart, PVector lineEnd, PVector circleCenter, float circleRadius, out PVector intsctPtA, out PVector intsctPtB ) { 
    return  GetLineCircleIntersectionPointsFiltered( lineStart, lineEnd - lineStart, circleCenter, circleRadius, t { 
      return  BoundsTestLineSegment( t ), out intsctPtA, out intsctPtB );
    }

    /// Returns the number of intersections and the points at which a line segment and a circle intersect (if they exist)
    public static int LineSegmentCircle( LineSegment2D lineSegment, Circle circle, out PVector intsctPtA, out PVector intsctPtB ) { 
      return  GetLineCircleIntersectionPointsFiltered( lineSegment.start, lineSegment.end - lineSegment.start, circle.center, circle.radius, t { 
        return  BoundsTestLineSegment( t ), out intsctPtA, out intsctPtB );
      }

      /// Returns the number of intersection points between line segment and a circle
      public static int LineSegmentCircle( PVector lineStart, PVector lineEnd, PVector circleCenter, float circleRadius ) { 
        return  GetLineCircleIntersectionCountFiltered( lineStart, lineEnd - lineStart, circleCenter, circleRadius, t { 
          return  BoundsTestLineSegment( t ) );
        }

        /// Returns the number of intersection points between line segment and a circle
        public static int LineSegmentCircle( LineSegment2D lineSegment, Circle circle ) { 
          return  GetLineCircleIntersectionCountFiltered( lineSegment.start, lineSegment.end - lineSegment.start, circle.center, circle.radius, t { 
            return  BoundsTestLineSegment( t ) );

            //#endregion

            //#region Lines

            /// Returns the intersection point of two infinite lines (if there is one)
            /// "aOrigin">Line A origin
            /// "aDir">Line A direction (does not have to be normalized)
            /// "bOrigin">Line B origin
            /// "bDir">Line B direction (does not have to be normalized)
            /// "intersectionPoint">The point at which they intersect
            public static boolean Lines( PVector aOrigin, PVector aDir, PVector bOrigin, PVector bDir, out PVector intersectionPoint ) {
              PVector aToB = bOrigin - aOrigin;
              if ( GetLineLineTValue( aToB, aDir, bDir, out float tA ) ) {
                intersectionPoint = aOrigin + tA * aDir;
                return true;
              }

              intersectionPoint = default;
              return false;
            }

            /// Returns the intersection point of two infinite lines (if there is one)
            /// "intersectionPoint">The point at which they intersect
            public static boolean Lines( Line2D a, Line2D b, out PVector intersectionPoint ) { 
              return  Lines( a.origin, a.dir, b.origin, b.dir, out intersectionPoint );

              //#endregion

              //#region Line-Circle

              /// Returns the points at which an infinite line and a circle intersect (if they exist)
              public static boolean LineCircle( PVector lineStart, PVector lineDir, PVector circleCenter, float circleRadius, out PVector intsctPtA, out PVector intsctPtB ) { 
                return  GetLineCircleIntersectionPointsUnfiltered( lineStart, lineDir, circleCenter, circleRadius, out intsctPtA, out intsctPtB ) > 0;

                /// Returns the points at which an infinite line and a circle intersect (if they exist)
                public static boolean LineCircle( Line2D line, Circle circle, out PVector intsctPtA, out PVector intsctPtB ) { 
                  return  GetLineCircleIntersectionPointsUnfiltered( line.origin, line.dir, circle.center, circle.radius, out intsctPtA, out intsctPtB ) > 0;

                  /// Returns whether or not an infinite line and a circle intersect
                  public static boolean LineCircle( PVector lineStart, PVector lineDir, PVector circleCenter, float circleRadius ) { 
                    return  GetLineCircleIntersectionState( lineStart, lineDir, circleCenter, circleRadius );

                    /// Returns whether or not an infinite line and a circle intersect
                    public static boolean LineCircle( Line2D line, Circle circle ) { 
                      return  GetLineCircleIntersectionState( line.origin, line.dir, circle.center, circle.radius );
                    }

                    //#endregion

                    /// Returns the two intersection points of two circles (if they exist)
                    /// "intsctPtA">The first intersection point
                    /// "intsctPtB">The second intersection point
                    public static boolean Circles( Circle a, Circle b, out PVector intsctPtA, out PVector intsctPtB ) {
                      float distSq = DistanceSquared( a.center, b.center );
                      float dist = Sqrt( distSq );
                      boolean differentPosition = dist > 0.00001f;
                      float maxRad = Max( a.radius, b.radius );
                      float minRad = Min( a.radius, b.radius );
                      boolean ringsTouching = Mathf.Abs( dist - maxRad ) < minRad;

                      if ( ringsTouching && differentPosition ) {
                        float aRadSq = a.radius.Square();
                        float bRadSq = b.radius.Square();
                        float lateralOffset = ( distSq - bRadSq + aRadSq ) / ( 2 * dist );
                        float normalOffset = ( 0.5f / dist ) * Sqrt( 4 * distSq * aRadSq - ( distSq - bRadSq + aRadSq ).Square() );
                        PVector tangent = ( b.center - a.center ) / dist;
                        PVector normal = tangent.Rotate90CCW();
                        PVector chordCenter = a.center + tangent * lateralOffset;
                        intsctPtA = chordCenter + normal * normalOffset;
                        intsctPtB = chordCenter - normal * normalOffset;
                        return true;
                      }

                      intsctPtA = intsctPtB = default;
                      return false;
                    }

                    /// Returns whether or not two discs overlap
                    public static boolean Discs( Circle a, Circle b ) { 
                      return  DistanceSquared( a.center, b.center ) <= ( a.radius + b.radius ).Square();

                      /// Returns whether or not two circles overlap
                      public static boolean Circles( Circle a, Circle b ) {
                        float dist = PVector.dist( a.center, b.center );
                        float maxRad = Max( a.radius, b.radius );
                        float minRad = Min( a.radius, b.radius );
                        return Mathf.Abs( dist - maxRad ) < minRad;
                      }


                      // internal
                      const float PARALLEL_DETERMINANT_THRESHOLD = 0.00001f;
                      static boolean Parallel( PVector aDir, PVector bDir ) { 
                        return  Abs( Determinant( aDir, bDir ) ) < PARALLEL_DETERMINANT_THRESHOLD;
                      }



                      // internal, based on https://stackoverflow.com/questions/1073336/circle-line-segment-collision-detection-algorithm
                      static void GetLineCircleIntersectionValues( PVector aOrigin, PVector aDir, PVector circleCenter, float radius, out float a, out float b, out float discriminant ) {
                        PVector circleToLineOrigin = aOrigin - circleCenter;
                        a = PVector.Dot( aDir, aDir ); // ray len sq
                        b = 2 * PVector.Dot( circleToLineOrigin, aDir );
                        float c = PVector.Dot( circleToLineOrigin, circleToLineOrigin ) - radius.Square();
                        discriminant = b * b - 4 * a * c;
                      }

                      // internal
                      static boolean GetLineCircleTValues( PVector aOrigin, PVector aDir, PVector circleCenter, float radius, out float tA, out float tB ) {
                        GetLineCircleIntersectionValues( aOrigin, aDir, circleCenter, radius, out float a, out float b, out float discriminant );
                        if ( discriminant > 0 ) {
                          discriminant = Mathf.Sqrt( discriminant );
                          tA = ( -b + discriminant ) / ( 2 * a );
                          tB = ( -b - discriminant ) / ( 2 * a );
                          return true;
                        } else {
                          tA = tB = 0f;
                          return false;
                        }
                      }

                      // internal, only useful for the Line-Circle since it doesn't check T values
                      static boolean GetLineCircleIntersectionState( PVector aOrigin, PVector aDir, PVector circleCenter, float radius ) {
                        GetLineCircleIntersectionValues( aOrigin, aDir, circleCenter, radius, out float _, out float _, out float discriminant );
                        return discriminant > 0;
                      }

                      // internal
                      static int GetLineCircleIntersectionCountFiltered( PVector aOrigin, PVector aDir, PVector cCenter, float r, Func<float, bool> InValidRange ) {
                        int pCount = 0;

                        if ( GetLineCircleTValues( aOrigin, aDir, cCenter, r, out float tA, out float tB ) ) {
                          if ( InValidRange( tA ) ) pCount++;
                          if ( InValidRange( tB ) ) pCount++;
                        }

                        return pCount;
                      }

                      // internal
                      static int GetLineCircleIntersectionPointsFiltered( PVector aOrigin, PVector aDir, PVector cCenter, float r, Func<float, bool> InValidRange, out PVector pA, out PVector pB ) {
                        int pCount = 0;

                        void Check( float t, out PVector p ) {
                          if ( InValidRange( t ) ) {
                            p = aOrigin + aDir * t;
                            pCount++;
                          } else p = default;
                        }

                        if ( GetLineCircleTValues( aOrigin, aDir, cCenter, r, out float tA, out float tB ) ) {
                          Check( tA, out pA );
                          Check( tB, out pB );
                        } else {
                          pA = pB = default;
                        }

                        return pCount;
                      }

                      // internal
                      static int GetLineCircleIntersectionPointsUnfiltered( PVector aOrigin, PVector aDir, PVector cCenter, float r, out PVector pA, out PVector pB ) {
                        if ( GetLineCircleTValues( aOrigin, aDir, cCenter, r, out float tA, out float tB ) ) {
                          pA = aOrigin + aDir * tA;
                          pB = aOrigin + aDir * tB;
                          return 2;
                        }

                        pA = pB = default;
                        return 0;
                      }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment