2010-09-22 74 views
0

我一直在研究这个问题一段时间,并且因此无法提出一个好的解决方案。在Bezier曲线中放置“好”控制点

问题:我有一个三维(或更多)2D点的有序列表,我想用三次贝塞尔曲线对它们进行描边,使其“看起来很好”。 “看起来不错”的部分非常简单:我只想让第二点上的楔子变平滑(例如,曲线本身并不是双重的)。因此,给定三点时,在绘制曲线时,应该在哪里放置两个控制点,这些控制点将围绕三重点中的第二个点。

到目前为止,我的解决方案如下,但不完整。这个想法也可能有助于传达我所追求的外观。给定三点(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)); 

然后,找到点上切线,在这种情况下,找到了曲线会从点2至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. 

回答

0

这听起来像你可能需要弄清楚曲线会方向,以设定切点使它不会翻倍。根据我的理解,它只是简单地找出从(x1, y1)(x2, y2)的方向,然后沿着切线行驶您的启发距离,沿着最靠近(x1, y1) -> (x2, y2)方向的方向,并在那里切入切点。

+0

我不怀疑这是基本的想法。数学很难。 – 2012-02-03 19:12:27

0

如果你确信自己有一个很好的方法来选择你的点应该沿着切线的距离,并且你只需要决定将哪一条放在哪一边,那么我建议你看看再次在该线相切的那个圆上。你在圆上依次得到z1,z2,z3;想象从z2朝z1方向绕过圆圈,而是沿着切线行进;那是z2之前的控制点应该在哪一边; “z2之后”的控制点应该在另一侧。

请注意,这保证始终将两个控制点放在z2的两侧,这很重要。 (另外:你可能希望它们与z2的距离相同,否则你将在z2处得到不连续点,呃你的曲线的二阶导数,这可能看起来有点不理想)。仍然是病理案件。

如果您不介意代码的复杂性,那么在Don Knuth的METAFONT程序(其主要目的是绘制字体)中,确实存在一个复杂且非常有效的算法(以及更多)。该算法归功于John Hobby。您可以在METAFONT中找到详细的解释和工作代码,或者更好的是,可能更好的是,密切相关的METAPOST(它生成PostScript输出而不是巨大的位图)。但是,由于METAFONT和METAPOST是“识字程序”,这意味着它们的源代码和文档由一种Pascal代码(用于METAFONT)或C代码(用于METAFONT)的混合组成对于METAPOST)和TeX标记。有些程序可以将它变成一个精美的排版文档,但据我所知,没有人将结果放到任何地方。所以这里有一个链接到源代码,你可能会或可能不会完全不明白:http://foundry.supelec.fr/gf/project/metapost/scmsvn/?action=browse&path=%2Ftrunk%2Fsource%2Ftexk%2Fweb2c%2Fmplibdir%2Fmp.w&view=markup - 你应该在其中搜索“选择控制点”。

(用于METAFONT精美的排版文件可作为标题“METAFONT:节目”下一个正确的精装书。但是,它的成本实际的金钱,该代码是在帕斯卡)