我一直在研究这个问题一段时间,到目前为止还没有想出一个好的解决方案。
问题:我有一个包含三个(或更多)二维点的有序列表,我想用三次贝塞尔曲线遍历这些点,使其“看起来不错”。“看起来不错”的部分非常简单:我只想平滑第二点处的楔形(因此,例如,曲线本身不会双回)。因此,给定三个点,在绘制曲线时,应该将两个控制点放置在三元组中的第二个点周围。
到目前为止,我的解决方案如下,但不完整。这个想法也可能有助于传达我所追求的外观。
给定三个点,(x1,y1), (x2,y2), (x3,y3)。取每个三重点所内接的圆(如果它们共线,我们只需在它们之间画一条直线并继续前进)。在点 (x2,y2) 处取与该圆相切的线——我们将围绕 (x2,y2) 的控制点放置在该切线上。
这是我坚持的最后一部分。我遇到的问题是找到一种方法将两个控制点放在这条切线上——我有一个足够好的启发式方法来判断它们应该在这条线上离 (x2,y2) 多远,但是当然,有这条线上的两个点距离那么远。如果我们计算“错误”方向的曲线,曲线会自行循环。
要找到由三个点描述的圆心(如果任何点具有相同的 x 值,只需在下面的计算中重新排序这些点):
double ma = (point2.y - point1.y) / (point2.x - point1.x);
double mb = (point3.y - point2.y) / (point3.x - point2.x);
CGPoint c; // Center of a circle passing through all three points.
c.x = (((ma * mb * (point1.y - point3.y)) + (mb * (point1.x + point2.x)) - (ma * (point2.x + point3.x))) / (2 * (mb - ma)));
c.y = (((-1 / ma) * (c.x - ((point1.x + point2.x) / 2))) + ((point1.y + point2.y) / 2));
然后,要找到切线上的点,在这种情况下,要找到从 point2 到 point3 的曲线的控制点:
double d = ...; // distance we want the point. Based on the distance between
// point2 and point3.
// mc: Slope of the line perpendicular to the line between
// point2 and c.
double mc = - (c.x - point2.x) / (c.y - point2.y);
CGPoint tp; // point on the tangent line
double c = point2.y - mc * point2.x; // c == y intercept
tp.x = ???; // can't figure this out, the question is whether it should be
// less than point2.x, or greater than?
tp.y = mc * tp.x + c;
// then, compute a point cp that is distance d from point2 going in the direction
// of tp.