4

I am doing a calligraphy application and would like to modify my code below so when a user ends a brush stroke, the line tapers and thins out like it would with a real calligraphy pen (a flick effect). I understand that touchesEnded may be a better way to do this, however I was just wondering what would be the best way to programmatically make this flick at the end of a stroke using CGRect or GraphicsContext in UIKit in Xcode for Objective C.

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwiped = YES;

UITouch *touch = [touches anyObject];
currentPoint = [touch locationInView:self.view];



UIGraphicsBeginImageContext(CGSizeMake(320, 568));
[drawImage.image drawInRect:CGRectMake(0, 0, 320, 568)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 5.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0, 0, 0, 1);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());


[drawImage setFrame:CGRectMake(0, 0, 320, 568)];
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
lastPoint = currentPoint;

}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//what code do I put here to get the flick effect - what CGGetContext Parameter
//may be applicable or what programming technique may help with this.     

}
Jesse Rusak
  • 56,530
  • 12
  • 101
  • 102
AppleFanBoy
  • 101
  • 1
  • 1
  • 8
  • I probably wouldn't be inclined to put drawing right in `touchesMoved` (i.e. I'd probably want to update my model with information about the user's gesture and either update a `CAShapeLayer` or use [`setNeedsDisplay`](http://developer.apple.com/library/ios/documentation/uikit/reference/uiview_class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-BBCCADHC) and have a subclassed `UIView` draw it for me), but the root of the question, how to draw a tapered line, is fascinating and I'm looking forward to any answers you might get. – Rob Feb 01 '13 at 17:47
  • This "xcode" tag is for questions about the IDE itself. – Jesse Rusak Feb 01 '13 at 21:15

1 Answers1

3

This may be over simplifying, but it should lead you in something of the right direction. I'm going to just make a triangle, but you could eventually add bezier curves to make the effect more realistic.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
//what code do I put here to get the flick effect - what CGGetContext Parameter
//may be applicable or what programming technique may help with this. 

    UIGraphicsBeginImageContext(CGSizeMake(320, 568));
    [drawImage.image drawInRect:CGRectMake(0, 0, 320, 568)];
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(context, 5.0);
    CGContextSetRGBFillColor(context, 0, 0, 0, 1);
    CGContextBeginPath(context);
    CGContextBeginPath(context);
    CGContextMoveToPoint(context, lastPoint.x, lastPoint.y);
    CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y);
    CGContextClosePath(context);
    CGContextStrokePath(context);

    //Normalized directionality
    float lineLength = sqrt((currentPoint.x - lastPoint.x)*(currentPoint.x - lastPoint.x) + (currentPoint.y - lastPoint.y)*(currentPoint.y - lastPoint.y));
    float dx = (currentPoint.x - lastPoint.x)/lineLength;
    float dy = (currentPoint.y - lastPoint.y)/lineLength;

    //Now make a triangle
    CGContextBeginPath(context);

    //2.5 is from 1/2 of your line width (5)
    CGContextMoveToPoint(context, currentPoint.x + 2.5*dy, currentPoint.y - 2.5*dx);

    //This 10 is completely arbitrary, the length your taper is going to be.
    //Ideally this will be proportional to your last line segment length, longer if their finger is moving faster...
    CGContextAddLineToPoint(context, currentPoint.x + 10*dx, currentPoint.y + 10*dy);

    //Now the last tip of the triangle
    CGContextMoveToPoint(context, currentPoint.x - 2.5*dy, currentPoint.y + 2.5*dx);
    CGContextClosePath(context);
    CGContextFillPath(context);

    [drawImage setFrame:CGRectMake(0, 0, 320, 568)];
    drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

Now to make this cooler you could add in calculation of the curve the person was drawing and create your "triangle" taper with bezier curves in the direction that they were curving. That could actually be really fun to calculate.

Putz1103
  • 6,211
  • 1
  • 18
  • 25
  • I appreciate your feedback on this. I will try this out and let you know how it goes. – Rob Feb 07 '13 at 14:47