I create dashed UIBezierPath using some passed points.
let pathLayer = CAShapeLayer()
pathLayer.strokeColor = UIColor.blue.cgColor
pathLayer.lineWidth = 3.0
pathLayer.fillColor = UIColor.clear.cgColor
pathLayer.lineDashPattern = [5.0, 2.0]
pathLayer.lineDashPhase = 0
let path = PathCreator.createPath(resultPoints)
pathLayer.path = path.cgPath
I've simplified PathCreator, but totally it looks something like this
PathCreator {
func createPath(resultPoints: [CGPoint]) -> UIBezierPath {
let path = UIBezierPath()
for i in 0..<(resultPoints.count-1) {
if resultPoints[i] is CircleCenterPoint {
continue
}
if resultPoints[i] is ArcEndPoint {
path.move(to: resultPoints[i].cg())
path.addLine(to: resultPoints[i+1].cg())
}
if let arcStartPoint = resultPoints[i] as? ArcStartPoint,
let circleCenterPoint = resultPoints[i+1] as? CircleCenterPoint,
let arcEndPoint = resultPoints[i+2] as? ArcEndPoint {
path.addArc(withCenter: circleCenterPoint.cg(),
radius: circleCenterPoint.radius,
startAngle: arcStartPoint.arcStartAngle,
endAngle: arcEndPoint.arcEndAngle,
clockwise: circleCenterPoint.clockwise)
} else {
path.move(to: resultPoints[i].cg())
path.addLine(to: resultPoints[i+1].cg())
}
}
return path
}
}
But sometimes i have problems at the junction of subpaths:
What am i missing?
I didn't follow this question for a long time. But now, when I came back, I found that I actually changed my code and it seems to work quite good. Here is the code that can be posted into playground and tested. Also this code doesn't expect any special types for points and other helper things. Check it out :)
import UIKit
import PlaygroundSupport
class PathCreator {
func createPath(by points: [CGPoint]) -> CGPath {
let path = CGMutablePath()
if points.count >= 3 {
path.move(to: points.first!)
for i in 0..<(points.count - 2) {
let startPoint = points[i]
let middlePoint = points[i+1]
let endPoint = points[i+2]
let isOnOneLin = isOnOneLine(point1: startPoint, point2: middlePoint, point3: endPoint)
if isOnOneLin {
path.addLine(to: middlePoint)
if i == points.count - 3 {
path.addLine(to: endPoint)
break
}
} else {
let currentAngleValue = angleBetween(vector1: (startPoint, middlePoint), vector2: (middlePoint, endPoint))
print(currentAngleValue)
if currentAngleValue < 45 {
path.addArc(tangent1End: middlePoint, tangent2End: endPoint, radius: 1)
} else {
path.addArc(tangent1End: middlePoint, tangent2End: endPoint, radius: 10)
}
if i == points.count - 3 {
path.addLine(to: endPoint)
break
}
}
}
} else if points.count == 2 {
path.move(to: points.first!)
path.addLine(to: points[1])
}
return path
}
private func angleBetween(vector1: (CGPoint, CGPoint), vector2: (CGPoint, CGPoint)) -> CGFloat {
// vector1.0
// ^
// \
// \
// \
// \
// ---------->vector2.1
// vector1.1
// vector2.0
let dx1 = vector1.0.x - vector1.1.x
let dy1 = vector1.0.y - vector1.1.y
let vector1 = CGVector(dx: dx1, dy: dy1)
let dx2 = vector2.1.x - vector2.0.x
let dy2 = vector2.1.y - vector2.0.y
let vector2 = CGVector(dx: dx2, dy: dy2)
let scalarProduct = vector1.dx * vector2.dx + vector1.dy * vector2.dy
let vector1Module = sqrt(vector1.dx * vector1.dx + vector1.dy * vector1.dy)
let vector2Module = sqrt(vector2.dx * vector2.dx + vector2.dy * vector2.dy)
let result = acos(scalarProduct / (vector1Module * vector2Module))
return result * 180 / .pi
}
private func isOnOneLine(point1: CGPoint, point2: CGPoint, point3: CGPoint) -> Bool {
let x1 = point1.x
let x2 = point2.x
let x3 = point3.x
let y1 = point1.y
let y2 = point2.y
let y3 = point3.y
let a = (x1 - x3) * (y2 - y3)
let b = (x2 - x3) * (y1 - y3)
let area = 1 / 2 * (a - b)
if area != 0 {
return false
} else {
return true
}
}
}
let str = "hello"
let points = [CGPoint(x: 150, y: 150),
CGPoint(x: 350, y: 150),
CGPoint(x: 350, y: 350),
CGPoint(x: 550, y: 350),
CGPoint(x: 550, y: 450),
CGPoint(x: 205, y: 455),
CGPoint(x: 450, y: 650),
CGPoint(x: 185, y: 750)]
let view = UIView(frame: CGRect(x: 0, y: 0, width: 1000, height: 1000))
view.backgroundColor = .white
PlaygroundPage.current.liveView = view
let pathLayer = CAShapeLayer()
pathLayer.strokeColor = UIColor.blue.cgColor
pathLayer.lineWidth = 4.0
pathLayer.fillColor = UIColor.clear.cgColor
pathLayer.lineDashPattern = [5.0, 2.0]
pathLayer.lineDashPhase = 0
view.layer.addSublayer(pathLayer)
let pathCreator = PathCreator()
let path = pathCreator.createPath(by: points)
pathLayer.path = path
And the result is on the image:
Although the solution is probably not perfect. I think it can be helpful for someone.