在iOS绘制过程中计算控制点

4
我正在制作一款绘图应用程序,用户可以用手指或者笔来绘制/写字。为此,我在我的应用程序中参考了https://github.com/yusenhan/Smooth-Line-View的代码。
我面临的问题是,有时候当你写得很接近时,书写不太流畅。
因此,我认为我在获取控制点方面犯了一些错误。
以下是我的代码:
//找到中点
CGPoint midPoint(CGPoint p1, CGPoint p2)
{
    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}

#pragma mark Gesture handle
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *touch = [touches anyObject];
    //LocationInView returns the current location of the reciever in coordinate system of the given View.
    m_previousPoint1 = [touch locationInView:self];
    m_previousPoint2 = [touch locationInView:self];
    m_currentPoint   = [touch locationInView:self];    

    [self touchesMoved:touches withEvent:event];}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{          
    //AnyObject:- Returns one of the objects in the set, or nil if the set contains no objects.
    UITouch *touch  = [touches anyObject];

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

    if(m_drawStep != ERASE)
    {
        m_drawStep = DRAW;
        m_drawing  = TRUE;        
    }    
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);//creates a graphics context suitable for use as an image(size of the image,opquae,scale, if scale = 0.0, means platform will take care of scaling)
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    m_curImage = UIGraphicsGetImageFromCurrentImageContext();// to turn the context into a UIImage    
    UIGraphicsEndImageContext();

 }

- (void)drawRect:(CGRect)rect
{
   CGPoint mid1 = midPoint(m_previousPoint1, m_previousPoint2);
   CGPoint mid2 = midPoint(m_currentPoint, m_previousPoint1);            

   [m_curImage drawAtPoint:CGPointMake(0, 0)];

   CGContextRef context = UIGraphicsGetCurrentContext();//Get a reference to current context(The context to draw)
   [self.layer renderInContext:context];
   //Simply keep referring to this context in below functions with proper arguments.
   CGContextMoveToPoint(context, mid1.x, mid1.y);//Position the current point
   CGContextAddQuadCurveToPoint(context, m_previousPoint1.x, m_previousPoint1.y, mid2.x, mid2.y);     
   CGContextSetLineCap(context, kCGLineCapRound);
   CGContextSetBlendMode(context, kCGBlendModeNormal);
   CGContextSetLineJoin(context, kCGLineJoinRound);
   CGContextSetLineWidth(context, self.lineWidth);
   CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
   CGContextSetShouldAntialias(context, YES);
   CGContextSetAllowsAntialiasing(context, YES);
   CGContextSetAlpha(context, self.lineAlpha);           
   CGContextSetFlatness(context, 0.6);
   CGContextStrokePath(context);//paints(fills) the line along the current path.            
}

根据我的理解,在CGContextAddQuadCurveToPoint中传递的点可以进行微调,但我不知道如何进行微调。我阅读文档以查找Bezier Curve的控制点,但我不理解。因此,朋友们,请帮助我理解我哪里出错了。

1
你可以使用Catmull-Rom样条线来代替bezeire曲线,以获得平滑的曲线。https://dev59.com/9moy5IYBdhLWcg3wN7UX - amar
@amar,你能提出一些建议来修改这段代码吗? - Ranjit
请检查此链接:http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-advanced-freehand-drawing-techniques/ 它可能会对您有所帮助,并向您展示如何使用贝塞尔曲线制作高效曲线。 - kamalesh kumar yadav
1个回答

4
您遇到的问题是,当用户缓慢拖动手指时,所获得的控制点距离太远,因此您得到的是大线段,而不是小像素变化,这会给您带来平滑的曲线外观。
从现有曲线计算贝塞尔控制点非常困难,因为控制点不在直线上。
最好使用Catmull-Rom曲线。Erica Sadun的《The Advanced iOS 6 Developer's Cookbook》书中有一个出色的“配方”,其中包含基于Catmull-Rom样条的平滑工作代码。 Catmull-Rom样条使用在曲线上的控制点。
我强烈推荐购买该书。第4.3个配方的示例代码将完全符合您的要求。

Catmull-Rom样条曲线沿着曲线具有控制点。您可以使用Catmull-Rom样条曲线将曲线分解为更多的直线段,而不使用三次或二次贝塞尔曲线。 - Duncan C
嗨@DuncanC,所以我应该完全放弃这段代码对吗?好的,我在4.3版本中看到了那段代码,它不能绘制平滑曲线。 - Ranjit
你好 @DuncanC,我已经查看了示例代码,函数catmull rom可以使用一定的粒度平滑给定路径。因此,路径可以是CGPath或UIBezierPath,对吗?我的意思是,我是否可以使用现有的代码并将我的路径传递给该函数。如果我错了,请纠正我。 - Ranjit
你好 @DuncanC,你说在我的现有代码中,控制点不是曲线。我没有理解这个意思。 - Ranjit
你好 @DuncanC,请查看这个 https://dev59.com/FHzaa4cB1Zd3GeqPUs-J,帮我解决一下。 - Ranjit
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接