不可靠的UIBezierpath曲线机制,控制点和曲线点

我试图使用UIBezierPath绘制一个简单的抛物线形状。 我有一个maxPoint和一个boundingRect我正在基础的抛物线的宽度和拉伸。
这里是我绘制抛物线的函数(我在容器视图中绘制抛物线, rect将是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中发送的maxPoint成为抛物线本身的实际极点。 因此,例如,如果我发送(CGRectGetMidX(container.bounds), 0) ,最高点应该在最顶端的中心。 但是在使用这个特定点的函数时,结果是这样的:

在这里输入图像说明

那么究竟是什么path呢? 或换句话说,我怎样才能从controlPoint点到我需要的实际最大点? 我试着根据boundingRect的高度来添加和减去y值中的不同值,但是我找不到正确的组合,因为在具有不同y值的不同点中,它的行为有所不同。 似乎有一些乘法器被join,我该如何解决?

对于可能的应用程序adam.wulf的解决scheme是好的,但它实际上并没有创build一个抛物线。 要创build抛物线,我们需要计算给定二次曲线中点的控制点。 贝塞尔path只是math; 我们可以很容易地计算出来。 我们只需要颠倒Bézier函数,并解决t = 0.5。

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

 2*Pc - P0/2 - P2/2 

Pc是我们想要经过的点, P0P2是终点。

(计算Bézier在其他点不是很直观,t = 0.25的值不是“四分之一的path”。但幸运的是,对于我们的目的,t = 0.5很好地匹配我们的直觉“中点“在一个二次方。”

鉴于我们的解决scheme,我们可以写我们的代码 原谅翻译Swift 3; 我的Xcode 7.3的副本对于iOS游戏机并不是很满意,但应该很容易转换为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函数是我们解决scheme的一维实现。 对于我们的二维CGPoint ,我们只需要调用两次。

如果我只能推荐一种理解Bézier曲线的资源,那很可能是维基百科的“构造Bézier曲线”部分。 研究显示曲线如何产生的小animation我觉得非常有启发性。 “具体案例”部分也很有用。 为了深入探讨这个话题(我build议所有的开发人员都熟悉这个话题),我喜欢BézierCurves的入门书 。 可以浏览一下,只读一下目前感兴趣的部分。 但是对这组函数的基本了解将会大大减lessCore Graphics绘制的魔法,并使UIBezierPath成为一个工具,而不是一个黑盒子。

诀窍是将曲线分成两部分,以便控制曲线通过哪些点。 正如Eduardo的回答所提到的,控制点处理切线,并且终点在曲线上。 这可以让你从左下angular到右上angular,然后从右上angular到右下angular:

 let p1 = CGPointMake(0,self.view.frame.height/2) let p3 = CGPointMake(self.view.frame.width,self.view.frame.height/2) let ctrlRight = CGPointMake(self.view.frame.width,0) let ctrlLeft = CGPointZero let bezierPath = UIBezierPath() bezierPath.moveToPoint(p1) bezierPath.addCurveToPoint(maxPoint, controlPoint1: p1, controlPoint2: ctrlLeft) bezierPath.addCurveToPoint(p3, controlPoint1: ctrlRight, controlPoint2: p3) UIColor.blackColor().setStroke() bezierPath.lineWidth = 1 bezierPath.stroke() 

让path= UIBezierPath()

  let p1 = CGPointMake(0,self.view.frame.height/2) let p3 = CGPointMake(self.view.frame.width,self.view.frame.height/2) path.moveToPoint(p1) path.addQuadCurveToPoint(p3, controlPoint: CGPoint(x: self.view.frame.width/2, y: -self.view.frame.height/2)) let line = CAShapeLayer() line.path = path.CGPath; line.strokeColor = UIColor.blackColor().CGColor line.fillColor = UIColor.redColor().CGColor view.layer.addSublayer(line) 

这是原因: https : //cdn.tutsplus.com/mobile/authors/legacy/Akiel%20Khan/2012/10/15/bezier.png你应该考虑切线的概念