/// <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 a line segment of length 1 starting at the point on the circle /// and extending either clockwise or counterclockwise. /// </summary> /// <param name="degrees">An angle.</param> public LineSeg2D TangentAt(decimal degrees, decimal length, bool clockwise) { var r = RightTriangleAbstract.FromTwoSides(_radius, length); decimal rad = DecimalEx.ToRad(degrees + r.AngleA); LineSeg2D ret = default(LineSeg2D); Debug.Assert(r.AngleA == RightTriangle.GetAngleFromSides(length, _radius)); Debug.Assert(r.Hypotenuse == RightTriangle.GetHypFromSides(length, _radius)); ret.Pt1 = PointAt(degrees); if (!clockwise) { ret.Pt2 = new Point2D(_center.X + r.Hypotenuse * DecimalEx.Cos(rad), _center.Y + r.Hypotenuse * DecimalEx.Sin(rad)); } else { ret.Pt2 = new Point2D(ret.Pt1.X - (_center.X + r.Hypotenuse * DecimalEx.Cos(rad) - ret.Pt1.X), ret.Pt1.Y - (_center.Y + r.Hypotenuse * DecimalEx.Sin(rad) - ret.Pt1.Y)); } return(ret); }
/// <summary> /// Gets hypotenuse from a known side and the angle opposite to it. /// </summary> /// <param name="side">Length of the known side.</param> /// <param name="angleOppositeToSide">Angle opposite to the known side in degrees.</param> public static decimal GetHypFromSideOppAngle(decimal side, decimal angleOppositeToSide) { // sin(a) = s / h // h = s / sin(a) return(side / DecimalEx.Sin(DecimalEx.ToRad(angleOppositeToSide))); }
/// <summary> /// Gets the coordinates of the point on the circle at the given angle. /// </summary> /// <param name="degrees">The angle in degrees.</param> public Point2D PointAt(decimal degrees) { decimal rad = DecimalEx.ToRad(degrees); return(new Point2D(_center.X + _radius * DecimalEx.Cos(rad), _center.Y + _radius * DecimalEx.Sin(rad))); }
/// <summary> /// Gets a side from the opposite angle and the length of the hypotenuse. /// </summary> /// <param name="oppositeAngle">Angle opposite to the side to calculate in degrees.</param> /// <param name="hypotenuse">Length of the hypotenuse.</param> public static decimal GetSideFromOppAngleHyp(decimal oppositeAngle, decimal hypotenuse) { // sin(oppositeAngle) = x / hypotenuse // x = hypotenuse * sin(oppositeAngle) return(hypotenuse * Convert.ToDecimal(DecimalEx.Sin(DecimalEx.ToRad(oppositeAngle)))); }