3
votes

I am building an iOS app for drawing first time. Now i am able to draw lines and curves using core graphics but unable UNDO the drawing. I am saving all the points when drawing and try trying to reuse them for UNDO and REDO, but with no success. Can anyone help to know what i am doing wrong?

Any help is highly appreciated.

Here is my code

   -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [tempPathArray removeAllObjects];
    UITouch *touch = [touches anyObject];

    previousPoint1 = [touch previousLocationInView:self];
    previousPoint2 = [touch previousLocationInView:self];
    currentPoint = [touch locationInView:self];

}

    -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *touch  = [touches anyObject];

    previousPoint2  = previousPoint1;
    previousPoint1  = [touch previousLocationInView:self];
    currentPoint    = [touch locationInView:self];


    // calculate mid point
    CGPoint mid1    = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2    = midPoint(currentPoint, previousPoint1);

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, mid1.x, mid1.y);
    CGPathAddQuadCurveToPoint(path, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
    CGRect bounds = CGPathGetBoundingBox(path);
    CGPathRelease(path);

    drawBox = bounds;

    //Pad our values so the bounding box respects our line width
    drawBox.origin.x        -= self.lineWidth * 2;
    drawBox.origin.y        -= self.lineWidth * 2;
    drawBox.size.width      += self.lineWidth * 4;
    drawBox.size.height     += self.lineWidth * 4;

    UIGraphicsBeginImageContext(drawBox.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    curImage = UIGraphicsGetImageFromCurrentImageContext();
    [curImage retain];
    UIGraphicsEndImageContext();

    [tempPathArray addObject:[NSValue valueWithCGRect:drawBox]];


    [self setNeedsDisplayInRect:drawBox];

}

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{

    [pathArray addObject:tempPathArray];
    NSLog(@"path array count %d", [pathArray count]);
}

    - (void)drawRect:(CGRect)rect
{
    NSLog(@"draw rect");
    [curImage drawAtPoint:CGPointMake(0, 0)];
    CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2 = midPoint(currentPoint, previousPoint1);

    context = UIGraphicsGetCurrentContext(); 

    [self.layer renderInContext:context];

    CGContextMoveToPoint(context, mid1.x, mid1.y);
    // Use QuadCurve is the key
    CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 

    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineWidth(context, self.lineWidth);
    CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);

    CGContextStrokePath(context);
    [super drawRect:rect];

}

    -(void)undoButtonClicked
{

    KidsPhotoBookAppDelegate *appDelegate = (KidsPhotoBookAppDelegate*)[[UIApplication sharedApplication]delegate];


    if([pathArray count]>0){
        [bufferArray addObject:[pathArray lastObject]];
        [pathArray removeLastObject];

        for (NSMutableArray *tempArray in pathArray) {
            for (int i  = 0; i < [tempArray count]; i++) {
                CGRect draw = [[tempArray objectAtIndex:i] CGRectValue];
                [self setNeedsDisplayInRect:draw];
            }
        }
    }


}
1

1 Answers

0
votes

Try this:

  1. Draw a line.
  2. Draw another line back over the first line.
  3. Undo.

I suspect you'll see it mostly work—the part of the second line that overlapped the first line will disappear, and only the part that didn't will remain.

The problem is that you're setting needs display on the portions of the drawing that you still have, but not the portion that you just vacated. This is exactly the inverse of what you should be doing: The portions you still have don't need to be redrawn, because they haven't changed, whereas the portion you vacated does need to be redrawn because it has changed.

So, set needs display in the area of the path you're removing, just before you remove it. You shouldn't need to set needs display of anything else.