2016-08-02 2 views
2

UIBezierPath을 사용하여 간단한 포물선 모양을 그려야합니다. 나는 maxPointboundingRect을 가지고 있는데 그 중 제가 포물선의 너비와 신축을 기준으로 삼고 있습니다.
여기가 포물선을 그리는 만든 기능이다 (I 컨테이너보기에서 포물선을 그리는는 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 값에서 다른 값을 빼내려고 시도했지만 다른 점이 다르기 때문에 다른 조합으로 서로 다른 동작을합니다. 어떤 종류의 곱셈기가 추가 된 것 같습니다. 어떻게 해결할 수 있습니까?

답변

4

을 adam.wulf의 솔루션은 괜찮 월 응용 프로그램,하지만 실제로 포물선을 만들지 않습니다. 포물선을 생성하려면, 2 차 곡선의 중간 점에서 제어점을 계산해야합니다. 베 지어 경로는 수학에 불과합니다. 우리는 이것을 아주 쉽게 계산할 수 있습니다. 베 지어 함수를 반전시켜 t = 0.5로 풀면됩니다.

베 지어 솔루션 0.5 (중점)는 Draw a quadratic Bézier curve through three given points에서 잘 유도됩니다. Pc

2*Pc - P0/2 - P2/2 

우리가 마지막 포인트는 통해 P0P2 가고 싶은 포인트입니다.

(다른 점에서 베 지어를 계산하는 것은 그리 직관적이지 않습니다 .t = 0.25의 값은 "경로의 길의 1/4"이 아닙니다. 그러나 운 좋게도 t = 0.5는 우리의 직감에 매우 잘 일치합니다 "midpoint"를 2 차로 표현한 것입니다.)

우리의 솔루션이 주어지면 코드를 작성할 수 있습니다. 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 기능 우리 용액의 일차원 구현이다.우리의 2 차원적인 CGPoint의 경우 두 번 호출해야합니다.

베 지어 곡선을 이해하기 위해 하나의 리소스 만 권장 할 수 있다면 위키피디아의 "Constructing Bézier curves" 섹션 일 수 있습니다. 커브가 어떻게 생겨나는지 보여주는 작은 애니메이션을 공부하면 아주 계몽 적입니다. "특정 사례"섹션도 유용합니다. 주제를 깊이 탐구하기 위해 (그리고 모든 개발자에게 익숙 함을 전하는 개발자에게 권장합니다.) A Primer on Bézier Curves을 좋아합니다. 그것을 훑어보고 지금 당신에게 관심있는 부분을 읽는 것이 좋습니다. 그러나이 기능 그룹에 대한 기본적인 이해는 Core Graphics에서 그림을 그리는 마법을 제거하고 UIBezierPath를 블랙 박스가 아닌 도구로 만드는 데 큰 도움이 될 것입니다.

+0

목표가 일련의 점에있는 부드러운 곡선을 만드는 것이라면 Catmull-Rom 스플라인이 베 지어보다 더 나은 선택 일 수 있습니다 곡선. 그들은 베 지어보다 계산 상 더 비쌉니다. 모든 제어점을 통과하는 곡선을 만듭니다. 그러나 베 지어 커브처럼 너무 커브를 그리면 Catmull-Rom 스플라인에서 "꼬임"을 얻을 수 있습니다. Erica Sadun의 우수한 iOS 개발자의 요리 책 서적에는 Catmull-Rom 스플라인에 대한 작업 코드가 있습니다. –

+0

Catmull-Rom 스플라인에 대한 하나의 좌절감은 첫 번째 점과 마지막 점이 포함되어 있지 않기 때문에 "올바른 위치"에 추가 확장 점을 추가해야한다는 것입니다. 구심력 C-R 스플라인을 사용하면 꼬임을 피할 수 있습니다. –

0

하자 경로 = 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 당신이 접선 개념 트릭 당신이 제어 할 수 있도록 두 개의 조각으로 곡선을 분할하는 것입니다

+0

실제로 코드를 사용하면 최대 점이 맨 위에 오게되지만 맨 아래 왼쪽부터 시작하여 맨 아래 오른쪽에서 끝날 때까지 포물선이 필요합니다. 높이의 반으로 포물선을 시작하고 끝내는 이유는 무엇입니까? 나는 'controlPoint'에서'-container.bounds.height'을 사용하여이 특정 포인트를 원하는 방식으로 만들었지 만 모든 유형의 포인트에서 작동하지 않는다는 것이 그 점입니다. 따라서 제어점의 y 값에 더해지는 동적 값이나 승수가 있어야합니다. 이것은 내가 찾으려는 것입니다 – Eilon

1

을 고려해야한다 곡선이 통과하는 점을 가리 킵니다. Eduardo의 대답에서 언급했듯이 제어점은 접선을 처리하고 종점은 곡선 위에 있습니다. 이것은 당신이 바닥에서 곡선이 다음 중앙 상단에서 오른쪽 하단, 상단 중앙에 남아있을 수 있습니다 :

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'를 제거하면 커브가 요청과 훨씬 더 밀접하게 일치 할 것입니다. 그러나 이것은 포물선이 아닙니다. 왜냐하면 여러분은 쿼드 곡선이 아닌 3 차 곡선을 추가하기 때문입니다. (그러나 실제 목표가 될 수있는 "포물선 모양"으로 만들 수 있습니다.) –