给定边界矩形、起始角和扫掠角,如何确定圆弧端点的点 [英] Given bounding rectangle, starting angle, and sweep angle, how to determine points of the arc endpoints

查看:34
本文介绍了给定边界矩形、起始角和扫掠角,如何确定圆弧端点的点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个外接矩形、起始角和扫掠角,如何确定圆弧两端的点?

private void myPaint(object sender, PaintEventArgs e){图形 g = e.Graphics;矩形 rc = 新矩形(242, 299, 200, 300);Pen penRed = new Pen(Color.Red, 1);g.DrawArc(penRed, rc, 18, -108);//TODO - 确定弧的每一端的点//点 pt1 = ???//点 pt2 = ???}

解决方案

使用这个优秀的

最后一个音符,由于四舍五入,起点和终点可能相差一两个像素.如果您想要更准确,则必须自己绘制弧线.

Given a bounding rectangle, 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 = ???
}

解决方案

Using the equation of an ellipse from this excellent Mathematics answer We can calculate the start and end points of your ellipse, given the start angle and sweep.

First, we need the center of the bounding box, so we know how to shift the coordinates. That's simply

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's mark that point.
g.FillRectangle(Brushes.Yellow, Rectangle.FromLTRB(cX - 3, cY - 3, cX + 3, cY + 3));

We then need to convert the angles from degrees into radians, and change the clockwise angle to a counter-clockwise angle like so:

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

We'll also define 2 helper functions, the first to normalize an angle (map arbitrary angles into the range 0-360) and the second to adjust the calculated (x, y) coordinates into the correct quadrant. (Given that positive y is actually down on the 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;
    }
}

We now have enough information to calculate the start and end 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);

Those coordinates are relative to the bounding box's center, so we offset it using the center point we calculated above:

x += cX;
y += cY;

We can now draw the point:

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

All together the paint function looks like this:

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 painted the window background black to make the boxes and lines stand out better, and I left in some additional drawing elements, so it is easier to see what's happening in the calculations above.

Placing the code into a form, and associating with the form's paint event produces this result:

One final note, due to rounding, the start and end points may be off by a pixel or two. If you want more accuracy, you'd have to draw the arc yourself.

这篇关于给定边界矩形、起始角和扫掠角,如何确定圆弧端点的点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