eraser tool for vector drawings ios - ios

I'm implementing my draw tools like this:
CGPoint CGPointCropByRect1(CGPoint point, CGRect rect)
{
rect = CGRectInset(rect, 5., 5.);
return CGPointMake(MIN(CGRectGetMaxX(rect), MAX(CGRectGetMinX(rect), point.x)), MIN(CGRectGetMaxY(rect), MAX(CGRectGetMinY(rect), point.y)));
}
CGFloat CGPointLengthToPoint1(CGPoint first, CGPoint second)
{
return sqrtf(powf(second.x - first.x, 2.) + powf(second.y - first.y, 2.));
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
_paths = [[NSMutableArray alloc] init];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
UIColor *color = [UIColor blackColor];
CGFloat width = 5.f;
if (_isErase) {
CGContextSetStrokeColorWithColor(ctx, [UIColor clearColor].CGColor);
//CGContextSetFillColorWithColor(ctx, [UIColor clearColor].CGColor);
CGContextSetBlendMode(ctx, kCGBlendModeClear);
}
else {
CGContextSetStrokeColorWithColor(ctx, [color CGColor]);
CGContextSetLineWidth(ctx, width);
CGContextSetLineJoin(ctx, kCGLineJoinRound);
CGContextSetLineCap(ctx, kCGLineCapRound);
}
for(NSArray *array in _paths)
{
size_t index = 0;
CGPoint first = [[array objectAtIndex:index++] CGPointValue];
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, first.x, first.y);
while (index < array.count)
{
CGPoint middlePoint = [[array objectAtIndex:index++] CGPointValue];
if(index < array.count)
{
CGPoint endPoint = [[array objectAtIndex:index++] CGPointValue];
//CGContextAddQuadCurveToPoint(ctx, middlePoint.x, middlePoint.y, endPoint.x, endPoint.y);
CGContextAddLineToPoint(ctx, middlePoint.x, middlePoint.y);
CGContextAddLineToPoint(ctx, endPoint.x, endPoint.y);
}
else
CGContextAddLineToPoint(ctx, middlePoint.x, middlePoint.y);
}
CGContextStrokePath(ctx);
}
CGContextBeginPath(ctx);
BOOL first = YES;
for(NSValue *point in _currentPath)
{
if(first)
CGContextMoveToPoint(ctx, point.CGPointValue.x, point.CGPointValue.y);
else
CGContextAddLineToPoint(ctx, point.CGPointValue.x, point.CGPointValue.y);
first = NO;
}
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
_currentPath = [[NSMutableArray alloc] init];
[_currentPath addObject:[NSValue valueWithCGPoint:[[touches anyObject] locationInView:self]]];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint currentTouch = [[touches anyObject] locationInView:self];
if(!CGRectContainsPoint(self.bounds, currentTouch))
{
if(!_currentPath.count)
return;
currentTouch = CGPointCropByRect1(currentTouch, self.bounds);
CGPoint lastTouch = [[_currentPath objectAtIndex:_currentPath.count - 1] CGPointValue];
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
[self setNeedsDisplayInRect:CGRectInset(CGRectMake(currentTouch.x, currentTouch.y, lastTouch.x - currentTouch.x, lastTouch.y - currentTouch.y), -10., -10.)];
return;
}
if(_currentPath.count == 0)
{
_currentPath = [[NSMutableArray alloc] init];
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
return;
}
CGPoint lastTouch = [[_currentPath objectAtIndex:_currentPath.count - 1] CGPointValue];
CGFloat dim = CGPointLengthToPoint1(currentTouch, lastTouch);
if(dim > 5.)
{
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
[self setNeedsDisplayInRect:CGRectInset(CGRectMake(currentTouch.x, currentTouch.y, lastTouch.x - currentTouch.x, lastTouch.y - currentTouch.y), -10., -10.)];
}
}
-(void)dropPath
{
if(_currentPath.count)
[_paths addObject:[NSArray arrayWithArray:_currentPath]];
[_currentPath release];
_currentPath = nil;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint currentTouch = [[touches anyObject] locationInView:self];
if (!_isErase) {
//CGPoint currentTouch = [[touches anyObject] locationInView:self];
[_currentPath addObject:[NSValue valueWithCGPoint:currentTouch]];
[self dropPath];
[self setNeedsDisplay];
}
else{
[_currentPath removeObject:[NSValue valueWithCGPoint:currentTouch]];
[self dropPath];
[self setNeedsDisplay];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
#end
the main idea is- I'm storing my current points in NSArray, and then add it in another array.
How can I create a eraser? I think the main idea is to redraw the lines, but how to implement it? Is there any of examples that will make it clear for me?
The option for using background color doesn't fit.
Thanks

You can try adding this snipper:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, self.path);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, [UIColor clear].CGColor);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextSetAlpha(context, self.lineAlpha);
CGContextStrokePath(context);

