import UIKit
let numberOfDrawer = 30
let drawColor = UIColor.yellow
let lineWidth: CGFloat = 1.0
enum PenType: String {
case pencil = "铅笔"
case bucket = "水桶"
case eraser = "橡皮擦"
mutating func next() {
switch self {
case .pencil:
self = .bucket
case .bucket:
self = .eraser
case .eraser:
self = .pencil
}
}
}
class ViewController: UIViewController {
var pentype = PenType.pencil
var drawLayer: CAShapeLayer!
var drawPaths = [CGMutablePath]()
@IBOutlet weak var penButton: UIButton!
var historyAllRecords = [CAShapeLayer]()
var historyShowingRecords = [CAShapeLayer]()
private func creatNewLayer()-> CAShapeLayer {
let layer = CAShapeLayer()
layer.lineWidth = lineWidth;
layer.strokeColor = drawColor.cgColor
layer.fillColor = penButton.isSelected ? drawColor.cgColor : UIColor.clear.cgColor
view.layer.addSublayer(layer)
return layer
}
override func viewDidLoad() {
super.viewDidLoad()
}
override var prefersStatusBarHidden: Bool {
return true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if pentype == .eraser { return }
drawPaths.removeAll()
drawLayer = creatNewLayer()
guard let point = touches.first?.location(in: view) else { return }
(0...numberOfDrawer).forEach { index in
let path = CGMutablePath()
path.move(to: convertPointByCenterOfPoint(point: point, index: index))
drawPaths.append(path)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let point = touches.first?.location(in: view) else { return }
if pentype == .eraser {
let deleteLayers = historyShowingRecords.filter({ (pathLayer) -> Bool in
return pathLayer.path!.contains(point)
})
deleteLayers.forEach{ $0.removeFromSuperlayer() }
return
}
drawPaths.enumerated().forEach { (index, path) in
path.addLine(to: convertPointByCenterOfPoint(point: point, index: index))
}
if pentype == .bucket {
let resultPath = drawPaths.reduce(CGMutablePath(), { (resultPath, nextPath) -> CGMutablePath in
let newNext = nextPath.mutableCopy()
newNext?.closeSubpath()
resultPath.addPath(newNext!)
return resultPath
})
drawLayer.path = resultPath
} else {
let resultPath = drawPaths.reduce(CGMutablePath(), { (resultPath, nextPath) -> CGMutablePath in
resultPath.addPath(nextPath)
return resultPath
})
drawLayer.path = resultPath
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if pentype == .eraser { return }
historyShowingRecords.append(drawLayer)
historyAllRecords = historyShowingRecords
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if pentype == .eraser { return }
historyShowingRecords.append(drawLayer)
historyAllRecords = historyShowingRecords
}
@IBAction func penChange(_ sender: UIButton) {
pentype.next()
sender.setTitle(pentype.rawValue, for: .normal)
}
@IBAction func backAction(_ sender: UIButton) {
if let deleteLayer = historyShowingRecords.last {
deleteLayer.removeFromSuperlayer()
historyShowingRecords.removeLast()
}
}
@IBAction func recoverAction(_ sender: Any) {
if historyShowingRecords.count < historyAllRecords.count {
let recoverLayer = historyAllRecords[historyShowingRecords.count]
historyShowingRecords.append(recoverLayer)
view.layer.addSublayer(recoverLayer)
}
}
@IBAction func cleanAction(_ sender: Any) {
historyShowingRecords.forEach{ $0.removeFromSuperlayer() }
historyShowingRecords.removeAll()
historyAllRecords.removeAll()
}
}
extension ViewController {
func convertPointByCenterOfPoint(point:CGPoint, index:Int) -> CGPoint {
let center = CGPoint(x:view.bounds.width/2.0, y:view.bounds.height/2.0)
let increaseAngle = Double.pi * 2.0 * Double(index) / Double(numberOfDrawer);
let radius: Double = sqrt(pow(Double(point.x) - Double(center.x), 2) + pow(Double(point.y) - Double(center.y), 2))
let angle: Double = getAngle(startPoint: center, endPoint: point) + increaseAngle
return CGPoint(x: cos(angle) * radius + Double(center.x), y: sin(angle)*radius + Double(center.y))
}
func getAngle(startPoint:CGPoint, endPoint:CGPoint) -> Double {
let y = Double(endPoint.y - startPoint.y)
let x = Double(endPoint.x - startPoint.x)
let length = sqrt(y*y + x*x)
var rads = asin(y/length)
if x < 0 {
rads = (Double.pi - rads)
}
return rads
}
}