/// <summary> /// Gets the two line segments that start at the given point and terminate /// on the circle and are tangent to the circle. /// </summary> /// <param name="point">The point for the tangent segments to go through.</param> /// <remarks> /// Got strategy from Wikipedia's description involving Thale's theorem. /// http://en.wikipedia.org/wiki/Tangent_lines_to_circles /// </remarks> public LineSeg2D[] TangentsThroughPoint(Point2D point) { Circle2D intersectingCircle = default(Circle2D); Point2D[] intersects = null; if (point.DistanceTo(this.Center) <= this.Radius) { return(null); } intersectingCircle = new Circle2D(this.Center, point); intersects = this.GetIntersect(intersectingCircle); if (intersects.Length != 2) { throw new Exception("Unexpected number of intersects when getting tangents through a point."); } return(new LineSeg2D[] { new LineSeg2D(point, intersects[0]), new LineSeg2D(point, intersects[1]) }); }
/// <summary> /// Creates an arc based on another arc, but with a different radius. /// </summary> /// <param name="a">An arc from which to take the center and start/end angles.</param> /// <param name="radius">A radius for the new arc.</param> public Arc2D(Arc2D a, decimal radius) { Circle = new Circle2D(a.Center, radius); _startAngle = a._startAngle; _endAngle = a._endAngle; }
/// <summary> /// Creates an arc on the given circle with the start angle projected through /// the start point and the end angle projected through the end point. /// </summary> /// <param name="c">Circle that the arc lies on.</param> /// <param name="startPoint">Point that start angle is projected through.</param> /// <param name="endPoint">Point that end angle is projected through.</param> public Arc2D(Circle2D c, Point2D startPoint, Point2D endPoint) { this.Circle = c; _startAngle = c.AngleThroughPoint(startPoint); _endAngle = c.AngleThroughPoint(endPoint); }
/// <summary> /// Creates an arc centered on the given point with the specified radius and start/end angle. /// </summary> /// <param name="center">Center of the arc.</param> /// <param name="radius">Radius of the arc.</param> /// <param name="startAngle">Start angle.</param> /// <param name="endAngle">End angle.</param> public Arc2D(Point2D center, decimal radius, decimal startAngle, decimal endAngle) { this.Circle = new Circle2D(center, radius); _startAngle = startAngle; _endAngle = endAngle; }
/// <summary> /// Creates an arc centered at (0,0) with the given radius and start/end angle. /// </summary> /// <param name="radius">Radius of the arc.</param> /// <param name="startAngle">Start angle.</param> /// <param name="endAngle">End angle.</param> public Arc2D(decimal radius, decimal startAngle, decimal endAngle) { this.Circle = new Circle2D(0, 0, radius); _startAngle = startAngle; _endAngle = endAngle; }
/// <summary> /// Creates and arc with the given circle and start/end angle. /// </summary> /// <param name="c">The circle that the arc lies on.</param> /// <param name="startAngle">Start angle.</param> /// <param name="endAngle">End angle.</param> public Arc2D(Circle2D c, decimal startAngle, decimal endAngle) { this.Circle = c; _startAngle = startAngle; _endAngle = endAngle; }
public decimal DistanceTo(Circle2D c) { return(c.DistanceTo(this)); }
public Point2D[] GetIntersect(Circle2D c, int decimals = -1) { _CheckIsValid(); return(c.GetIntersect(this, decimals)); }
/// <summary> /// Returns circles that are tangent to another circle and line. /// </summary> /// <param name="line">Line that returned circles should be tangent to.</param> /// <param name="circle">Circle that returned circles should be tangent to.</param> /// <param name="radius">Radius of new circles.</param> /// <returns>External tangent circles are listed first.</returns> public static Circle2D[] FromTangentTangentRadius(LineSeg2D line, Circle2D circle, decimal radius) { return(FromTangentTangentRadius(circle, line, 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 }); }