Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smooth writing on iPad

I'm currently working on a iPad project where I need the functionality to let the user write on a piece of paper with a stylus.

I've tested a couple of styluses and found out that the bamboo was the best. They also have a free application which you can use to write.

The problem I'm facing is that the method I use does not delivers smooth curves. The bamboo paper app provides perfect looking lines. This is the code I have so far:

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIGraphicsBeginImageContext(self.frame.size);

    // draw accumulated lines
    if ([self.lines count] > 0) {
        for (Line *tempLine in self.lines){
            CGContextSetAlpha(context, tempLine.opacity);
            CGContextSetStrokeColorWithColor(context, tempLine.lineColor.CGColor);
            CGContextSetLineWidth(context, tempLine.lineWidth);
            CGContextSetLineCap(context, kCGLineCapRound);
            CGContextSetLineJoin(context, kCGLineJoinRound);
            CGContextAddPath(context, tempLine.linePath);
            CGContextStrokePath(context);

            }
    }

    //draw current line
    CGContextSetAlpha(context, self.currentLine.opacity);


    CGContextSetStrokeColorWithColor(context, self.currentLine.lineColor.CGColor);
    CGContextSetLineWidth(context, self.currentLine.lineWidth);
    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineJoin(context, kCGLineJoinRound);
    CGContextBeginPath(context);
    CGContextAddPath(context, self.currentLine.linePath);
    CGContextStrokePath(context);


    UIGraphicsEndImageContext();


}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint cPoint = [touch locationInView:self];

    CGPathMoveToPoint(self.currentLine.linePath, NULL, cPoint.x, cPoint.y);

    [self setNeedsDisplay];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];   
    CGPoint currentPoint = [touch locationInView:self];

    CGPathAddLineToPoint(self.currentLine.linePath, NULL, currentPoint.x, currentPoint.y);

    [self setNeedsDisplay];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  
    UITouch *touch = [touches anyObject];
    CGPoint cPoint = [touch locationInView:self];
    CGPathAddLineToPoint(self.currentLine.linePath, NULL, cPoint.x, cPoint.y);

    [self setNeedsDisplay];
    [self.lines addObject:self.currentLine];
    Line *nextLine = [[Line alloc] initWithOptions:self.currentLine.lineWidth color:self.currentLine.lineColor opacity:self.currentLine.opacity];
    self.currentLine = nextLine;
    [nextLine release];
}

Here are the images that makes it clear what problem I'm facing. This is the image what gets generated when writing with the code provided above:

enter image description here

This is the image if I write the same thing on the Mamboo paper app:

enter image description here

Does anyone have an idea how to get the nice writing like in the mamboo app?

like image 911
CyberK Avatar asked Sep 19 '11 08:09

CyberK


1 Answers

Instead of joining the points using straight lines (CGPathAddLineToPoint) you should try using bezier curves: CGPathAddCurveToPoint or CGPathAddQuadCurveToPoint.

This is what will do the smoothing.


If you are not familliar with bézier curves, you will probably find the wikipedia page about Bézier curves interesting (not specifically the math equations, but look at the sketches and animated images). It will give your the general idea of how control points affect the smoothing of the lines around the key points of your line.

For your case, Quadratic curves (only one control point for each subsegment between two of your key points) should be sufficient.

Construction of a quadratic Bézier curve - Source: Wikipedia(One line from P0 to P1, smoothed using control point P1)


One example (out of the box, only a suggestion out of my mind, never tested, adapt the coefficients to your needs) to compute this control point C between each of your keypoints A and B is to make the AC being, say, 2/3rd of the length of AB, and (AB,AC) making an angle of 30 degrees or sthg similar.

You may even propose in the settings of your app to adjust the smoothing strengh with a slider, which will impact the values you choose to compute each control points and see which coefficients fits best.

like image 82
AliSoftware Avatar answered Oct 12 '22 11:10

AliSoftware