public static IEnumerable <Point2D> IntersectWithLine(this Circle2D circle, BoundaryLine2D line)
        {
            var offsetToCenter = line.HalfPlane.GetOffsetFromBoundaryTowardInside(circle.Center);

            if (!(offsetToCenter.AbsoluteValue() <= circle.Radius))
            {
                return(Enumerable.Empty <Point2D>());
            }

            var intersectionOfLineWithPerpendicularRadius =
                circle.Center + line.HalfPlane.DirectionTowardInterior.ToVector(-offsetToCenter);

            var distanceFromPerpendicularRadiusToIntersectionsSquared =
                circle.Radius.Square() - offsetToCenter.Square();

            // If it's negative, the line doesn't quite intersect the circle.

            if (distanceFromPerpendicularRadiusToIntersectionsSquared > Unit.ZeroArea)
            {
                var distanceFromPerpendicularRadiusToIntersections =
                    distanceFromPerpendicularRadiusToIntersectionsSquared.SquareRoot();

                var intersectionPoints =
                    line
                    .ParallelDirections
                    .Select(direction =>
                            intersectionOfLineWithPerpendicularRadius
                            + direction.ToVector(distanceFromPerpendicularRadiusToIntersections))
                    .ToList();

                if (intersectionPoints.DistinctEquatable().Count() > 1)
                {
                    return(intersectionPoints);
                }
            }

            return(intersectionOfLineWithPerpendicularRadius.Singleton());
        }
        public static Either <Null, Point2D, Segment2D> IntersectWithDisk(this Segment2D segment, Circle2D diskBoundary)
        {
            var lineIntersectionsWithBoundary = diskBoundary.IntersectWithLine(segment.AsLine()).ToList();

            if (lineIntersectionsWithBoundary.Count == 0)
            {
                return(Null.Instance);
            }

            if (lineIntersectionsWithBoundary.Count == 1)
            {
                var point = lineIntersectionsWithBoundary.Single();
                if (segment.Contains(point))
                {
                    return(point);
                }
                return(Null.Instance);
            }

            var segmentDirection = segment.GetDirection();

            var(baseSideIntersection, endSideIntersection) =
                (lineIntersectionsWithBoundary[0], lineIntersectionsWithBoundary[1]).ReverseIf(
                    (lineIntersectionsWithBoundary[0].DirectionTo(lineIntersectionsWithBoundary[1])
                     .Value
                     .DotProduct(segmentDirection)
                    ) < 0);

            var clipBase =
                (baseSideIntersection - segment.BasePoint).GetComponentInDirection(segmentDirection)
                > Unit.ZeroDistance;
            var clipEnd =
                (endSideIntersection - segment.EndPoint).GetComponentInDirection(segmentDirection) < Unit.ZeroDistance;

            var clippedBase = clipBase ? baseSideIntersection : segment.BasePoint;
            var clippedEnd  = clipEnd ? endSideIntersection : segment.EndPoint;

            if (clippedBase == clippedEnd)
            {
                return(clipBase ? segment.EndPoint : segment.BasePoint);
            }

            var signedDistance = (clippedEnd - clippedBase).GetComponentInDirection(segmentDirection);

            if (signedDistance > Unit.ZeroDistance)
            {
                return(new Segment2D(clippedBase, clippedEnd));
            }

            return(Null.Instance);
        }
 public static IEnumerable <Point2D> IntersectWithLine(this Circle2D circle, Line2D line) =>
 circle.IntersectWithLine(line.AsBoundaryLine());