ios - 将 QuadCurve 添加到 UIBezierPath

标签 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

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

编辑:发布的图片。到下面的答案。

enter image description here

谢谢 兰 git

最佳答案

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

更改:

[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.)

If we are using the mid point as the ToPoint value, we need to take care the first case when there is only one current point, because with only one current point, we cannot derive a mid point from it - we need 2 points.

因此,我们最初需要“读取”当前点之后的一个点来计算中点。以下代码执行此操作:

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];
}

The variable counter is initially set to 0. So, nothing gets drawn until the second pass when counter is 1. And when it is, we will have 2 points to calculate the mid point.

接下来是其余的改动:

2.)

Once the first case is taken care of, we move forward to the rest of the curve and derive appropriately the points with which we connect the segments:

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

这是上面第一个 if 之后的 else if。当仅处理第一种情况时,我们进入此处,因为我使用一个简单的计数器,并在每次调用 touchesMoved 时递增它。

这里发生的是,我们使用前一个点作为控制点从前一个中点连接到 mid1。那么,目前的情况又如何呢?我们将使用它直到下一次传递。

3.) And finally, we take care the last segment of the curve in 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];
}

关于ios - 将 QuadCurve 添加到 UIBezierPath,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21143614/

相关文章:

iphone - 需要在我的应用程序运行时调暗 iPhone 屏幕

ios - NSDate 在 iOS 8.4 和 9.3 版本的模拟器上崩溃少于 5s

ios - 我怎样才能使 int 等于 int64_t 而没有得到转换丢失整数精度警告?

iphone - 退出应用程序后 imageview 为空

ios - swift 变得奇怪的淹没虚线

iphone - uisearchDisplayController:更改标签 "No Results"

ios - 从 Air for iOs 应用程序发送到第二个应用程序的链接

ios - ScrollView didEndDragging 时预测可见索引路径

ios - FBSDKLoginKit,注销完成时如何回调?

iphone - 处理带有静态单元格和另一个 searchResultsTableView 的 tableview