C# 给定边界矩形、起始角度和扫掠角度,如何确定圆弧端点的点

C# 给定边界矩形、起始角度和扫掠角度,如何确定圆弧端点的点,c#,.net,wpf,trigonometry,C#,.net,Wpf,Trigonometry,给定一个边界矩形、起始角和扫掠角,如何确定圆弧每一端的点 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,

给定一个边界矩形、起始角和扫掠角,如何确定圆弧每一端的点

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 = ???
}

根据这一极好的公式,我们可以计算椭圆的起点和终点,给定起点角度和扫掠

首先,我们需要边界框的中心,这样我们就知道如何移动坐标。那很简单

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));
然后我们需要将角度从度转换为弧度,并将顺时针角度更改为逆时针角度,如下所示:

double minTheta = (Math.PI / 180) * (360 - start);
double maxTheta = (Math.PI / 180) * (360 - (start + sweep));
我们还将定义两个辅助函数,第一个用于规范化角度(将任意角度映射到0-360范围),第二个用于将计算的(x,y)坐标调整到正确的象限。(考虑到正y实际上在表单上)

这些坐标相对于边界框的中心,因此我们使用上面计算的中心点对其进行偏移:

x += cX;
y += cY;
我们现在可以得出结论:

g.FillRectangle(Brushes.Purple, new Rectangle((int)x - 3, (int)y - 3, 6, 6));
总的来说,绘制功能如下所示:

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);
}
我将窗口背景漆成黑色,以使方框和线条更加突出,并留下了一些额外的绘图元素,因此更容易看到上面的计算结果

将代码放置到表单中,并与表单的绘制事件关联会产生以下结果:


最后一个注意事项是,由于四舍五入,起点和终点可能会偏离一到两个像素。如果你想获得更高的精确度,你必须自己画弧。

这似乎不是一个编程问题,而是一个数学问题。您最好找出计算所需内容的公式,然后将该公式应用到代码中。如果你被困在这个问题上,你可以发布你已经尝试过的,以及你正在尝试实现的公式。然后我们可以帮助你。你需要能够评估曲线->自己画->有很多算法,做一个网络搜索。这绝对是完美的!非常感谢您的帮助。经过进一步测试,此解决方案适用于18,-108的起始角和扫掠角。但是如果我使用18,-188,其中一个端点的位置是错误的。如果可以的话,我会添加另一张图片。我会想办法的。想象一条穿过中心点的垂直线。当前的实现总是将第一点放在它应该放在的地方。但第二个点只有在圆弧没有穿过假想的垂直线时才是正确的。它总是将两个点放在左半部或右半部。进一步测试后,计算出的x值似乎总是大于中心点的x值。即将更新。我翻转了坐标系(-y向上)和角度(+θ为顺时针)。加上公式中的Tan()仅在一定范围内定义。
g.FillRectangle(Brushes.Purple, new Rectangle((int)x - 3, (int)y - 3, 6, 6));
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);
}