Related

Creating an ios paint application

I'm trying to create a simple paint app.
- (void)handleSingleTap:(UIPanGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView:[recognizer.view superview]];
NSLog(#"Test");
CGFloat ok = 40;
self.sheet.test = ok;
[self.sheet addPoint: location];
//Do stuff here...
}
This function draws lines but when I lift up my finger and replace it there is a "straight line" from the last point to the next one. How can I skip this?
Try controlling it using UIGestureRecognizerStateEnded
if(recognizer.state == UIGestureRecognizerStateEnded){
//Drawing Ends.
isDrawn = NO;
}
with your comments, I understood that you are controlling your line drawing method with a variable isDrawn.
if(recognier.state == UIGestureStateBegan){
[self moveToPoint:point]; // declare the point variable in the header file.
isDrawn = YES;
//Drawing Starts
}
Hope below code snippet helps
typedef NS_ENUM(NSInteger, PenType){
kPenTypeGreen,
kPenTypeCyan,
kPenTypeRed,
kPenTypePurple,
kPenTypeErase
};
#interface MCStylus() {
PenType penType;
CGPoint lastPoint;
CGPoint secondLastPoint;
NSInteger currentStylistPageIndex;
NSMutableArray *arrayOfStylistImages;
}
#property (nonatomic, strong) IBOutlet UIImageView *handwritingView;
#property (nonatomic, strong) UIImageView *drawImage;
- (void)initializeUI {
arrayOfStylistImages = [[NSMutableArray alloc] init];
[arrayOfStylistImages addObject:[[UIImage alloc] init]];
self.drawImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.handwritingView.frame.size.width, self.handwritingView.frame.size.height)];
self.drawImage.userInteractionEnabled = true;
self.handwritingView.backgroundColor = [UIColor whiteColor];
self.handwritingView.layer.cornerRadius = 5.0f;
self.handwritingView.layer.borderColor = [UIColor colorWithWhite:230.0f/255.0f alpha:1.0].CGColor;
self.handwritingView.layer.borderWidth = 2.0f;
self.handwritingView.clipsToBounds = true;
[self.handwritingView addSubview:self.drawImage];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
int count = [allTouches count];
if(count==1){
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self.handwritingView];
secondLastPoint = lastPoint;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
NSArray *allTouches = [touches allObjects];
int count = [allTouches count];
if(count==1){
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.handwritingView];
UIGraphicsBeginImageContext(self.handwritingView.frame.size);
if(self.drawImage.image!=NULL)
[self.drawImage.image drawInRect:CGRectMake(0, 0, self.handwritingView.frame.size.width, self.handwritingView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 2.0);
switch (penType) {
case kPenTypeGreen:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 1.0, 0.0, 1.0);
break;
case kPenTypeCyan:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.0, 0.0, 1.0, 1.0);
break;
case kPenTypeRed:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1.0, 0.0, 0.0, 1.0);
break;
case kPenTypePurple:
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0.5, 0.2, 0.3, 1.0);
break;
case kPenTypeErase:
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 6.0 * (self.handwritingView.frame.size.height/350));
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeClear);
CGContextSetStrokeColorWithColor(UIGraphicsGetCurrentContext(),[UIColor clearColor].CGColor);
break;
default:
break;
}
CGPoint mid1 = CGPointMake((lastPoint.x+secondLastPoint.x)/2, (lastPoint.y + secondLastPoint.y)/2);
CGPoint mid2 = CGPointMake((lastPoint.x+currentPoint.x)/2, (lastPoint.y+currentPoint.y)/2);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(UIGraphicsGetCurrentContext(),lastPoint.x, lastPoint.y,mid2.x,mid2.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
self.drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
secondLastPoint = lastPoint;
lastPoint = currentPoint;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
[super touchesEnded:touches withEvent:event];
if(self.drawImage.image!=NULL)
[arrayOfStylistImages replaceObjectAtIndex:currentStylistPageIndex withObject:self.drawImage.image];
}

