Silver Challenge: Colors
Changes to Line.swift: import UIKit and make extension to Line
// import Foundation
import UIKit
import CoreGraphics
struct Line {
var begin = CGPoint.zero
var end = CGPoint.zero
}
extension Line {
var angle: Measurement<UnitAngle> {
guard begin != end else {
return Measurement(value: 0.0, unit: .radians)
}
let dy = Double(end.y - begin.y)
let dx = Double(end.x - begin.x)
let angleInRadian: Measurement<UnitAngle> = Measurement(value: atan2(dy, dx), unit: .radians)
return angleInRadian
}
var color: UIColor {
let colors = [ UIColor.black, UIColor.blue, UIColor.brown, UIColor.cyan, UIColor.darkGray, UIColor.gray, UIColor.green, UIColor.lightGray, UIColor.magenta, UIColor.orange, UIColor.purple, UIColor.red, UIColor.yellow]
let ratio = (self.angle.value + Double.pi) / (Double.pi * 2) // First map angle in 0 ..< 2*Pi
let colorIndex = Int( Double(colors.count - 1) * ratio)
return colors[colorIndex]
}
}
Update draw(_ in DrawView.swift
override func draw(_ rect: CGRect) {
for line in finishedLines {
line.color.setStroke() // Use color by angle
stroke(line)
}
currentLineColor.setStroke()
for (_, line) in currentLines {
line.color.setStroke() // Use color by angle
stroke(line)
}
}
Gold Challenge: Circles
Two touches will trigger the draw circle mode. The center of circle is calculated by mid-point of the two touches.
Create a file Circle.swift
import CoreGraphics
struct Circle {
var rect = CGRect.zero
init() {
self.rect = CGRect.zero
}
init(rect: CGRect) {
self.rect = rect
}
init(point1: CGPoint, point2: CGPoint) {
let width = abs(point2.x - point1.x)
let height = abs(point2.y - point1.y)
let diameter = min(width, height)
let radius = diameter / 2
let center = CGPoint(x: (point1.x + point2.x) / 2, y: (point1.y + point2.y) / 2)
self.rect = CGRect(x: center.x - radius, y: center.y - radius, width: diameter, height: diameter)
}
}
Here is updated DrawView.swift
import UIKit
class DrawView: UIView {
var currentLines = [NSValue:Line]()
var finishedLines = [Line]()
var currentCircle = Circle()
var finishedCircles = [Circle]()
@IBInspectable var finishedLineColor: UIColor = UIColor.black {
didSet {
setNeedsDisplay()
}
}
@IBInspectable var currentLineColor: UIColor = UIColor.red {
didSet {
setNeedsDisplay()
}
}
@IBInspectable var lineThickness: CGFloat = 10 {
didSet {
setNeedsDisplay()
}
}
func stroke(_ line: Line) {
let path = UIBezierPath()
path.lineWidth = lineThickness
path.lineCapStyle = .round
path.move(to: line.begin)
path.addLine(to: line.end)
path.stroke()
}
override func draw(_ rect: CGRect) {
for line in finishedLines {
line.color.setStroke() // Use color by angle
stroke(line)
}
currentLineColor.setStroke()
for (_, line) in currentLines {
line.color.setStroke() // Use color by angle
stroke(line)
}
// Draw Circles
finishedLineColor.setStroke()
for circle in finishedCircles {
let path = UIBezierPath(ovalIn: circle.rect)
path.lineWidth = lineThickness
path.stroke()
}
currentLineColor.setStroke()
UIBezierPath(ovalIn: currentCircle.rect).stroke()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Log statement to see the order of events
print(#function)
if touches.count == 2 {
let touchesArray = Array(touches)
let location1 = touchesArray[0].location(in: self)
let location2 = touchesArray[1].location(in: self)
currentCircle = Circle(point1: location1, point2: location2)
} else {
for touch in touches {
let location = touch.location(in: self)
let newline = Line(begin: location, end: location)
let key = NSValue(nonretainedObject: touch)
currentLines[key] = newline
}
}
setNeedsDisplay()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// Log statement to see the order of events
print(#function)
if touches.count == 2 {
let touchesArray = Array(touches)
let location1 = touchesArray[0].location(in: self)
let location2 = touchesArray[1].location(in: self)
currentCircle = Circle(point1: location1, point2: location2)
} else {
for touch in touches {
let key = NSValue(nonretainedObject: touch)
currentLines[key]?.end = touch.location(in: self)
}
}
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// Log statement to see the order of events
print(#function)
if touches.count == 2 {
let touchesArray = Array(touches)
let location1 = touchesArray[0].location(in: self)
let location2 = touchesArray[1].location(in: self)
currentCircle = Circle(point1: location1, point2: location2)
finishedCircles.append(currentCircle)
currentCircle = Circle()
} else {
for touch in touches {
let key = NSValue(nonretainedObject: touch)
if var line = currentLines[key] {
line.end = touch.location(in: self)
finishedLines.append(line)
currentLines.removeValue(forKey: key)
}
}
}
setNeedsDisplay()
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
// Log statement to see the order of events
print(#function)
currentLines.removeAll()
currentCircle = Circle()
setNeedsDisplay()
}
}