gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 23:14:23 24 4
gpt4 key购买 nike

给定边界矩形、起始角和扫描角,如何确定圆弧两端的点?

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

最佳答案

使用这个优秀的 Mathematics answer 中的椭圆方程我们可以根据起始角度和扫掠计算出椭圆的起点和终点。

首先,我们需要边界框的中心,所以我们知道如何移动坐标。简直了

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));

我们还将定义 2 个辅助函数,第一个用于归一化角度(将任意角度映射到 0-360 范围内),第二个用于将计算出的 (x, y) 坐标调整到正确的象限。 (鉴于积极的 y 实际上在表格上)

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;
}
}

我们现在有足够的信息来计算起点和终点。

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));

paint 函数看起来像这样:

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);
}

我将窗口背景涂成黑色以使框和线更加突出,并且我留下了一些额外的绘图元素,因此更容易看出上面的计算发生了什么。

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

Final Result

最后一点,由于四舍五入,起点和终点可能相差一两个像素。如果你想要更准确,你必须自己画弧。

关于c# - 给定边界矩形、起始角和扫角,如何确定圆弧端点的点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37758377/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com