/// <summary> /// Create a circle from three points. /// </summary> /// <param name="pt1">A point.</param> /// <param name="pt2">A point.</param> /// <param name="pt3">A point.</param> public Circle2D(Point2D pt1, Point2D pt2, Point2D pt3) : this(pt1.X, pt1.Y, pt2.X, pt2.Y, pt3.X, pt3.Y) { }
/// <summary> /// Creates a new instance with the center at the given point and a radius of r. /// </summary> /// <param name="center">The center of the circle.</param> /// <param name="radius">The radius of the circle.</param> public Circle2D(Point2D center, decimal radius) { _center = center; _radius = 0m; // to satisfy compiler this.Radius = radius; }
/// <summary> /// Gets the points of intersection between this circle and the line which /// contains the given line segment. /// </summary> /// <param name="l">Line segment used to determine line equation.</param> public Point2D[] GetIntersectFast(ref LineSeg2D l) { decimal[] x = new decimal[2]; decimal m = 0m; decimal b = 0m; decimal aCoeff = 0m; decimal bCoeff = 0m; decimal cCoeff = 0m; decimal lineX = 0m; decimal t = 0m; decimal p = 0m; decimal q = 0m; Point2D[] pts = null; if (!l.IsVertical) { // Circle (x - h) ^ 2 + (y - k) ^ 2 = r ^ 2 // Center: (h, k) // Radius: r // Line y = m * x + b // (x - h) ^ 2 + (m * x + b - k) ^ 2 = r ^ 2 // (x - h) * (x - h) + (m * x + b - k) * (m * x + b - k) = r^2 // (x^2 - 2 * h * x + h^2) + (m^2 * x^2 + 2 * (b - k) * m * x + (b - k)^2 = r^2 // (m^2 + 1) * x^2 + (2 * (b - k) * m - 2 * h) * x + (h^2 + (b - k)^2 - r^2) = 0 m = l.Slope; b = l.YIntersect; aCoeff = DecimalEx.Pow(m, 2) + 1; bCoeff = 2 * (b - _center.Y) * m - 2 * _center.X; cCoeff = DecimalEx.Pow(_center.X, 2) + DecimalEx.Pow(b - _center.Y, 2) - DecimalEx.Pow(_radius, 2); x = DecimalEx.SolveQuadratic(aCoeff, bCoeff, cCoeff); if (x.Length == 0) { return new Point2D[] { } } ; pts = new Point2D[x.Length]; for (var i = 0; i <= x.Length - 1; i++) { pts[i] = new Point2D(x[i], m * x[i] + b); } } else { // Circle (x - h) ^ 2 + (y - k) ^ 2 = r ^ 2 // Center: (h, k) // Radius: r // Line x = lineX // Got the following from // http://www.sonoma.edu/users/w/wilsonst/Papers/Geometry/circles/T1--2/T1-3-2.html // http://www.sonoma.edu/users/w/wilsonst/Papers/Geometry/circles/default.html lineX = l.Pt1.X; t = _radius * _radius - (lineX - _center.X) * (lineX - _center.X); if (t < 0) { return(new Point2D[] { }); } else { p = _center.Y + DecimalEx.Sqrt(t); q = _center.Y - DecimalEx.Sqrt(t); pts = new Point2D[1]; pts[0] = new Point2D(lineX, p); // NOTE that P=Q when t=0 if (p != q) { Array.Resize(ref pts, 2); pts[1] = new Point2D(lineX, q); } } } return(pts); }
/// <summary> /// Returns distance to the given point from the circle. If the /// point is on the circle, distance is 0. If the point is inside /// the circle, the distance is expressed as a negative number /// whose absolute value is the distance from the outside of the circle. /// </summary> /// <param name="pt">The point to get distance to.</param> public decimal DistanceTo(Point2D pt) { return(Center.DistanceTo(pt) - Radius); }
/// <summary> /// Creates a new instance with the center at (x, y) and a radius of r. /// </summary> /// <param name="x">The X component of the center.</param> /// <param name="y">The Y component of the center.</param> /// <param name="radius">The radius of the circle.</param> public Circle2D(decimal x, decimal y, decimal radius) { _center = new Point2D(x, y); _radius = 0m; // to satisfy compiler this.Radius = radius; }
public static Circle2D[] FromTwoPointsAndRadius(Point2D pt1, Point2D pt2, decimal radius) { return(FromTwoPointsAndRadius(pt1.X, pt1.Y, pt2.X, pt2.Y, radius)); }
/// <summary> /// Creates a new instance with the center at the origin with the provided radius. /// </summary> /// <param name="radius">The radius of the circle.</param> public Circle2D(decimal radius) { _center = Point2D.Origin; _radius = 0m; // to satisfy compiler this.Radius = radius; }
/// <summary> /// Gets the points of intersection between this circle and another circle. /// </summary> /// <param name="other">The other circle.</param> /// <param name="decimals">Determines rounding that should be performed when determining /// if line intersection happens on zero, one, or two points. Default is -1 for /// no rounding.</param> /// <param name="impreciseResult">Which value to return for an imprecise result, /// i.e. tangency determined by rounding. If positive, returns the point on the larger circle. If /// negative, returns the point on the smaller circle. If 0, returns the midpoint between these /// two points.</param> public Point2D[] GetIntersect(Circle2D other, int decimals = -1, int impreciseResult = 0) { Vector2D meToOtherVector = default(Vector2D); meToOtherVector = this.Center.GetVectorTo(other.Center); if (decimals >= 0) { // The only intersection decision that can be made to a given precision is whether // the two circles are tangent to each other, either internally or externally. if (this.IsTangentTo(other, decimals)) { // If the smaller circle is inside the other, then the smaller is // considered internally tangent to the larger. if ((this.Radius < other.Radius && this.IsInside(other, decimals)) || (other.Radius < this.Radius && other.IsInside(this, decimals))) { // Internal tangent Point2D pointOnLargeCircle = default(Point2D); Point2D pointOnSmallCircle = default(Point2D); // Vectors to the two tangent points are both pointing in the same // direction--from the center of the larger circle towards the // center of the smaller circle. Their magnitude is the same as the // radius of the circle whose center they start from. if (this.Radius > other.Radius) { // Go from center of larger circle, Me, to smaller circle, other. pointOnLargeCircle = this.Center + new Vector2D(meToOtherVector, this.Radius); pointOnSmallCircle = other.Center + new Vector2D(meToOtherVector, other.Radius); } else { // Go from center of larger circle, other, to smaller circle, Me. pointOnLargeCircle = other.Center - new Vector2D(meToOtherVector, other.Radius); pointOnSmallCircle = this.Center - new Vector2D(meToOtherVector, this.Radius); } if (impreciseResult > 0) { // Point on larger return(new Point2D[] { pointOnLargeCircle }); } else if (impreciseResult < 0) { // Point on smaller return(new Point2D[] { pointOnSmallCircle }); } else { // Split difference LineSeg2D l = new LineSeg2D(pointOnLargeCircle, pointOnSmallCircle); return(new Point2D[] { l.MidPoint }); } } else { // External tangent Point2D pointOnMe = default(Point2D); Point2D pointOnOther = default(Point2D); // Vectors to the two tangent points are simply pointing at the other // circle's center with a magnitude of the radius of the circle whose // center it originates in. pointOnMe = this.Center + new Vector2D(meToOtherVector, this.Radius); pointOnOther = other.Center - new Vector2D(meToOtherVector, other.Radius); if (impreciseResult > 0) { // Point on larger return(new Point2D[] { (this.Radius > other.Radius ? pointOnMe : pointOnOther) }); } else if (impreciseResult < 0) { // Point on smaller return(new Point2D[] { (this.Radius < other.Radius ? pointOnMe : pointOnOther) }); } else { if (pointOnMe == pointOnOther) { return(new Point2D[] { pointOnMe }); } else { // Split difference return(new Point2D[] { new LineSeg2D(pointOnMe, pointOnOther).MidPoint }); } } } } } // Detect situations where two points touch decimal a = 0m; decimal h = 0m; decimal r2mina2 = 0m; Vector2D vToIntersectMidPt = default(Vector2D); Vector2D vToIntersect1 = default(Vector2D); // The following two equations are from: // http://paulbourke.net/geometry/2circle/ a = (DecimalEx.Pow(meToOtherVector.Magnitude, 2) - DecimalEx.Pow(other.Radius, 2) + DecimalEx.Pow(this.Radius, 2)) / (2 * meToOtherVector.Magnitude); r2mina2 = DecimalEx.Pow(this.Radius, 2) - DecimalEx.Pow(a, 2); // No intersection points -- one circle is inside or outside the other if (r2mina2 < 0) { return new Point2D[] { } } ; vToIntersectMidPt = new Vector2D(this.Center, other.Center); vToIntersectMidPt.Magnitude = a; if (r2mina2 == 0) { // Only one intersection point return(new Point2D[] { this.Center + vToIntersectMidPt }); } h = DecimalEx.Sqrt(r2mina2); vToIntersect1 = vToIntersectMidPt.GetPerpendicular(); vToIntersect1.Magnitude = h; return(new Point2D[] { this.Center + vToIntersectMidPt + vToIntersect1, this.Center + vToIntersectMidPt - vToIntersect1 }); }