How we erase Line

I want to make erase button on click we erase line on moving the line . But I am Unable to do it. I am successfully implemented of code of create d Line. But stuck how to erase Line. I am newer in iOS. Here is my code. Please help
#implementation Line
{
UIBezierPath *path;
UIImage *incrementalImage; // (1)
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
[self setMultipleTouchEnabled:NO];
[self setBackgroundColor:[UIColor whiteColor]];
path = [UIBezierPath bezierPath];
[path setLineWidth:2.0];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setMultipleTouchEnabled:NO];
path = [UIBezierPath bezierPath];
[path setLineWidth:1.0];
self.backgroundColor=[UIColor clearColor];
_button = [UIButton buttonWithType:UIButtonTypeCustom];
[_button setTitle:#"" forState:UIControlStateNormal];
_button.userInteractionEnabled=YES;
_button.frame =CGRectMake(100, 130, 100, 100);
_button.backgroundColor =[ UIColor redColor];
[_button addTarget:self
action:#selector(erase)
forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_button];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[incrementalImage drawInRect:rect]; // (3)
[path stroke];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path moveToPoint:p];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event // (2)
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];
[self drawBitmap]; // (3)
[self setNeedsDisplay];
[path removeAllPoints]; //(4)
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (void)drawBitmap // (3)
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, 0.0);
[[UIColor blackColor] setStroke];
if (!incrementalImage) // first draw; paint background white by ...
{
UIBezierPath *rectpath = [UIBezierPath bezierPathWithRect:self.bounds]; // enclosing bitmap by a rectangle defined by another UIBezierPath object
[[UIColor whiteColor] setFill];
[rectpath fill]; // filling it with white
}
[incrementalImage drawAtPoint:CGPointZero];
[path stroke];
incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
-(void)erase
{
NSLog(#"erasingLIne");
}
Take a BOOL value for erase. BOOL isErase;
when erase button tapped
if button tapped
{
isErase =Yes;
}else
{
isErase = NO;
}
[path strokeWithBlendMode:isErase?kCGBlendModeClear:kCGBlendModeNormal
alpha:1.0f];
Hope it works for you.

iOS How to draw a stroke with an outline

I am looking for an output as in this image Expected Result
I need an outline to my stroke. My code is as follows
- (void)awakeFromNib {
self.strokeArray = [NSMutableArray array];
self.layerIndex = 0;
self.isSolid = false;
self.path = [[UIBezierPath alloc] init];
self.innerPath = [[UIBezierPath alloc] init];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path moveToPoint:p];
[self.innerPath moveToPoint:p];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path addLineToPoint:p];
[self.innerPath addLineToPoint:p];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[self.path addLineToPoint:p];
[self.innerPath addLineToPoint:p];
[self drawBitmap];
[self setNeedsDisplay];
[self.path removeAllPoints];
[self.innerPath removeAllPoints];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (void)drawRect:(CGRect)rect
{
[self.incrementalImage drawInRect:rect];
[self.brushColor setStroke];
self.path.lineWidth = self.brushWidth;
if(self.isEraser)
[self.path strokeWithBlendMode:kCGBlendModeClear alpha:0.0];
else
[self.path stroke];
self.innerPath.lineWidth = self.brushWidth - 10;
[[UIColor clearColor] setStroke];
[self.innerPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
}
- (void)drawBitmap
{
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
if (!self.incrementalImage)
{
CGContextClearRect(context, CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height));
}
[self.incrementalImage drawAtPoint:CGPointZero];
[self.brushColor setStroke];
self.path.lineWidth = self.brushWidth;
if(self.isEraser)
[self.path strokeWithBlendMode:kCGBlendModeClear alpha:0.0];
else
[self.path stroke];
self.innerPath.lineWidth = self.brushWidth - 10;
[[UIColor clearColor] setStroke];
[self.innerPath strokeWithBlendMode:kCGBlendModeClear alpha:1.0];
self.incrementalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
On screen what i get is as per this image, Actual Result
I understand that blend mode 'clear' gives an eraser effect. What i want is that the stroke should have a solid outline on the sides and be clear in the middle. It should not blend into the path right below it.The path below it should still be visible.
How can i achieve this result?
Have a look at this question: Generate a CGPath from another path's line width outline
I guess that's what you need: creating a polygon of the line and stroke that instead of the line. Use CGPathCreateCopyByStrokingPath to get a path of the polygon and stroke it.
OK, since CGPathCreateCopyByStrokingPath seems to be a bit buggy, you could create your own implementation. Something like the following algorithm, which assumes you have a NSArray of CGPoint packed in NSValue objects.
It works pretty well until you start adding short overlapping lines which could of course easily happen while drawing. You could reduce this effect by only adding points in touchesMoved that have a larger distance (lineWidth/2?) to the previous added point. Another drawback is that the lines are simply straight (no kCGLineJoinRound or kCGLineCapRound) but maybe you could adjust the algorithm to do that.
+ (UIBezierPath*)polygonForLine:(NSArray *)points withLineWidth:(CGFloat)lineWidth{
UIBezierPath *path = [UIBezierPath bezierPath];
//stores the starting point to close the path
CGPoint startPoint;
//get the points to a c-array for easier access
CGPoint cpoints[points.count];
int numPoints = 0;
for(NSValue *v in points){
cpoints[numPoints++] = [v CGPointValue];
}
//store the last intersection to apply it for the next segement
BOOL hasIntersection = NO;
CGPoint intersectionPoint;
for (int i=0;i<numPoints-1;i++){
//get the current line segment
CGPoint p1 = cpoints[i];
CGPoint p2 = cpoints[i+1];
CGPoint l1p1,l1p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l1p1,&l1p2);
//if there had been an intersection with the previous segement, start here to get a nice outline
if(hasIntersection){
l1p1 = intersectionPoint;
}
//is there a next segment?
if(i+2<numPoints){
//get the next line segment
p1 = cpoints[i+1];
p2 = cpoints[i+2];
CGPoint l2p1,l2p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l2p1,&l2p2);
//calculate the intersection point with the current line segment
hasIntersection = getLineIntersection(l1p1, l1p2, l2p1, l2p2, &intersectionPoint);
//if they intersect, the current linesegment has to end here to get a nice outline
if(hasIntersection){
l1p2 = intersectionPoint;
}
}
//write the current linesegment to the path
if(i==0){
//first point, move to it and store it for closing the path later on
startPoint = l1p1;
[path moveToPoint:startPoint];
}else{
[path addLineToPoint:l1p1];
}
[path addLineToPoint:l1p2];
}
//now do the same for the other side of the future polygon
hasIntersection = NO;//reset intersections
for (int i=numPoints-1;i>0;i--){
//get the current line segment
CGPoint p1 = cpoints[i];
CGPoint p2 = cpoints[i-1];
CGPoint l1p1,l1p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l1p1,&l1p2);
//if there had been an intersection with the previous segement, start here to get a nice outline
if(hasIntersection){
l1p1 = intersectionPoint;
}
//is there a next segment?
if(i-2>=0){
//get the next line segment
p1 = cpoints[i-1];
p2 = cpoints[i-2];
CGPoint l2p1,l2p2;
getOffsetLineSegmentForPoints(p1,p2,lineWidth,&l2p1,&l2p2);
//calculate the intersection point with the current line segment
hasIntersection = getLineIntersection(l1p1, l1p2, l2p1, l2p2, &intersectionPoint);
//if they intersect, the current linesegment has to end here to get a nice outline
if(hasIntersection){
l1p2 = intersectionPoint;
}
}
//write the current linesegment to the path
[path addLineToPoint:l1p1];
[path addLineToPoint:l1p2];
}
//close the path
[path addLineToPoint:startPoint];
//we're done
return path;
}
void getOffsetLineSegmentForPoints(CGPoint p1, CGPoint p2, CGFloat lineWidth, CGPoint *linep1, CGPoint *linep2){
CGPoint offset = CGPointSub(p2, p1);
offset = CGPointNorm(offset);
offset = CGPointOrthogonal(offset);
offset = CGPointMultiply(offset, lineWidth/2);
(*linep1) = CGPointAdd(p1, offset);
(*linep2) = CGPointAdd(p2, offset);
}
CGPoint CGPointSub(CGPoint p1, CGPoint p2){
return CGPointMake(p1.x-p2.x, p1.y-p2.y);
}
CGPoint CGPointAdd(CGPoint p1, CGPoint p2){
return CGPointMake(p1.x+p2.x, p1.y+p2.y);
}
CGFloat CGPointLength(CGPoint p){
return sqrtf(powf(p.x,2)+powf(p.y,2));
}
CGPoint CGPointNorm(CGPoint p){
CGFloat length = CGPointLength(p);
if(length==0)
return CGPointZero;
return CGPointMultiply(p, 1/length);
}
CGPoint CGPointMultiply(CGPoint p, CGFloat f){
return CGPointMake(p.x*f, p.y*f);
}
CGPoint CGPointOrthogonal(CGPoint p){
return CGPointMake(p.y, -p.x);
}
BOOL getLineIntersection(CGPoint l1p1, CGPoint l1p2, CGPoint l2p1,
CGPoint l2p2, CGPoint *intersection)
{
CGPoint s1 = CGPointSub(l1p2, l1p1);
CGPoint s2 = CGPointSub(l2p2, l2p1);
float determinant = (-s2.x * s1.y + s1.x * s2.y);
if(determinant==0)
return NO;
CGPoint l2p1l1p1 = CGPointSub(l1p1, l2p1);
float s, t;
s = (-s1.y * l2p1l1p1.x + s1.x * l2p1l1p1.y) / determinant;
t = ( s2.x * l2p1l1p1.y - s2.y * l2p1l1p1.x) / determinant;
if (s >= 0 && s <= 1 && t >= 0 && t <= 1){
if (intersection != NULL){
(*intersection).x = l1p1.x + (t * s1.x);
(*intersection).y = l1p1.y + (t * s1.y);
}
return YES;
}
return NO;
}

