Swift 虚线UIBezierPath子路径连接

Swift 虚线UIBezierPath子路径连接,swift,uibezierpath,Swift,Uibezierpath,我使用一些传递点创建虚线UIBezierPath 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 =

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

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
我简化了PathCreator,但它看起来完全像这样

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{
func createPath(结果点:[CGPoint])->UIBezierPath{
let path=UIBezierPath()

对于0中的i..由于您的CAShapeLayer是一条路径,只需设置该路径的lineJoin属性。在您的情况下,我认为kCALineJoinRound可以工作


由于您的CAShapeLayer是一条路径,只需设置该路径的lineJoin属性。在您的情况下,我认为kCALineJoinRound可以工作


仅对第一个点使用“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
    }
}
PathCreator{
func createPath(结果点:[CGPoint])->UIBezierPath{
var wMoved=假;
let path=UIBezierPath()

对于0..中的i,仅对第一个点使用“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
    }
}
PathCreator{
func createPath(结果点:[CGPoint])->UIBezierPath{
var wMoved=假;
let path=UIBezierPath()

对于0中的我,…我很长时间没有关注这个问题。但是现在,当我回来时,我发现我实际上更改了我的代码,它似乎工作得很好。下面是可以发布到游乐场并进行测试的代码。此外,此代码不需要任何特殊类型的积分和其他帮助程序。请查看:)

导入UIKit
导入PlaygroundSupport
类路径创建者{
func createPath(按点:[CGPoint])->CGPath{
let path=CGMutablePath()
如果points.count>=3{
路径。移动(到:点。第一!)
对于0..CGFloat中的i{
//矢量1.0
//     ^
//     \
//      \
//       \
//        \
//------>vector2.1
//矢量1.1
//矢量2.0
设dx1=vector1.0.x-vector1.1.x
设dy1=vector1.0.y-vector1.1.y
设vector1=CGVector(dx:dx1,dy:dy1)
设dx2=vector2.1.x-vector2.0.x
设dy2=vector2.1.y-vector2.0.y
设vector2=CGVector(dx:dx2,dy:dy2)
设scalarProduct=vector1.dx*vector2.dx+vector1.dy*vector2.dy
设vector1Module=sqrt(vector1.dx*vector1.dx+vector1.dy*vector1.dy)
设vector2Module=sqrt(vector2.dx*vector2.dx+vector2.dy*vector2.dy)
让结果=acos(标度积/(向量1模块*向量2模块))
返回结果*180/.pi
}
私有函数等非线(点1:CGPoint,点2:CGPoint,点3:CGPoint)->Bool{
设x1=point1.x
设x2=point2.x
设x3=point3.x
设y1=1.y点
设y2=2.y点
设y3=点3.y
设a=(x1-x3)*(y2-y3)
设b=(x2-x3)*(y1-y3)
设面积=1/2*(a-b)
如果面积!=0{
返回错误
}否则{
返回真值
}
}
}
让str=“你好”
设点=[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),
(x:185,y:750)]
let view=ui视图(帧:CGRect(x:0,y:0,宽度:1000,高度:1000))
view.backgroundColor=.white
PlaygroundPage.current.liveView=视图
让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(路径层)
让pathCreator=pathCreator()
let path=pathCreator.createPath(by:points)
pathLayer.path=路径
结果显示在图像上:


虽然这个解决方案可能并不完美。我认为它可能对某些人有所帮助。

我很久没有关注这个问题了。但是现在,当我回来时,我发现我实际上更改了我的代码,它似乎工作得很好。这是可以发布到游乐场并进行测试的代码。而且这段代码也不期望有任何特殊的问题点数和其他辅助对象的类型。请查看:)

导入UIKit
导入PlaygroundSupport
类路径创建者{
func createPath(按点:[CGPoint])->CGPath{
let path=CGMutablePath()
如果points.count>=3{
路径。移动(到:点。第一!)
对于0..CGFloat中的i{
//矢量1.0
//     ^
//     \
//      \
//       \
//        \
//------>vector2.1
//矢量1.1
//矢量2.0
设dx1=vector1.0.x-vector1.1.x
设dy1=vector1.0.y-vector1.1.y
设vector1=CGVector(dx:dx1,dy:dy1)
设dx2=vector2.1.x-vector2.0.x
设dy2=vector2.1.y-vector2.0.y
设vector2=CGVector(dx:dx2,dy:dy2)
设scalarProduct=vector1.dx*vector2.dx+vector1.dy*vector2.dy
设vector1Module=sqrt(vector1.dx*vector1.dx+vector1.dy*vector1.dy)
设vector2Module=sqrt(vector2.dx*vector2.dx+vector2.dy*vector2.dy)
让结果=acos(标度积/(向量1模块*向量2模块))
返回结果*180/.pi
}
私有函数等非线(点1:CGPoint,点2:CGPoint,点3:CGPoint)->Bool{
设x1=point1.x
设x2=point2.x
设x3=point3.x
设y1=1.y点
设y2=2.y点
设y3=点3.y
设a=(x1-x3)*(y2-y3)
设b=(x2-x3)*(y1-y3)
设面积=1/2*(a-b)
如果面积!=0{
返回错误
}否则{
返回真值
}
}
}
让str=“你好”
设点=[CGPoint(x:150,y:150),
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