How do I draw a cosine or sine curve in Swift?

后端 未结 2 1065
时光说笑
时光说笑 2020-12-18 14:12

I\'ve been trying to figure out how to use UIBezierPath for this project, but I don\'t know how to implement this kind of drawing. I can draw a circle and arcs and straight

相关标签:
2条回答
  • 2020-12-18 14:53

    To draw a sine wave on a UIBezierPath called path, draw a number of line segments using path.addLine(to:). The trick is to convert the angle (0 to 360) to the x coordinate of a point, and sin(x) to the y coordinate of a point.

    Here is an example:

    class SineView: UIView{
        let graphWidth: CGFloat = 0.8  // Graph is 80% of the width of the view
        let amplitude: CGFloat = 0.3   // Amplitude of sine wave is 30% of view height
    
        override func draw(_ rect: CGRect) {
            let width = rect.width
            let height = rect.height
    
            let origin = CGPoint(x: width * (1 - graphWidth) / 2, y: height * 0.50)
    
            let path = UIBezierPath()
            path.move(to: origin)
    
            for angle in stride(from: 5.0, through: 360.0, by: 5.0) {
                let x = origin.x + CGFloat(angle/360.0) * width * graphWidth
                let y = origin.y - CGFloat(sin(angle/180.0 * Double.pi)) * height * amplitude
                path.addLine(to: CGPoint(x: x, y: y))
            }
    
            UIColor.black.setStroke()
            path.stroke()
        }
    }
    
    let sineView = SineView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    sineView.backgroundColor = .white
    

    Here it is running in a Playground:


    @Rob updated this code making it @IBDesignable with @IBInspectable properties in addition to adding a periods property. Check out his answer here.

    0 讨论(0)
  • 2020-12-18 14:53

    This allows you to place a sine wave inside a rect:

        func generateWave(cycles: Int, inRect: CGRect, startAngleInDegrees: CGFloat = 0) -> UIBezierPath {
            let dx = inRect.size.width
            let amplitude = inRect.size.height
            let scaleXToDegrees = 1 / (inRect.size.width / 360.0 / CGFloat(cycles))
            let path = UIBezierPath()
            for x in stride(from: 0, to: dx + 5, by: 5) {
                let y = sin(D2R(startAngleInDegrees + x * scaleXToDegrees)) * amplitude / 2
                let p = CGPoint(x: x + inRect.origin.x, y: y + inRect.origin.y)
                if x == 0 {
                    path.move(to: p)
                } else {
                    path.addLine(to: p)
                }
            }
            return path
        }
    

    To animate:

        override func update(_ currentTime: TimeInterval) {
            shape?.removeFromParent()
    
            let path = generateWave(cycles: 7, inRect: targetRect, startAngleInDegrees: currentStartAngle)
            shape = SKShapeNode(path: path.cgPath)
            shape!.strokeColor = .red
            shape!.lineWidth = 1
            self.addChild(shape!)
            currentStartAngle += 5
        }
    
    0 讨论(0)
提交回复
热议问题