我在Android上正确渲染弧线时遇到问题。我怀疑我的数学在这里失败了,但我已经检查并重新检查,无法发现问题。
请考虑以下事项:
其中:
R
是椭圆的边界矩形O
是椭圆的原点a
是椭圆的x半径b
是椭圆的y半径P1
是椭圆上的第一个点P2
是椭圆上的第二个点我希望弧线在P1和P2之间延伸,但正如你所看到的,它会提前开始并结束。
一旦我确定了椭圆的边界矩形(这是正确的),我首先绘制一些调试信息:
// highlight each important point
path.AddCircle(P1.X, P1.Y, 3, Graphics.Path.Direction.Cw);
path.AddCircle(P2.X, P2.Y, 3, Graphics.Path.Direction.Cw);
path.AddCircle(O.X, O.Y, 3, Graphics.Path.Direction.Cw);
// draw bounding rectangle
path.AddRect(rect, Graphics.Path.Direction.Cw);
// draw in ellipse radii (a and b)
path.MoveTo(O.X, O.Y);
path.RLineTo(radius.Width, 0);
path.MoveTo(O.X, O.Y);
path.RLineTo(0, radius.Height);
在上面描述的具体示例中,这些是我正在使用的值(为了清楚起见,我将稍微舍入所有值):
O = (644, 850.154)
P1 = (528.08, 1030.4)
P2 = (759.92, 1030.4)
R = (322, 656.954, 644, 386.4)
到目前为止,这么好。以上所有内容都应该是正确的。接下来,我计算从O
到P1
和P2
的归一化向量:
var P1Vec = (P1 - O).Normalize();
var P2Vec = (P2 - O).Normalize();
这些出现为:
P1Vec = (-0.541, 0.841)
P2Vec = (0.541, 0.841)
为了确保这些是正确的,我添加了一些调试图形:
path.MoveTo(O.X, O.Y);
var end = startVec * 400;
path.RLineTo(end.X, end.Y);
path.MoveTo(O.X, O.Y);
end = endVec * 400;
path.RLineTo(end.X, end.Y);
正如您从图片中看到的那样,正如您所期望的那样,这些线条将完全切换为P1
和P2
。
所以下一步是弄清楚角度,因为那是Android的AddArc
方法所期望的:
var P1VecDot = Point.UnitX.Dot(P1Vec);
var P2VecDot = Point.UnitX.Dot(P2Vec);
var P1Acos = Math.Acos(P1VecDot);
var P2Acos = Math.Acos(P2VecDot);
var P1Angle = P1Acos.ToDegrees();
var P2Angle = P2Acos.ToDegrees();
我在这里得到的价值是:
P1VecDot = -0.541
P2VecDot = 0.541
P1Acos = 2.142
P2Acos = 0.999
P1Angle = 122.745
P2Angle = 57.254
这些角度之间的跨度约为65°,感觉恰到好处。所以,P1Angle
是我们的起始角度,因此我只需计算扫描然后绘制弧线:
var sweepAngle = P2Angle - P1Angle;
path.AddArc(R, startAngle, sweepAngle);
但绘制的弧线看起来不正确。
我确信这与绘制椭圆弧有关,而不是圆形,因为如果我使圆弧成圆形,那么一切都有效。我觉得我需要将椭圆上的点投影到圆上的等效点上并使用这些点来计算角度,但我还没有点击如何执行此操作。
有关如何修复的想法吗?
更新:我已经弄明白这里发生了什么,据我所知,这完全是无证件行为。我将在周末清理我的代码并发布一个答案(实际上,可能会在这篇文章上发表一篇博文)。