swift - 用线连接网格中的点

标签 swift graph grid coordinates line

我需要放置一条线,当有人在这些点之间点击时连接网格中的每两个点,这样它们就可以连接起来。我设法创建了点网格:

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

我设法在 View 上画线,但只有当我单击起点并再次单击终点时,才能创建线,但我需要在水平和垂直的每 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)

    }

最佳答案

我编写了一个名为 findEndPoints 的函数,它可以在 View 中给定一个 touchPoint 的情况下找到正确线端点的 CGPoint 坐标。我将大部分工作作为 Double 类型完成,这样就不必担心它与 CGFloat 之间的转换。

我还将 touchGestureRecognizer 的设置移动到从 init 调用的 setup 例程,因为您只想执行一次并 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

关于swift - 用线连接网格中的点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44614090/

相关文章:

java - Java数据结构无向图

java - 邻接矩阵删除顶点

javascript - 保持正确的位置标签x轴jquery flot

grid - 在 wx.grid 中输入关键行为

ios - 为什么 Obj-C 实例有 1 个保留计数刚创建?

xcode - 我可以使用 Xcode 7 在 Swift 1(适用于 iOS 7 和 8)中编写应用程序吗?

android - 有谁知道如何让 map 在 Activity 组内工作?

css - Susy - 获取流体容器中的静态跨度宽度

json - 无法解码 token : The token ###

swift - 泛型类和继承