将QuadCurve添加到UIBezierPath [英] Adding a QuadCurve to UIBezierPath

查看:103
本文介绍了将QuadCurve添加到UIBezierPath的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am doing a drawing app and I am trying to smooth the line which I draw with finger.For this purpose I am using "quadCurveToPoint" function. But, I am not getting it right.

以下是我的代码:

- (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
{

}

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

When I draw with my finger, I am geting a path like this below:

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

I am not understanding what I am missing. So I need help in this regard.

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

Image posted w.r.t. to the below answer.

谢谢
Ranjit

Thanks Ranjit

推荐答案

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

Your code looks good. But to fix the problem you mentioned, change the current code to the following:

更改:

[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算法):

背景

Background:

根据WWDC的想法是这样的:

The idea is this according to WWDC:

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

1.) Instead of using the current point, we use the mid points as the start point and end point.

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

2.) As a result, we use the actual touch points as control points.

您的代码的分析/更正

Analysis / Correction for your code:

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

So here is a simplified version of code I made making use the idea that was introduced in WWDC.

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

You got the idea. Almost. Given the above, we need to make changes to your code in touchesMoved to the following:


1。)

1.)

如果我们使用中间点作为 ToPoint 值,我们需要采取当只有一个当前点时,关注第一个案例
,因为
只有一个当前点,我们无法从中得到一个中点 -
我们需要2个点

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.

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

So, we would need to "read" one point past the current point initially to calculate the mid point. The following does that:

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个点来计算中点。

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。)

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++;

这是否则如果就在首先如果以上。我们只在处理第一个案例时进入此处,因为我使用一个简单的计数器并在每次 touchesMoved 被调用时递增它。

Here is the else if right after the first if above. We enter here when only the first case is handled, for that I use a simple counter and increment it every time touchesMoved gets called.

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

What happens here is that we are connecting from the previous mid point to mid1 using the previous point as control point. So, what about the current point? We are using it until the next pass.


3。)最后,我们在<$ c中注意曲线的最后一段$ c> touchesEnded :



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

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

This simply draws a line from your mid point to the last point.

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

And finally in touchesBegan, I set counter = 0;, so the next curve will start the above process again.

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

I tested the above using both simulator and device, and here is a screen shot:

以下是完整的来源:

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

这篇关于将QuadCurve添加到UIBezierPath的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