【问题标题】:how to compute the control points for a smooth path given a set of points?给定一组点,如何计算平滑路径的控制点?
【发布时间】:2011-11-06 02:02:27
【问题描述】:

我正在使用 UIBezierPath,但这个问题涉及路径的控制点,而不是绘图。给定一组点,我可以渲染一条路径。但是,我无法弄清楚如何计算控制点以像照片曲线编辑器(How to implement a Photoshop Curves editor in UIKit)中那样具有平滑线。

我看到的最接近的答案在这里:how can i trace the finger movement on touch for drawing smooth curves?

但是,我仍然无法掌握正确的计算方法。用代码总结一下:

for (int i = 0; i< points; i++) 
{
     ...

     [path addQuadCurveToPoint:nextPoint controlPoint:WTF];
}

【问题讨论】:

  • 寂静如此响亮,让人心痛。
  • 您希望曲线准确地通过每个给定点吗?还是您想要一条更平滑的曲线可能刚好通过某些给定点?
  • @robmayoff 我想 close 如果它是一个更简单的操作就足够了。
  • 如果有帮助,大多数色调曲线倾向于使用样条曲线插值的值。

标签: iphone objective-c ios quartz-graphics bezier


【解决方案1】:

您链接到的图像是一个不使用二次曲线的示例,所以我要运行 使用图像而不是代码。

下面的 ios(和 os x)上的贝塞尔路径基本上是绘图命令和点的列表。例如:

[path moveTo:CGMakePoint(1,1)];
[path curveToPoint:(10,10) controPoint1:(3,7) controlPoint2:(4,1)];
[path curveToPoint:(10,10) controPoint1:(15,17) controlPoint2:(21,11)];
[path closePath];

结果:

moveto (1,1)      
curveto (10,10) (3,7) (4,1) 
curveto (20,0) (15,17) (21,11)    
closepath 

贝塞尔路径上的控制点控制曲线离开点的方向和速率。第一个控制点 (cp) 控制曲线离开前一个点的方向和速率,第二个控制点控制您要弯曲到的点。对于二次曲线(使用 addQuadCurveToPoint:controlPoint: 得到的),这两个点都是相同的,正如您在文档中看到的方法 here 中所见。

沿着一组点获得平滑曲线涉及使 cp1 和 cp2 彼此共线,并且该线平行于该线段任一端的点。

这看起来像:

[path moveTo:2];
[path curveTo:3 controlPoint1:cp1 controlPoint2:cp2];

cp1 和 cp2 可以通过选择一些恒定的线长并做一些几何来计算(我现在忘记了我所有的线方程,但它们是 easily googleable)

将使用#-># 指定一个段,并使用#->#(cp#) 指定该段的要调用曲线的控制点。

下一个问题是使曲线从 2->3 段平滑到 3->4 段。此时在您的代码中,您应该有一个为 2->3(cp2) 计算的控制点。鉴于您之前的恒定线长(这将控制您获得的曲线的锐利程度),您可以通过在图中获得与 2->3(cp2) 和点 3 共线的点来计算 3->4 的 cp1。然后计算与 3->4(cp1) 共线并平行于点 3 和点 4 形成的线的 3->4(cp2)。冲洗并重复您的点数组。

【讨论】:

  • 感谢您的回复。不幸的是,在阅读完链接后,我仍然无法确定正确的方法。我责怪我的大脑。
  • 没有办法编写代码来计算控制点。
【解决方案2】:

我不确定这会有多大帮助,但我必须做一些类似的事情来实现一个曲线路径,以便在这个应用程序中跟随笔记 (www.app.net/hereboy)。本质上,它是一条具有三条曲线的路径。

为此,我为每条曲线创建了 4 个点、一个起点、一个终点以及 25% 标记和 75% 标记处的两个控制点。

这是我为此编写的代码:

//create points along the keypath for curve.
CGMutablePathRef curvedPath = CGPathCreateMutable();
const int TOTAL_POINTS = 3;
int horizontalWiggle = 15;

int stepChangeX = (endPoint.x - viewOrigin.x) / TOTAL_POINTS;
int stepChangeY = (endPoint.y - viewOrigin.y) / TOTAL_POINTS;

for(int i = 0; i < TOTAL_POINTS; i++) {
    int startX = (int)(viewOrigin.x + i * stepChangeX);
    int startY = (int)(viewOrigin.y + i * stepChangeY);

    int endX = (int)(viewOrigin.x + (i+1) * stepChangeX);
    int endY = (int)(viewOrigin.y + (i+1) * stepChangeY);

    int cpX1 = (int)(viewOrigin.x + (i+0.25) * stepChangeX);
    if((i+1)%2) {
        cpX1 -= horizontalWiggle;
    } else {
        cpX1 += horizontalWiggle;
    }
    int cpY1 = (int)(viewOrigin.y + (i+0.25) * stepChangeY);

    int cpX2 = (int)(viewOrigin.x + (i+0.75) * stepChangeX);
    if((i+1)%2) {
        cpX2 -= horizontalWiggle;
    } else {
        cpX2 += horizontalWiggle;
    }
    int cpY2 = (int)(viewOrigin.y + (i+0.75) * stepChangeY);

    CGPathMoveToPoint(curvedPath, NULL, startX, startY);
    CGPathAddCurveToPoint(curvedPath, NULL, cpX1, cpY1, cpX2, cpY2, endX, endY);
}

祝你好运!

【讨论】:

    猜你喜欢
    • 2011-07-14
    • 2013-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    • 2013-04-05
    相关资源
    最近更新 更多