微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 Swift 中绘制正弦曲线

如何解决在 Swift 中绘制正弦曲线

在我的 Swift 项目中,我应该使用 Pan Gesture 检测用户的移动并绘制这样的正弦曲线。是否有任何图书馆可以绘制这个或我可以通过任何方式实现它??

这个正弦曲线也应该有控制点,我可以在那里动态地重塑它。

Sinusoidal Curve

解决方法

您可以使用点、直线或曲线段绘制任何数学函数。正弦曲线特别容易,因为您可以非常轻松地确定极端值和其他感兴趣的点来构建此类曲线的近似值。

一种非常直接的绘制方式是这样的:

class SinusoidalCurveView: UIView {
    
    var resolution: CGFloat? = nil { didSet { setNeedsDisplay() } }
    var function: (n: CGFloat,verticalScale: CGFloat,horizontalScale: CGFloat) = (100.0,30.0,30.0) { didSet { setNeedsDisplay() } }
    
    private func solveY(_ x: CGFloat) -> CGFloat {
        let n = function.n
        let h = function.verticalScale
        let m = function.horizontalScale
        return h*sin(x/m) + n
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        let resolutionStep: CGFloat = {
            if let resolution = resolution {
                return rect.width/resolution
            } else {
                return 1.0/self.layer.contentsScale
            }
        }()
        
        var x: CGFloat = 0.0
        let path = UIBezierPath()
        path.move(to: CGPoint(x: x,y: solveY(x)))
        while x < rect.width {
            x += resolutionStep
            path.addLine(to: CGPoint(x: x,y: solveY(x)))
        }
        
        path.stroke()
    }
    
}

它可以使用一些改进和额外的参数等等。但我相信它应该说明这种方法。

就控制点而言,您也应该没有问题。由于您可以确定所有极端情况和其他兴趣点,因此您只需检测平移手势的起始位置并相应地管理行为。

例如,这使用平移手势处理垂直缩放的更改:

enum PointOfInterest {
    case extreme(at: CGPoint)
    case zero(at: CGPoint)
}

private func getClosestPointOfInterest(to point: CGPoint) -> PointOfInterest? {
    // Do the math here
    return nil
}

private var selectedPointOfInterest: PointOfInterest?
@objc private func onPan(_ sender: UIGestureRecognizer) {
    switch sender.state {
    case .began:
        if let pointOfInterest = getClosestPointOfInterest(to: sender.location(in: sender.view)) {
            // Got a point that is near enough
            selectedPointOfInterest = pointOfInterest
        } else {
            selectedPointOfInterest = nil
            // Invalidate events
            sender.isEnabled = false
            sender.isEnabled = true
        }
    case .changed:
        guard let selectedPointOfInterest = selectedPointOfInterest else { return }
        switch selectedPointOfInterest {
        case .extreme(let initialLocation):
            let newLocation = sender.location(in: sender.view)
            let offset = newLocation.y - sinusoidalCurveView.function.n
            sinusoidalCurveView.function = (sinusoidalCurveView.function.n,offset,sinusoidalCurveView.function.horizontalScale)
        default:
            break
        }
    default:
        selectedPointOfInterest = nil
    }
}

没有添加控制点,所以在平底锅上什么也没有发生。但是,在您向视图中添加平移手势识别器后,已经添加此代码将使事情起作用。

private func getClosestPointOfInterest(to point: CGPoint) -> PointOfInterest? {
    // Do the math here
    return .extreme(at: .zero)
}

从这里开始,事情应该很简单了。这有点工作,但应该没什么大不了的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。