将QuadCurve添加到UIBezierPath

时间:2014-01-15 17:00:01

标签: ios objective-c uikit core-graphics uibezierpath

我正在做一个绘图应用程序,我正在尝试平滑我用手指绘制的线。为此我使用“quadCurveToPoint”功能。但是,我说得不对。

以下是我的代码:

- (void) drawRect:(CGRect)rect
{   
    [path stroke];
}

- (id) initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame])
        self.multipleTouchEnabled = NO;

    path = [UIBezierPath bezierPath];
    path.lineWidth = IS_IPAD? 2.0f : 1.0f;

    return self;
}



- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{   
    UITouch *touch = [touches anyObject];

    m_previousPoint1 = [touch locationInView:self];
    m_previousPoint2 = [touch locationInView:self];
    m_currentPoint  = [touch locationInView:self];
}

//Find the midpoint
CGPoint midPoint(CGPoint p1, CGPoint p2)
{
    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}


- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{
    UITouch *touch = [touches anyObject];

    m_previousPoint2 = m_previousPoint1;
    m_previousPoint1 = m_currentPoint;

    m_currentPoint = [touch locationInView:self];

    CGPoint mid1 = midPoint(m_previousPoint1, m_previousPoint2);
    CGPoint mid2 = midPoint(m_currentPoint, m_previousPoint1);



    [path setFlatness:1.0f];
    [path setLineCapStyle:kCGLineCapRound];
    [path setLineJoinStyle:kCGLineJoinRound];
    [path moveToPoint:m_previousPoint1];
    [path addLineToPoint:mid1];

    [path addQuadCurveToPoint:mid2 controlPoint:m_currentPoint];
    [self setNeedsDisplay];
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{

}

当我用手指画画时,我正在设置如下所示的路径:

enter image description here

我不明白我错过了什么。所以我在这方面需要帮助。

编辑:图片发布于w.r.t.以下答案。

enter image description here

由于 Ranjit

1 个答案:

答案 0 :(得分:5)

您的代码看起来不错。但要解决您提到的问题,请将当前代码更改为以下内容:

变化:

[path moveToPoint:m_previousPoint1];
[path addLineToPoint:mid1];

要:

[path moveToPoint:mid1];
[path addLineToPoint:m_previousPoint1];

并改变这一点:

[path addQuadCurveToPoint:mid2 controlPoint:m_currentPoint];

要:

[path addQuadCurveToPoint:m_currentPoint controlPoint:mid2];

测试。


附录(WWDC算法):

<强> 背景

根据WWDC的说法,这个想法是这样的:

1。)我们使用中点作为起点和终点,而不是使用当前点。

2。)因此,我们使用实际触摸点作为控制点。

您的代码的分析/更正

所以这里是我使用WWDC中引入的想法的简化版代码。

你明白了。几乎。鉴于上述情况,我们需要在touchesMoved中对您的代码进行以下更改:

  

1)

     

如果我们使用中点作为ToPoint值,我们需要注意第一种情况   当只有一个当前点时,因为   只有一个当前点,我们无法从中得出一个中点 -   我们需要2分

因此,我们需要首先“读取”当前点之后的一个点来计算中点。以下是:

UITouch *touch = [touches anyObject];

m_previousPoint1 = m_currentPoint;
m_currentPoint = [touch locationInView:self];
mid1 = midPoint(m_currentPoint, m_previousPoint1);

if(counter == 1)
{
    [path moveToPoint:m_currentPoint];
    [path addLineToPoint:mid1];
    [self setNeedsDisplay];
}
  

变量计数器最初设置为0.因此,在第二个之前不会绘制任何内容   当计数器为1时传递。当它是时,我们将有2个点来计算中点。

接下来是其余部分:

  

2。)

     

一旦第一个案例得到处理,我们就会前进到曲线的其余部分并推导出来   适当地与我们连接的点   细分:

else if(counter > 1)
{
    [path addQuadCurveToPoint:mid1 controlPoint:m_previousPoint1];
    [self setNeedsDisplay];
}
counter++;

以上是else if之后的第一个if。我们只在处理第一个案例时进入这里,为此我使用一个简单的计数器,并在每次调用touchesMoved时递增它。

这里发生的是我们使用前一个点作为控制点从前一个中点连接到mid1。那么,目前的情况呢?我们正在使用它,直到下一次通过。

  

3。)最后,我们在touchesEnded

中注意曲线的最后一段
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [path addLineToPoint:[[touches anyObject] locationInView:self]];
    [self setNeedsDisplay];
}

这只是从中点到最后一点画一条线。

最后在touchesBegan,我设置counter = 0;,因此下一条曲线将再次开始上述过程。

我使用模拟器和设备测试了上述内容,这是一个屏幕截图:

screenshot

以下是完整的消息来源:

- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{
    UITouch *touch = [touches anyObject];
    counter = 0;
    m_previousPoint1 = [touch locationInView:self];
    m_currentPoint  = [touch locationInView:self];
}

//Find the midpoint
CGPoint midPoint(CGPoint p1, CGPoint p2)
{
    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}


- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{
    UITouch *touch = [touches anyObject];

    m_previousPoint1 = m_currentPoint;
    m_currentPoint = [touch locationInView:self];

    mid1 = midPoint(m_currentPoint, m_previousPoint1);

    [path setFlatness:1.0f];
    [path setLineCapStyle:kCGLineCapRound];
    [path setLineJoinStyle:kCGLineJoinRound];

    if(counter == 1)
    {
        [path moveToPoint:m_currentPoint];
        [path addLineToPoint:mid1];
        [self setNeedsDisplay];
    }
    else if(counter > 1)
    {
        [path addQuadCurveToPoint:mid1 controlPoint:m_previousPoint1];
        [self setNeedsDisplay];
    }
    counter++;
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [path addLineToPoint:[[touches anyObject] locationInView:self]];
    [self setNeedsDisplay];
}