【问题标题】:How do I draw a cosine or sine curve in Swift?如何在 Swift 中绘制余弦或正弦曲线?
【发布时间】:2016-10-25 02:13:30
【问题描述】:

我一直在试图弄清楚如何在这个项目中使用 UIBezierPath,但我不知道如何实现这种绘图。我可以画一个圆、圆弧和直线,但我对这个感到很迷茫。感谢帮助

【问题讨论】:

    标签: swift uibezierpath


    【解决方案1】:

    要在名为pathUIBezierPath 上绘制正弦波,请使用path.addLine(to:) 绘制多个线段。诀窍是将角度(0360)转换为点的x 坐标,将sin(x) 转换为点的y 坐标。

    这是一个例子:

    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
    

    它在 Playground 中运行:


    @Rob 更新了此代码,使其在 @IBDesignable 中添加了 @IBInspectable 属性,并添加了 periods 属性。看看他的回答here

    【讨论】:

    • 您如何将其制作成动画正弦波?
    • @PetrusTheron - 要设置动画,请在要设置动画的属性上添加didSet 属性观察器,在didSet 中调用self.setNeedsDisplay()。使用计时器每 1/30 秒左右更新一次属性。要使正弦波滚动,请添加一个角度 offset 属性,然后将高度计算更改为:let y = origin.y - CGFloat(sin((angle + offset)/180.0 * Double.pi)) * height * amplitude
    • 我没有在操场上运行这个示例,而是通过在设置背景颜色的行之后添加self.view.addSubview(sineView) 从应用程序 ViewController 运行这个示例
    • @vacawama 这个图形宽度实际上是波的频率。我说的对吗?
    【解决方案2】:

    这允许您在矩形内放置一个正弦波:

        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
        }
    

    动画:

        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
        }
    

    【讨论】:

    • 这个例子需要 SpriteKit。几个变量和函数 D2R 未声明
    猜你喜欢
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-06
    • 2023-01-25
    • 2020-06-04
    相关资源
    最近更新 更多