【问题标题】:Drawing Smooth Curve绘制平滑曲线
【发布时间】:2017-08-03 10:10:29
【问题描述】:

通过向 Y 添加一些静态值,我有两个点 leftright,X 是左右的 AVG 我创建了第三个点 centre

之后,我使用它们之间的贝塞尔路径绘制曲线,一切正常。

在上面的曲线

现在我想再创建两个点(5 点曲线)。

centreleft 之间的一个以及 centreright 之间的一个。

尝试再次平均并使用

绘制5点曲线
  func drawFivePoint(_ startPoint: CGPoint?, leftCenterPoint: CGPoint?, toControlPoint controlPoint: CGPoint?, toRightControlPoint rightPoint: CGPoint?, toEnd endPoint: CGPoint?) {

    var arrPoints = [NSValue]()
    if startPoint != nil {
        arrPoints.append(NSValue(cgPoint: startPoint!))
    }

    if leftCenterPoint != nil && !(__CGPointEqualToPoint(leftCenterPoint!, .zero)) {
        arrPoints.append(NSValue(cgPoint: leftCenterPoint!))
    }

    if controlPoint != nil {
        arrPoints.append(NSValue(cgPoint: controlPoint!))
    }

    if rightPoint != nil && !(__CGPointEqualToPoint(rightPoint!, .zero)) {
        arrPoints.append(NSValue(cgPoint: rightPoint!))
    }

    if endPoint != nil {
        arrPoints.append(NSValue(cgPoint: endPoint!))
    }

    guard  let bezierPath = UIBezierPath.interpolateCGPoints(withHermite: arrPoints, closed: false) else {
        print("path is nil")

        return
    }
    curveSize = bezierPath.bounds
    let strokeColor = UIColor.white
    if curveLayer != nil {
        curveLayer?.removeFromSuperlayer()
        curveLayer = nil
    }
    curveLayer = CAShapeLayer()
    curveLayer?.lineWidth = 1.0 / self.zoomScale
    curveLayer?.fillColor = UIColor.clear.cgColor
    curveLayer?.path = bezierPath.cgPath
    curveLayer?.strokeColor = strokeColor.cgColor
    viewBase.layer.addSublayer(curveLayer!)
}

错误的结果

问题:如何计算点以便形状不受影响,我在曲线上得到 5 个点

【问题讨论】:

    标签: ios swift3 uibezierpath


    【解决方案1】:

    很难说,您要达到什么目标,但如果您的目标是找到属于您在第一步中定义的贝塞尔曲线的一部分的点,请先查看贝塞尔曲线是如何定义的。 Wikipedia。一般只有贝塞尔曲线的第一个和最后一个控制点也是曲线的一部分。

    要在贝塞尔曲线上找到特定 t (0..1) 的点 P(t),您可以使用 De Casteljau's Algorithm

    在您的游乐场尝试这个简单的 sn-p。我选择控制点,因此 x 线性依赖于 Bezier t 参数。 y 的形状与贝塞尔曲线的形状相同,很容易在操场上将其视为值的图表

    //: Playground - noun: a place where people can play
    
    // point
    struct Point {
        var x: Double
        var y: Double
    }
    
    // linear bezier
    func linearBezier(p1: Point, p2: Point, t: Double)->Point {
        let px = p1.x + t*(p2.x - p1.x)
        let py = p1.y + t*(p2.y - p1.y)
        return Point(x: px, y: py)
    }
    
    // quadratic bezier
    func quadraticBezier(p1: Point, p2: Point, p3: Point, t: Double)->Point {
        let p12 = linearBezier(p1: p1, p2: p2, t: t)
        let p23 = linearBezier(p1: p2, p2: p3, t: t)
        return linearBezier(p1: p12, p2: p23, t: t)
    }
    
    // cubic bezier
    func cubicBezier(p1: Point, p2: Point, p3: Point, p4: Point, t: Double)->Point {
        let p12 = linearBezier(p1: p1, p2: p2, t: t)
        let p23 = linearBezier(p1: p2, p2: p3, t: t)
        let p34 = linearBezier(p1: p3, p2: p4, t: t)
        return quadraticBezier(p1: p12, p2: p23, p3: p34, t: t)
    }
    
    let p1 = Point(x: 0.0, y: 0.0)
    let p2 = Point(x: 15.0, y: 10.0)
    let p3 = Point(x: 30.0, y: 5.0)
    
    for t in stride(from: 0.0, through: 1.0, by: 0.025) {
        let p = quadraticBezier(p1: p1, p2: p2, p3: p3, t: t)
        print(p.x, p.y)
        p.x
        p.y // see the values as a graph
    
    }
    
    let p4 = Point(x: 45.0, y: 10.0)
    
    for t in stride(from: 0.0, through: 1.0, by: 0.025) {
        let p = cubicBezier(p1: p1, p2: p2, p3: p3, p4: p4, t: t)
        print(p.x, p.y)
        p.x
        p.y // see the values as a graph
    
    }
    

    人们可以进一步做得更通用

    func bezier(controlPoints: [Point], t: Double)->[Point] {
        if controlPoints.count == 1 { return controlPoints }
        var reducedPoints: [Point] = []
        for i in 0..<(controlPoints.count - 1) {
            let p = linearBezier(p1: controlPoints[i], p2: controlPoints[i+1], t: t)
            reducedPoints.append(p)
        }
        return bezier(controlPoints: reducedPoints, t: t)
    }
    
    let points = [p1,p2,p3,p4]
    
    for t in stride(from: 0.0, through: 1.0, by: 0.0125) {
        let p = bezier(controlPoints: points, t: t)
        p.count // it is alway 1 :-)
        p[0].x
        p[0].y
    }
    

    这会给你同样的结果。函数bezier 可用于“任意”数量的控制点。考虑到根据定义,贝塞尔函数仅对区间 (0...1.0) 中的 t 有效,即使您可以计算任何区间中的值。

    【讨论】:

    • @MikeAlter 我可以,但我不确定你不会做什么。你想找到一个点,它是你的贝塞尔曲线的一部分,它的位置介于中点和第一个(控制点)之间以及中点和最后一个(控制点)之间吗?根据您的问题,我了解您已将贝塞尔曲线定义为二次贝塞尔曲线,对吗?
    • 是的,我有左右两个点,从中我创建了中间点。但现在我需要在不影响曲线的情况下再添加两个点。因此,当我绘制 5 点曲线时找到该点后,它应该像 3 点一样平滑。现在你明白我的意思了吗?
    • 好的,谢谢,我会检查并告诉你是否工作
    猜你喜欢
    • 1970-01-01
    • 2012-06-09
    • 2017-06-10
    • 2017-01-14
    • 2015-11-18
    • 2023-03-09
    • 2012-01-31
    • 2013-01-20
    • 1970-01-01
    相关资源
    最近更新 更多