/// <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> /// <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> public Point2D[] GetIntersect(LineSeg2D l, int decimals = -1) { LineSeg2D centToLine = default(LineSeg2D); decimal centToLineLength = 0m; decimal centToLineLengthForComp = 0m; decimal radiusForComp = 0m; if (l.IsHorizontal) { // The center to any horizontal line is a vertical line through // the center of the circle. centToLine = new LineSeg2D(this.Center, this.Center + new Vector2D(0, 1)); } else { centToLine = LineSeg2D.FromPointSlope(this.Center, l.PerpendicularSlope); } centToLine.Pt2 = l.GetIntersect(centToLine, true).Value; centToLineLength = centToLine.Length; // Get numbers for comparison, rounding if necessary centToLineLengthForComp = centToLineLength; radiusForComp = _radius; if (decimals >= 0) { centToLineLengthForComp = centToLineLengthForComp.RoundFromZero(decimals); radiusForComp = radiusForComp.RoundFromZero(decimals); } // See if line is outside of circle if (centToLineLengthForComp > radiusForComp) { return(new Point2D[] { }); } // See if line is tangent to circle if (centToLineLengthForComp == radiusForComp) { return(new Point2D[] { centToLine.Pt2 }); } // Line must intersect in two places Vector2D vCentToChord = default(Vector2D); decimal halfChord = 0m; // Get a vector from the center to the intersecting chord vCentToChord = centToLine.GetVectorP1toP2(); if (vCentToChord.Magnitude == 0) { Vector2D offsetVector = default(Vector2D); // Line goes through circle center if (l.IsVertical) { // Slope undefined so just go up the length of the radius offsetVector = new Vector2D(0, _radius); } else { offsetVector = new Vector2D(_radius * DecimalEx.Cos(DecimalEx.ATan(l.Slope)), _radius * DecimalEx.Sin(DecimalEx.ATan(l.Slope))); } return(new Point2D[] { this.Center + offsetVector, this.Center - offsetVector }); } else { Vector2D vChord = default(Vector2D); // Get a vector along the chord vChord = vCentToChord.GetPerpendicular(); // Determine the length of half the chord halfChord = RightTriangle.GetSideFromSideHyp(centToLineLength, _radius); // Set the magnitude of the vector along the chord // to be half the chord length vChord.Magnitude = halfChord; // The two intersecting points are points translated // from the center of the circle to the chord (+vCentToChord) // and then translated to the ends of the chord (+-vChord) return(new Point2D[] { this.Center + vCentToChord + vChord, this.Center + vCentToChord - vChord }); } }
/// <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 }); }