how to space apart circle dots after drawing

user touch and drag on top of image
i had this code that will give me circle after drawing but how do i space apart them ?
//UIView CircleView
- (void) touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event
{
NSLog(#"started");
// Initialize a new path for the user gesture
self.path = [UIBezierPath bezierPath];
self.path.lineWidth = 4.0f;
self.whiteCircleArray = [[NSMutableArray alloc]init];
UITouch *touch = [touches anyObject];
[self.path moveToPoint:[touch locationInView:self]];
self.touchedEnded = FALSE;
}
- (void) touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event
{
// Add new points to the path
NSLog(#"Moved");
UITouch *touch = [touches anyObject];
//NSLog(#"[touch locationInView:self] %#",NSStringFromCGPoint([touch locationInView:self]));
[self.whiteCircleArray addObject: NSStringFromCGPoint([touch locationInView:self])];
[self.path addLineToPoint:[touch locationInView:self]];
//double startAngle = RADIANS(0);
//double endAngle = RADIANS(360);
// if ([touch locationInView:self].x <=200 )
// {
// [self.path addArcWithCenter:[touch locationInView:self] radius:LARGE_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
// }
// else if ([touch locationInView:self].x >=120 )
// {
// [self.path addArcWithCenter:[touch locationInView:self] radius:SMALL_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
// }
//[self.path addArcWithCenter:[touch locationInView:self] radius:BIG_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
//[self.path addArcWithCenter:[touch locationInView:self] radius:MIDDIUM_RADIUS startAngle:startAngle endAngle:endAngle clockwise:NO];
[self setNeedsDisplay];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"ended");
UITouch *touch = [touches anyObject];
//[self.path addLineToPoint:[touch locationInView:self]];
self.locationOfTouch =[touch locationInView:self];
self.touchedEnded = TRUE;
//NSLog(#"white circle pos %#",self.whiteCircleArray);
for(NSString *p in self.whiteCircleArray)
{
CGPoint point = CGPointFromString(p);
NSLog(#"X=%0.1f Y=%0.1f",point.x,point.x);
}
[self setNeedsDisplay];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"cancelled");
[self touchesEnded:touches withEvent:event];
}
-(void)drawTouchCircle
{
CGContextRef ctx= UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextSetLineWidth(ctx,1);
CGContextSetRGBFillColor(ctx, 55.0/255, 255.0/255.0, 5.0/255.0, 1.0);
CGContextSetRGBStrokeColor(ctx,0.0/255,0.0/255,0.0/255,1.0);
for(NSString *p in self.whiteCircleArray)
{
CGPoint point = CGPointFromString(p);
NSLog(#"X=%0.1f Y=%0.1f",point.x,point.x);
CGContextAddArc(ctx, point.x, point.y, LARGE_RADIUS, 0, M_PI*2, YES);
CGContextFillPath(ctx);
CGContextStrokePath(ctx);
}
}
- (void) drawRect:(CGRect)rect
{
// Draw the path
NSLog(#"drawRect");
if (self.touchedEnded)
{
[self drawTouchCircle];
}
else
{
UIColor *strokeColor = [UIColor redColor];
[strokeColor setStroke];
[self.path stroke];
}
// [self.path fill];
//[self.path closePath];
}
Put a distance check in your algo... CGPoint diff = {p2.x - p1.x, p2.y - p1.y} If the diff is greater than , add a new point.

CGContext strangeness

I have a little code module that should refer as signature panel so that the user can sign on this panel with his finger. The whole thing runs on the iPad.
Now, I managed to do the usual touchesBegan(), touchesMoved(), touchesEnded() carousel to make him sign on that panel. While signing, I draw his signature on the main view. However, due to whatever reason, the image appears twice: once correctly and once upside down above the main signature (see image). Since I don't see any translating being done in my code, I suspect that the whole code might be incorrect, but I don't know why. Does anyone know what I'm doing wrong here?
#import "RMSignatureView.h"
#import <QuartzCore/QuartzCore.h>
#interface RMSignatureView() {
CGPoint origin;
}
-(void) setupLayer;
#property (nonatomic, retain) UIImage* image;
#end
#implementation RMSignatureView
#synthesize image;
-(void) dealloc {
[image release];
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setupLayer];
}
return self;
}
-(id) initWithCoder:(NSCoder *)aDecoder {
if ([super initWithCoder:aDecoder] == self) {
[self setupLayer];
}
return self;
}
-(void) setupLayer {
self.layer.cornerRadius = 10;
self.layer.borderColor = [UIColor colorWithRed:109.0/256.0 green:149.0/256.0 blue:224.0/256.0 alpha:1.0].CGColor;
self.layer.borderWidth = 0.5f;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor);
CGFloat sizes[2];
sizes[0] = 1;
sizes[1] = 1;
CGContextSetLineDash(context, 0, sizes, 2);
CGContextMoveToPoint(context, rect.origin.x + 50, rect.origin.y + rect.size.height - 30);
CGContextAddLineToPoint(context, rect.origin.x + rect.size.width - 50, rect.origin.y + rect.size.height - 30);
CGContextStrokePath(context);
CGContextSetLineDash(context, 0, NULL, 0);
if (image)
CGContextDrawImage(context, rect, image.CGImage);
CGContextRestoreGState(context);
}
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
origin = [touch locationInView:self];
}
-(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
origin.x = -1;
origin.y = -1;
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
origin.x = -1;
origin.y = -1;
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
if (origin.x != -1 && origin.y != -1) {
UIGraphicsBeginImageContext(self.frame.size);
#try {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
if (image)
CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage);
CGContextMoveToPoint(context, origin.x, origin.y);
origin = [touch locationInView:self];
CGContextAddLineToPoint(context, origin.x, origin.y);
CGContextStrokePath(context);
self.image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(context);
}
#finally {
UIGraphicsEndImageContext();
}
}
[self setNeedsDisplay];
}
#end
Found it.. Quartz has (0, 0) in the lower left instead of upper left.

Resources