Search code examples
iosarraysswiftcgpointcgpath

Appending array of CGPoints to array: Array<Array<CGPoint>>?


I have a drawing app using Core Graphics. Everything works fine. I'm able to draw. I added an "undo" button to undo the line. It works, but...

Problem: Every time the "undo" button is pressed it removes line by line by line. I'm trying to append array of CGPath to an array which will hold the entire drawing. e.g. If I draw a line from the left edge of the screen to the right edge of the screen, when I pressed the "UNDO", it should remove this 'path'(array of CGPoints). It's currently doing line by line which takes like a million "UNDO" calls to remove that same drawpath.

Probable Solution: I think the best way is to collect an array of CGPoints from touchesBegans through touchesEnded and then append it to an array that holds array of CGPoints.

 array<array<CGPoint>> //Using something like this

MainViewController: Calling the "UNDO" Action

 //calls the "undo" in UIView class
 @IBAction func undoButton(sender: AnyObject) {
 var theDrawView = drawView as DrawView
 theDrawView.undoLastPath()
}

Custom UIView Class:

var lines: [Line] = []

var lastPoint: CGPoint!
var drawColor = UIColor.redColor()
var allLines = Array<Array<CGPoint>>()//Will store arrays of CGPoint Arrays


required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
    var touch = touches.first as! UITouch
    lastPoint = touch.locationInView(self)
}

override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
    var touch = touches.first as! UITouch
    var newPoint = touch.locationInView(self)

    lines.append(Line(start: lastPoint, end: newPoint, color: drawColor))
    lastPoint = newPoint
    self.setNeedsDisplay()

}

override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
    var touch = touches.first as! UITouch
    var newPoint = touch.previousLocationInView(self)
    //ERROR: lines are not appending!
    allLines.append(lines(start: lastPoint, end: newPoint, color: drawColor))

    touchesMoved(touches, withEvent: event)
}

override func drawRect(rect: CGRect) {
    var context = UIGraphicsGetCurrentContext()
    CGContextBeginPath(context)
    CGContextSetLineWidth(context, 10.0)
    CGContextSetLineCap(context, kCGLineCapRound)

    //Currently this works: Will add the new allLines (Array)
    for line in lines {

        CGContextMoveToPoint(context, line.start.x, line.start.y)
        CGContextAddLineToPoint(context, line.end.x, line.end.y)

        //CGContextSetRGBStrokeColor(context, 0, 0, 0, 1.0)
        CGContextSetStrokeColorWithColor(context, line.color.CGColor)
        CGContextStrokePath(context)
    }
}
func eraseAll(){
    lines.removeAll(keepCapacity: false)
    self.setNeedsDisplay()
}

Custom Swift class for my line:

class Line {
var start: CGPoint
var end: CGPoint
var color: UIColor
init(start _start: CGPoint, end _end: CGPoint, color: UIColor) {
    start = _start
    end = _end
    color = _color
    }
}

I've tried multiple different ways to append the lines array to allLines array but without success.

How can I append my lines draw to this:

 array<array<CGPoint>>

Solution

  • I believe you should make your allLines be an array of array of Line:

    var allLines = [[Line]]()
    

    Then your touchesEnded becomes:

    override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
        var touch = touches.first as! UITouch
        var newPoint = touch.previousLocationInView(self)
        lines.append(Line(start: lastPoint, end: newPoint, color: drawColor))
        allLines.append(lines)
    
        // Prep lines to hold the next line
        lines = []
    }
    

    and in your drawRect:

    for lines in allLines {
        for line in lines {
    
            CGContextMoveToPoint(context, line.start.x, line.start.y)
            CGContextAddLineToPoint(context, line.end.x, line.end.y)
    
            //CGContextSetRGBStrokeColor(context, 0, 0, 0, 1.0)
            CGContextSetStrokeColorWithColor(context, line.color.CGColor)
            CGContextStrokePath(context)
        }
    }
    

    and undoLastPath is simply:

    func undoLastPath() {
        if count(allLines) > 0 {
            allLines.removeLast()
            self.setNeedsDisplay()
        }
    }