用线条连接网格中的点

时间:2017-06-18 10:34:51

标签: swift graph grid coordinates line

当有人在这些点之间点击时,我需要放置将连接网格中每2个点的线,以便它们可以连接。我设法创建点网格:

func drawPointGrid() {

    let points: CGFloat = 5

    let cellWidth = bounds.width / points

    let cellHeight = bounds.height  / points

    for i in 0..<Int(points) {

        for j in 0..<Int(points) {

            let circleX: CGFloat = ((CGFloat(i) + 0.5) * cellWidth)

            let circleY: CGFloat =  ((CGFloat(j) + 0.5) * cellHeight)

            let centerCirclePath = UIBezierPath(ovalIn: CGRect(x: circleX, y: circleY, width: diameter, height: diameter))

            let  customlayer = CAShapeLayer()
            customlayer.path = centerCirclePath.cgPath
            customlayer.fillColor = UIColor.black.cgColor
            layer.addSublayer(customlayer)
        }
    }
}

这是我的视觉点网格:enter image description here

我设法在视图上创建线条,但只有当我点击起点并再次点击终点时,才会创建线条,但我需要在水平和垂直之间的每2个点之间创建这条线当用户在它们之间点击时:

override func draw(_ rect: CGRect) {
    drawPointGrid()
            tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showMoreActions))
            tapGestureRecognizer.numberOfTapsRequired = 1
            addGestureRecognizer(tapGestureRecognizer)
}


 // draw line from point to point that are clicked

var firstPoint: CGPoint?

var secondPoint: CGPoint?

    func showMoreActions(touch: UITapGestureRecognizer) {

        let touchPoint = touch.location(in: self)

        guard let _ = firstPoint else {

            firstPoint = touchPoint

            return
        }

        guard let _  = secondPoint else {

            secondPoint = touchPoint

            addLine(start: firstPoint!,end: secondPoint!)

            firstPoint = nil
            secondPoint = nil

            return
        }
    }


    func addLine(start: CGPoint,end:CGPoint) {

        let line = CAShapeLayer()

        let linePath = UIBezierPath()

        linePath.move(to: start)
        linePath.addLine(to: end)
        line.path = linePath.cgPath
        line.strokeColor = UIColor.black.cgColor
        line.lineWidth = 2
        line.lineJoin = kCALineJoinRound
        layer.addSublayer(line)

    }

1 个答案:

答案 0 :(得分:1)

我编写了一个名为findEndPoints的函数,它在视图中找到CGPoint的正确行终点的touchPoint坐标。我将大部分工作作为Double类型完成,以避免担心在CGFloat之间进行转换。

我还将touchGestureRecognizer的设置移动到从setup调用的init例程,因为您只需要执行一次,draw可以多次调用

class DotsView: UIView {

    let diameter = CGFloat(5)

    func setup() {
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(showMoreActions))
        tapGestureRecognizer.numberOfTapsRequired = 1
        addGestureRecognizer(tapGestureRecognizer)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func draw(_ rect: CGRect) {
        drawPointGrid()    
    }

    // draw line between points

    func showMoreActions(touch: UITapGestureRecognizer) {

        let touchPoint = touch.location(in: self)

        let (start, end) = findEndPoints(touchPt: touchPoint)
        addLine(start: start, end: end)
    }

    func addLine(start: CGPoint,end:CGPoint) {

        let line = CAShapeLayer()

        let linePath = UIBezierPath()

        linePath.move(to: start)
        linePath.addLine(to: end)
        line.path = linePath.cgPath
        line.strokeColor = UIColor.black.cgColor
        line.lineWidth = 2
        line.lineJoin = kCALineJoinRound
        layer.addSublayer(line)
    }

    func drawPointGrid() {

        let points: CGFloat = 5
        let diameter: CGFloat = 5

        let cellWidth = bounds.width / points

        let cellHeight = bounds.height  / points

        for i in 0..<Int(points) {

            for j in 0..<Int(points) {

                let circleX: CGFloat = ((CGFloat(i) + 0.5) * cellWidth)

                let circleY: CGFloat =  ((CGFloat(j) + 0.5) * cellHeight)

                let centerCirclePath = UIBezierPath(ovalIn: CGRect(x: circleX, y: circleY, width: diameter, height: diameter))

                let  customlayer = CAShapeLayer()
                customlayer.path = centerCirclePath.cgPath
                customlayer.fillColor = UIColor.black.cgColor
                layer.addSublayer(customlayer)
            }
        }
    }

    func findEndPoints(touchPt: CGPoint) -> (pt1: CGPoint, pt2: CGPoint) {
        let points = 5.0
        let cellWidth = Double(bounds.width) / points
        let cellHeight = Double(bounds.height)  / points

        // convert touch point to grid coordinates
        let gridX = Double(touchPt.x) / cellWidth - 0.5
        let gridY = Double(touchPt.y) / cellHeight - 0.5

        // snap to nearest point in the grid
        let snapX = round(gridX)
        let snapY = round(gridY)

        // find distance from touch to snap point
        let distX = abs(gridX - snapX)
        let distY = abs(gridY - snapY)

        // start second point on top of first
        var secondX = snapX
        var secondY = snapY

        if distX < distY {
            // this is a vertical line
            if secondY > gridY {
                secondY -= 1
            } else {
                secondY += 1
            }
        } else {
            // this is a horizontal line
            if secondX > gridX {
                secondX -= 1
            } else {
                secondX += 1
            }
        }

        let halfdot = Double(diameter) / 2

        // convert line points to view coordinates
        let pt1 = CGPoint(x: (snapX + 0.5) * cellWidth + halfdot, y: (snapY + 0.5) * cellHeight + halfdot)
        let pt2 = CGPoint(x: (secondX + 0.5) * cellWidth + halfdot, y: (secondY + 0.5) * cellHeight + halfdot)

        return (pt1, pt2)
    }

}

Demo running in simulator