理解 UIBezierPath 曲线机制,controlPoint 和曲线点 [英] Undestanding UIBezierPath curving mechanism, controlPoint and the curve point

查看:57
本文介绍了理解 UIBezierPath 曲线机制,controlPoint 和曲线点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 UIBezierPath 绘制一个简单的抛物线形状.我有一个 maxPoint 和一个 boundingRect,我以抛物线的宽度和拉伸为基础.
这是我绘制抛物线的函数(我在容器视图中绘制抛物线,rect 将是 container.bounds):

I'm trying to draw a simple Parabola shape using UIBezierPath. I have a maxPoint and a boundingRect of which I'm basing the width and stretch of the parabola.
Here's the function I made to draw the parabola (I draw the parabola in a container view, rect will be container.bounds):

func addParabolaWithMax(maxPoint: CGPoint, inRect boundingRect: CGRect) {
    let path = UIBezierPath()

    let p1 = CGPointMake(1, CGRectGetMaxY(boundingRect)-1)
    let p3 = CGPointMake(CGRectGetMaxX(boundingRect)-1, CGRectGetMaxY(boundingRect)-1)

    path.moveToPoint(p1)
    path.addQuadCurveToPoint(p3, controlPoint: maxPoint)

    // Drawing code
    ...
}

我的问题是,我希望我在函数中发送的 maxPoint 成为抛物线本身的实际极值点.例如,如果我发送 (CGRectGetMidX(container.bounds), 0),最大点应该在最顶部的中心.但是在这个特定点上使用这个函数时,结果是这样的:

My problem is, that I want the maxPoint that I send in the function to be the actual extreme point in the parabola itself. So for example, if I send in (CGRectGetMidX(container.bounds), 0), The maximum point should be at the top-most center. But in using this function with this particular point, this is what the result looks like:

那么这里的路径到底是做什么的呢?或者换句话说,我怎样才能从 controlPoint 到我需要的实际最大点?我已经尝试根据 boundingRect 的高度从 y 值中添加和减去不同的值,但我无法找到正确的组合,因为在不同的具有不同 y 值的点的行为不同.似乎添加了某种乘数,我该如何解决?

So what exactly the path does here? Or in other words, how can I get from the controlPoint to the actual max point that I need? I've tried adding and subtracting different values from the y value, based on the height of the boundingRect, but I couldn't quite find the right combination, as in different points with different y values it behaves differently. There seem to be some kind of multiplier being added in, how can I solve it?

推荐答案

对于可能的应用程序,adam.wulf 的解决方案很好,但它实际上并没有创建抛物线.要创建抛物线,我们需要计算给定二次曲线中点的控制点.贝塞尔路径只是数学;我们可以很容易地计算出来.我们只需要对 Bézier 函数求逆并求解 t=0.5.

For may applications adam.wulf's solution is fine, but it doesn't actually create a parabola. To create a parabola, we need to compute the control point given the midpoint of the quadratic curve. Bézier paths are just math; we can compute this quite easily. We just need to invert the Bézier function and solve it for t=0.5.

0.5(中点)的 Bézier 解在 通过三个给定点绘制二次贝塞尔曲线.

The Bézier solution at 0.5 (the midpoint) is derived nicely at Draw a quadratic Bézier curve through three given points.

2*Pc - P0/2 - P2/2

其中Pc是我们要经过的点,P0P2是终点.

Where Pc is the point we want to go through and P0 and P2 are the end points.

(计算其他点的 Bézier 不是很直观.t=0.25 处的值不是沿路径的四分之一."但幸运的是,对于我们的目的,t=0.5 与我们的直觉非常匹配二次方程上的中点".)

(Computing the Bézier at other points is not very intuitive. The value at t=0.25 is not "a quarter of the way along the path." But luckily for our purposes, t=0.5 matches quite nicely to our intuition of "the midpoint" on a quadratic.)

给定我们的解决方案,我们可以编写我们的代码.原谅翻译到 Swift 3;我的 Xcode 7.3 副本对 iOS Play 不太满意,但应该很容易转换为 2.2.

Given our solution, we can write our code. Forgive the translation to Swift 3; my copy of Xcode 7.3 isn't very happy with iOS playgrounds, but it should be easy to convert to 2.2.

func addParabolaWithMax(maxPoint: CGPoint, inRect boundingRect: CGRect) -> UIBezierPath {

    func halfPoint1D(p0: CGFloat, p2: CGFloat, control: CGFloat) -> CGFloat {
        return 2 * control - p0 / 2 - p2 / 2
    }

    let path = UIBezierPath()

    let p0 = CGPoint(x: 0, y: boundingRect.maxY)
    let p2 = CGPoint(x: boundingRect.maxX, y: boundingRect.maxY)

    let p1 = CGPoint(x: halfPoint1D(p0: p0.x, p2: p2.x, control: maxPoint.x),
                     y: halfPoint1D(p0: p0.y, p2: p2.y, control: maxPoint.y))

    path.move(to: p0)
    path.addQuadCurve(to: p2, controlPoint: p1)
    return path
}

halfPoint1D 函数是我们解决方案的一维实现.对于我们的二维CGPoint,我们只需要调用它两次.

The halfPoint1D function is the the one-dimensional implementation of our solution. For our two-dimentional CGPoint, we just have to call it twice.

如果我只能推荐一种理解贝塞尔曲线的资源,它可能是 维基百科中的构建贝塞尔曲线"部分.研究显示曲线如何产生的小动画,我觉得很有启发性.特定情况"部分也很有用.对于该主题的深入探索(我建议所有开发人员都熟悉),我喜欢 A Primer关于贝塞尔曲线.可以略读它并阅读您目前感兴趣的部分.但是对这组函数的基本理解将大大有助于消除 Core Graphics 中绘制的魔力,并使 UIBezierPath 成为工具而不是黑匣子.

If I could recommend just one resource for understanding Bézier curves, it would probably be the "Constructing Bézier curves" section from Wikipedia. Studying the little animations that show how the curves come about I find very enlightening. The "Specific Cases" section is useful as well. For a deep exploration of the topic (and one that I recommend all developers have a passing familiarity with), I like A Primer on Bézier Curves. It's ok to skim it and just read the parts that interest you at the moment. But a basic understanding of this group of functions will go a long way to removing the magic from drawing in Core Graphics and make UIBezierPath a tool rather than a black box.

这篇关于理解 UIBezierPath 曲线机制,controlPoint 和曲线点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