将QuadCurve添加到UIBezierPath

Ran*_*jit 2 core-graphics objective-c uikit ios 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
{

}
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

编辑:图片发布到以下答案.

在此输入图像描述

谢谢Ranjit

Unh*_*lig 5

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

更改:

[path moveToPoint:m_previousPoint1];
[path addLineToPoint:mid1];
Run Code Online (Sandbox Code Playgroud)

至:

[path moveToPoint:mid1];
[path addLineToPoint:m_previousPoint1];
Run Code Online (Sandbox Code Playgroud)

并改变这个:

[path addQuadCurveToPoint:mid2 controlPoint:m_currentPoint];
Run Code Online (Sandbox Code Playgroud)

至:

[path addQuadCurveToPoint:m_currentPoint controlPoint:mid2];
Run Code Online (Sandbox Code Playgroud)

测试.


附录(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];
}
Run Code Online (Sandbox Code Playgroud)

变量计数器最初设置为0.因此,当计数器为1时,直到第二次传递才会被绘制.当它是时,我们将有2个点来计算中点.

然后是其余的接触:

2.)

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

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

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

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

3.)最后,我们关注曲线的最后一段touchesEnded:

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

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

最后touchesBegan,我设置了counter = 0;,所以下一条曲线将再次开始上述过程.

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

截图

以下是完整的来源:

- (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];
}
Run Code Online (Sandbox Code Playgroud)