2016-08-02 1 views
2

UIBezierPathを使用して単純な放物線形状を描こうとしています。私はmaxPointboundingRectを持っていますが、そのうちの私は放物線の幅と伸びを基準にしています。
ここで私は放物線を描くために作られた機能だ(私はコンテナビューで放物線を描くが、rectcontainer.boundsになります):UIBezierPathカーブ機構、controlPoint、カーブポイント

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)で送信すると、最大ポイントは最上部の中央にあるはずです。正確にパスがここで何をするかそう

enter image description here

:しかし、この特定の時点で、この機能を使用するには、これは結果がどのように見えるのですか?つまり、controlPointから、私が必要とする実際の最大ポイントまでどうすればいいですか?私はboundingRectの高さに基づいて、yの値から別の値を加算して減算しようとしましたが、別の点で異なったyの値とは違ったふうに正しい組み合わせを見つけることができませんでした。何らかの乗数が追加されているようですが、どうすれば解決できますか?

答えて

4

は結構ですが、それは実際に放物線を作成しません。放物線を作成するには、二次曲線の中点を指定して制御点を計算する必要があります。ベジエパスは数学だけです。これを非常に簡単に計算することができます。ベジエ関数を逆にして、t = 0.5で解くだけです。

ベジエ溶液0.5(中点)は、Draw a quadratic Bézier curve through three given pointsにきれいに誘導されます。 Pcたちが通って、P0P2行きたいポイントです

2*Pc - P0/2 - P2/2 

は、エンドポイントです。

(ベジエの計算は他の点では直感的ではありませんが、t = 0.25の値は "経路の途中の四分の一"ではありませんが、幸いなことにt = 0.5は直感によく似ています

私たちの解決策が与えられれば、コードを書くことができます。 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関数は、私たちのソリューションの1次元実装です。私たちの2次元のCGPointについては、それを2回呼び出すだけです。

ベジエ曲線を理解するためのリソースが1つだけ推奨される場合は、おそらくウィキペディアの"Constructing Bézier curves"セクションになります。どのようにカーブが来るかを示す小さなアニメーションを勉強すると、私は非常に啓発されています。 「特定のケース」セクションも同様に便利です。トピックの深い探究のために(そして、すべての開発者に親しみを持っていることをお勧めします)、私はA Primer on Bézier Curvesが好きです。それをスキミングし、ちょうどあなたが興味のある部分を読むのは大丈夫です。しかし、このグループの機能を基本的に理解することは、Core Graphicsの描画から魔法を取り除き、UIBezierPathをブラックボックスではなくツールにするという大きな道のりになります。

+0

一連の点にある滑らかな曲線を作成することを目標とする場合、Catmull-Romスプラインがベジェよりも優れた選択肢になることに注意してください曲線。 Bezierよりも計算コストが高く、すべてのコントロールポイントを通過するカーブを作成します。しかし、ベジェ曲線のように、あまりにも急にカーブすると、Catmull-Romスプラインで「キンク」を得ることができます。 Erica Sadunの優れたiOSデベロッパー向けクックブックの書籍には、興味があればCatmull-Romスプラインの作業コードがあります。 –

+0

Catmull-Romスプラインについての不満は、最初と最後の点が含まれていないことです。そのため、「正しい場所」に余分な拡張点を追加する必要があります。求心的なC-Rスプラインを使用すると、ねじれを防ぐことができます(これは私の通常の好みです)。 –

0

LETパス= 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あなたはトリックはあなたがコントロールすることができるように、2つの部分に曲線を分割することです正接コンセプト

+0

実際にそのコードを使用すると、最大のポイントが上に表示されますが、下端の左端から始まり下端右端で終わるように放物線が必要です。なぜ放物線を半分の高さで開始して終了しますか?私は 'controlPoint'で' -container.bounds.height'を指定することで、この特定のポイントをどのようにしたいのかを管理しましたが、すべてのタイプのポイントでは機能しません。したがって、コントロールポイントのy値に追加される動的値または乗数が必要です。これは私が見つけようとしているところです – Eilon

1

を検討する必要があります曲線が通過する点を指します。エドゥアルドの答えで述べたように、コントロールポイントは接線を処理し、エンドポイントは曲線上にあります。これは、あなたは下から曲線はその後、上部中央から右下に、上部中央に残っていることができます:5月アプリケーションのadam.wulfのソリューションについては

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() 
+0

アプローチに同意しましたが、 'p1'と' p3'で '/ 2'を削除すると、カーブは要求とはるかに緊密に一致します。しかし、これは放物線ではありません。なぜなら、クワッドカーブではなくキュービックカーブを追加しているからです。 (ただし、実際の目標であるかもしれない「放物線状」にすることができます) –