虚线UIBezierPath子路径连接

时间:2017-01-17 17:18:50

标签: swift uibezierpath

我使用一些传递点创建了虚线UIBezierPath。

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
    }
}

我简化了PathCreator,但完全看起来像这样

select rank(window(*)) from StockEvent.win:length(10)

但有时我在子路径的交界处遇到问题:

path example

我缺少什么?

3 个答案:

答案 0 :(得分:2)

仅在第一点使用“ path.move”。对于其余几点,请使用“ path.addLine”。

因此解决方案如下:

PathCreator {
    func createPath(resultPoints: [CGPoint]) -> UIBezierPath {
        var wMoved = false;
        let path = UIBezierPath()
        for i in 0..<(resultPoints.count-1) {
            if resultPoints[i] is CircleCenterPoint {
                continue
            }
            if resultPoints[i] is ArcEndPoint {
                if wMoved {
                    path.addLine(to: resultPoints[i].cg())
                } else {
                    path.move(to: resultPoints[i].cg())
                    wMoved = true
                }
                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 {
                if wMoved {
                    path.addLine(to: resultPoints[i].cg())
                } else {
                    path.move(to: resultPoints[i].cg())
                    wMoved = true
                }
                path.addLine(to: resultPoints[i+1].cg())
            }
        }
        return path
    }
}

答案 1 :(得分:0)

由于您的CAShapeLayer是单个路径,因此请设置路径的lineJoin属性。在你的情况下,我认为kCALineJoinRound将起作用。 Possible line join values.

pathLayer.lineJoin = kCALineJoinRound

答案 2 :(得分:0)

我很久没有关注这个问题了。但是现在,当我回来时,我发现我实际上在更改代码,并且看起来工作得很好。这是可以发布到操场上并经过测试的代码。同样,此代码不期望任何特殊类型的要点和其他帮助对象。签出:)

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

结果在图像上:

enter image description here

尽管解决方案可能并不完美。我认为这对某人可能会有帮助。