Swift UIBezierPath Different Coordinate Starting Point

|▌冷眼眸甩不掉的悲伤 提交于 2020-02-06 07:41:20

问题


I have an UIBezierPath arrow that I found here. My goal is to pass the function "addArrows" a list of player arrays and draw arrows between them. This code works great... except when I call addArrows(gameScene: scene, from: [1, 3], to: [1, 3]) or addArrows(gameScene: scene, from: [2, 3], to: [2, 3]). This should create arrows between players 1 and 3 (1st call), and 2 and 3 (2nd call). However, it is creating arrows between players 2 and 3 (1st call) and players 1 and 3 (2nd call). I have added print statements to the "addArrows" function and it is returning the locations (located in my constants struct) of players correctly. It works if it is fed an array of [1, 2, 3] and [1, 2, 3] or [1, 2] and [1, 2]. What exactly is happening here?

struct K {
static let stackPositions = [
    // Player 1
    1: CGPoint(x: (_screenW / 2), y: cardHeightConstant + cardHeight + 60),
    // Player 2
    2: CGPoint(x: (_screenW / 2), y: _screenH - cardHeightConstant - cardHeight - 60),
    // Player 3
    3: CGPoint(x: 30, y: _screenH / 2),
    // Player 4
    4: CGPoint(x: _screenW - 30, y: _screenH / 2)
]
}

// https://stackoverflow.com/questions/48625763/how-to-draw-a-directional-arrow-head
extension UIBezierPath {
func addArrow(start: CGPoint, end: CGPoint, pointerLineLength: CGFloat, arrowAngle: CGFloat) {
    self.move(to: start)
    self.addLine(to: end)

    let startEndAngle = atan((end.y - start.y) / (end.x - start.x)) + ((end.x - start.x) < 0 ? CGFloat(Double.pi) : 0)
    let arrowLine1 = CGPoint(x: end.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle + arrowAngle), y: end.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle + arrowAngle))
    let arrowLine2 = CGPoint(x: end.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle - arrowAngle), y: end.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle - arrowAngle))

    self.addLine(to: arrowLine1)
    self.move(to: end)
    self.addLine(to: arrowLine2)
}
}

func addArrows(gameScene: GameScene, from: [Int], to: [Int]) {

for fromPlayerNumber in from {
    for toPlayerNumber in to {
        guard let fromPos = K.stackPositions[fromPlayerNumber] else { return }
        guard let toPos = K.stackPositions[toPlayerNumber] else { return }
        if fromPos == toPos { continue }

        print(fromPos.y)
        print(toPos.y)
        let arrow = UIBezierPath()
        arrow.addArrow(start: CGPoint(x: fromPos.x, y: fromPos.y),
                       end: CGPoint(x: toPos.x, y: toPos.y),
                       pointerLineLength: 7,
                       arrowAngle: CGFloat(Double.pi / 4))

        let arrowLayer = CAShapeLayer()
        arrowLayer.strokeColor = UIColor.black.cgColor
        arrowLayer.lineWidth = 1.0
        arrowLayer.path = arrow.cgPath
        arrowLayer.fillColor = UIColor.clear.cgColor
        arrowLayer.lineJoin = CAShapeLayerLineJoin.round
        arrowLayer.lineCap = CAShapeLayerLineCap.round
        gameScene.view?.layer.addSublayer(arrowLayer)
    }
}

}

Edit

I have forced the "From" location to be CGPoint(x: 0, y: 0). This is starting the arrow in the top left portion of the screen rather than all my other references which are starting in the bottom left of the screen. So, it appears that the arrow is using a different anchor point than the other objects in my scene. I tried setting arrowLayer.anchorPoint = CGPoint(x: 0, y: 0), but that didn't work...


回答1:


Here, the coordinate system was referencing the top left of the screen as opposed to the bottom left. In order to fix this, all I needed to do was "invert" the y coordinates of the start and ending y points. Fix below:

    func addArrow(start: CGPoint, end: CGPoint, pointerLineLength: CGFloat, arrowAngle: CGFloat) {

        // Adjust Y Directions Here! // 
        let adjStart = CGPoint(x: start.x, y: K._screenH - start.y)
        let adjEnd = CGPoint(x: end.x, y: K._screenH - end.y)

        self.move(to: adjStart)
        self.addLine(to: adjEnd)

        let startEndAngle = atan((adjEnd.y - adjStart.y) / (adjEnd.x - adjStart.x)) + ((adjEnd.x - adjStart.x) < 0 ? CGFloat(Double.pi) : 0)
        let arrowLine1 = CGPoint(x: adjEnd.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle + arrowAngle),
                                 y: adjEnd.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle + arrowAngle))
        let arrowLine2 = CGPoint(x: adjEnd.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle - arrowAngle),
                                 y: adjEnd.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle - arrowAngle))

        self.addLine(to: arrowLine1)
        self.move(to: adjEnd)
        self.addLine(to: arrowLine2)
    }


来源:https://stackoverflow.com/questions/59791882/swift-uibezierpath-different-coordinate-starting-point

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!