我正在做一个绘图应用程序,我正在尝试平滑我用手指绘制的线。为此我使用“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
{
}
当我用手指画画时,我正在设置如下所示的路径:
我不明白我错过了什么。所以我在这方面需要帮助。
编辑:图片发布于w.r.t.以下答案。
由于 Ranjit
答案 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;
,因此下一条曲线将再次开始上述过程。
我使用模拟器和设备测试了上述内容,这是一个屏幕截图:
以下是完整的消息来源:
- (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];
}