/// <returns>Null (no intercepts), or array of length 1 or 2.</returns> public WPoint[] GetIntersectionPoints(WLine line) { //line does not intersect if perpendicular line from circle-center to line is longer than circle-radius WPoint perpendicularToCenter = line.GetPerpendicularIntersect(Center); if (perpendicularToCenter.Distance(Center) > Radius) { return(null); } //equation of circle with radius r and center (h, k) //is (x - h)^2 + (y - k)^2 = r^2 //line: y = mx + b //circle: (x - h)^2 + (y - k)^2 = r^2 //substitute y: (x - h)^2 + (mx + b - k)^2 = r^2 //expand: x^2 - 2hx + h^2 + m^2x^2 + 2(b - k)mx + (b - k)^2 - r^2 = 0 //group: (1 + m^2)x^2 + (-2h + 2(b - k)m)x + (h^2 + (b - k)^2 - r^2) = 0 //quadratic equation: if 0 = Ax^2 + Bx + C, then x = (-B +- sqrt(B^2 - 4AC)) / 2A double A = 1 + Math.Pow(line.Slope, 2); double B = (-2 * Center.X) + (2 * (line.YIntercept - Center.Y) * line.Slope); double C = Math.Pow(Center.X, 2) + Math.Pow(line.YIntercept - Center.Y, 2) - Math.Pow(Radius, 2); double x1 = (-1 * B + Math.Sqrt(Math.Pow(B, 2) - (4 * A * C))) / (2 * A); double x2 = (-1 * B - Math.Sqrt(Math.Pow(B, 2) - (4 * A * C))) / (2 * A); double y1 = line.Slope * x1 + line.YIntercept; double y2 = line.Slope * x2 + line.YIntercept; if (line.IsVertical) { x1 = line.A.X; x2 = line.A.X; //must use circle equation instead of line equation to find y's y1 = Center.Y + Math.Sqrt(Math.Pow(Radius, 2) - Math.Pow(x1 - Center.X, 2)); y2 = Center.Y - Math.Sqrt(Math.Pow(Radius, 2) - Math.Pow(x1 - Center.X, 2)); } if (line.IsHorizontal) { y1 = line.A.Y; y2 = line.A.Y; } WPoint point1 = new WPoint(x1, y1); WPoint point2 = new WPoint(x2, y2); List <WPoint> result = new List <WPoint>() { point1 }; if (point1 != point2) { result.Add(point2); } return(result.ToArray()); }
//todo: better names for PointOnLine and PointPastLine, they are misleading /// <summary> /// Calculates point along line AB, starting at A and moving towards B /// </summary> /// <exception cref='ArgumentException'>Point A and B cannot be the same.</exception> public static WPoint PointOnLine(WPoint a, WPoint b, double distance) { double lineLength = a.Distance(b); if (lineLength == 0) { throw new ArgumentException("Point A and B cannot be the same."); } double lengthRatio = distance / lineLength; double x = ((1d - lengthRatio) * a.X) + (lengthRatio * b.X); double y = ((1d - lengthRatio) * a.Y) + (lengthRatio * b.Y); return(new WPoint(x, y)); }
/// <summary> /// Calculates point along line AB, starting at B and moving away from A /// </summary> public static WPoint PointPastLine(WPoint a, WPoint b, double distance) { double lineLength = a.Distance(b); return(PointOnLine(a, b, lineLength + distance)); }