不可靠的UIBezierPath曲线机制,控制点和曲线点 [英] Undestanding UIBezierPath curving mechanism, controlPoint and the curve point

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

问题描述

我试图用 UIBezierPath 绘制一个简单的抛物线形状。我有一个 maxPoint 和一个 boundingRect ,其中我基于抛物线的宽度和拉伸。

这是我绘制抛物线的函数(我在容器视图中绘制抛物线, rect 将会是 container.bounds <
$ b

  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)

//绘图代码
...
}

我的问题是,我想要 maxPoint (CGRectGetMidX(container.bounds),0),最高点应该位于最顶端的中心。但是在使用这个特定点的函数时,结果如下所示:



那么这条道路究竟在做什么呢?或者换句话说,我如何从 controlPoint 获得我需要的实际最大点?我试着根据 boundingRect 的高度从 y 值中加入和减去不同的值,但是我无法完全找到正确的组合,因为在具有不同 y 值的不同点上,它的行为有所不同。似乎有某种倍增器被添加进来,我该如何解决它?

解决方案

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

<0.5>Bézier解0.5(中点)很好地在。 p>

  2 * Pc  -  P0 / 2  -  P2 / 2 

其中 Pc 是我们想要经过的点, P0 P2 是终点。



(计算Bézier在其他点不是很直观。 t = 0.25并不是沿路的四分之一。但幸运的是,对于我们的目的而言,t = 0.5与我们对二次方的中点的直觉相当吻合。)

考虑到我们的解决方案,我们可以编写我们的代码。原谅翻译Swift 3;我的Xcode 7.3版本对iOS游戏机并不满意,但应该很容易转换为2.2。

(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)
让p2 = CGPoint(x:boundingRect.maxX,y:boundingRect.maxY)

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

path.move(to:p0)
path.addQuadCurve(到:p2,controlPoint:p1)
返回路径
}

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



如果我可以推荐一个资源为了理解Bézier曲线,它可能是构造Bézier曲线部分来自维基百科。研究显示曲线如何产生的小动画我觉得非常有启发性。 具体案例部分也很有用。为了深入探讨这个话题(我建议所有开发者都熟悉这个话题),我喜欢 A Bézier曲线入门。可以浏览它,只需阅读目前您感兴趣的部分即可。但是对这组函数的基本了解将大大减少Core Graphics绘制中的魔法,并使UIBezierPath成为一个工具而不是黑盒子。


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
    ...
}

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:

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?

解决方案

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.

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

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

(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.)

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
}

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

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曲线机制,控制点和曲线点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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