Given the bounding box, the starting angle, and the sweep angle, how to determine the points of the arc endpoints

Given the bounding box, the starting angle, and the sweep angle, how do I determine the points of each end of the arc?

private void myPaint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; Rectangle rc = new Rectangle(242, 299, 200, 300); Pen penRed = new Pen(Color.Red, 1); g.DrawArc(penRed, rc, 18, -108); // TODO - Determine Point of each end of arc // Point pt1 = ??? // Point pt2 = ??? } 

enter image description here

+1
c # wpf trigonometry
source share
1 answer

Using the equation of the ellipse from this excellent Mathematical answer We can calculate the start and end points of your ellipse, given the starting angle and the scan.

First, we need the center of the bounding box, so we know how to move the coordinates. It's simple

 Rectangle rc = new Rectangle(242, 299, 200, 300); int cX = (rc.Left + rc.Right) / 2; int cY = (rc.Bottom + rc.Top) / 2; // For debugging purposes, let mark that point. g.FillRectangle(Brushes.Yellow, Rectangle.FromLTRB(cX - 3, cY - 3, cX + 3, cY + 3)); 

Then we need to convert the angles from degrees to radians and change the angle clockwise to the angle counterclockwise like this:

 double minTheta = (Math.PI / 180) * (360 - start); double maxTheta = (Math.PI / 180) * (360 - (start + sweep)); 

We will also define 2 auxiliary functions, the first to normalize the angle (randomly display the angles in the range 0-360), and the second to correct the calculated (x, y) coordinates in the correct quadrant. (Given that positive y is actually omitted in form)

 public double NormalizeAngle(double angle) { while (angle >= 360) angle -= 360; while (angle < 0) angle += 360; return angle; } public void AdjustCoordinatesForAngle(double angle, ref double x, ref double y) { if (angle > 0 && angle <= 90) { x *= 1; y *= 1; } else if (angle >= 90 && angle < 180) { x *= -1; y *= 1; } else if (angle >= 180 && angle < 270) { x *= -1; y *= -1; } else if (angle >= 270 && angle < 360) { x *= 1; y *= -1; } } 

Now we have enough information to calculate the starting and ending points.

 double minTheta = (Math.PI / 180) * (360 - start); double maxTheta = (Math.PI / 180) * (360 - (start + sweep)); double a = width / 2.0; double b = height / 2.0; double denom = Math.Pow(a, 2) * Math.Pow(Math.Tan(minTheta), 2); denom = denom / Math.Pow(b, 2); denom = Math.Sqrt(denom + 1); double x = Math.Abs(a / denom); double y = Math.Abs((a * Math.Tan(minTheta)) / denom); start = NormalizeAngle(start); this.AdjustCoordinatesForAngle(start, ref x, ref y); 

These coordinates are relative to the center of the bounding box, so we offset it using the center point calculated above:

 x += cX; y += cY; 

Now we can draw a point:

 g.FillRectangle(Brushes.Purple, new Rectangle((int)x - 3, (int)y - 3, 6, 6)); 

All together, the paint function is as follows:

 private void myPaint(object sender, PaintEventArgs e) { double start = 18; double sweep = -108; Graphics g = e.Graphics; g.Clear(Color.Black); Rectangle rc = new Rectangle(200, 10, 200, 300); int cX = (rc.Left + rc.Right) / 2; int cY = (rc.Bottom + rc.Top) / 2; g.FillRectangle(Brushes.Yellow, Rectangle.FromLTRB(cX - 3, cY - 3, cX + 3, cY + 3)); int width = rc.Width; int height = rc.Height; if (start >= 360) start -= 360; double minTheta = (Math.PI / 180) * (360 - start); double maxTheta = (Math.PI / 180) * (360 - (start + sweep)); double a = width / 2.0; double b = height / 2.0; double denom = Math.Pow(a, 2) * Math.Pow(Math.Tan(minTheta), 2); denom = denom / Math.Pow(b, 2); denom = Math.Sqrt(denom + 1); double x = Math.Abs(a / denom); double y = Math.Abs((a * Math.Tan(minTheta)) / denom); start = NormalizeAngle(start); this.AdjustCoordinatesForAngle(start, ref x, ref y); x += cX; y += cY; g.FillRectangle(Brushes.Purple, new Rectangle((int)x - 3, (int)y - 3, 6, 6)); denom = Math.Pow(a, 2) * Math.Pow(Math.Tan(maxTheta), 2); denom = denom / Math.Pow(b, 2); denom = Math.Sqrt(denom + 1); x = Math.Abs(a / denom); y = Math.Abs((a * Math.Tan(maxTheta)) / denom); double endAngle = (start + sweep); endAngle = NormalizeAngle(endAngle); this.AdjustCoordinatesForAngle(endAngle, ref x, ref y); x += cX; y += cY; g.FillRectangle(Brushes.Blue, new Rectangle((int)x - 3, (int)y - 3, 6, 6)); Pen penRed = new Pen(Color.Red, 1); g.DrawRectangle(Pens.Green, rc); g.DrawArc(penRed, rc, (float)start, (float)sweep); } 

I drew the black background of the window to make the windows and lines stand out better, and I went into some additional elements of the drawing, so it’s easier to see what happens in the calculations above.

Placing the code on the form, and associating it with the paint event of the form produces the following result:

Final result

Finally, due to rounding, the start and end points can be disabled by a pixel or two. If you want more accuracy, you will have to draw the arc yourself.

+2
source share

All Articles