在路径上找到一个点

Old*_*ame 6 algorithm objective-c cgpath uibezierpath

我有一个应用程序在a中绘制bezier曲线UIView,我需要在为Y设置值时找到X相交.首先,据我所知,没有办法直接找到一个点,UIBezierPath但你可以找到一点CGPath.

首先,如果我"抚摸"我UIBezierPath(就像我在我的代码中所做的那样)这实际上是在创建一个CGPath还是我需要采取进一步的步骤来实际将其转换为CGPath

其次,我想通过提供Y的值来找到在X处相交的曲线.

我的目的是当用户移动滑块(分别向左或向右移动曲线)时,自动计算给定Y值的X.

我的开始显示.

我的开始显示

当我调整滑块时会发生什么.

当我调整滑块时会发生什么

我希望我的显示器看起来像.

我希望我的显示器看起来像

GraphView.h

#import <UIKit/UIKit.h>

@interface GraphView : UIView
{
    float adjust;
    int x;
    int y;
}

- (IBAction)sliderChanged:(id)sender;
- (IBAction)yChanged:(id)sender;

@property (weak, nonatomic) IBOutlet UISlider *sliderValue;
@property (weak, nonatomic) IBOutlet UITextField *xValue;
@property (weak, nonatomic) IBOutlet UITextField *yValue;

@end
Run Code Online (Sandbox Code Playgroud)

GraphView.m

#import "GraphView.h"

@interface GraphView ()


@end

@implementation GraphView

@synthesize sliderValue, xValue, yValue;

- (id)initWithCoder:(NSCoder *)graphView
{
    self = [super initWithCoder:graphView];
    if (self) {
        adjust = 194;
        y = 100;
    }
    return self;
}

- (IBAction)sliderChanged:(id)sender
{
    adjust = sliderValue.value;
    // Calcualtion of the X Value and setting of xValue.text textField goes here
    [self setNeedsDisplay];
}

- (IBAction)yChanged:(id)sender
{
    y = yValue.text.intValue;
    [self setNeedsDisplay];
    [self resignFirstResponder];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch * touch = [touches anyObject];
    if(touch.phase == UITouchPhaseBegan) {
        y = yValue.text.intValue;
        [self setNeedsDisplay];
        [yValue resignFirstResponder];
    }
}

- (void)drawRect:(CGRect)rect
{
    UIBezierPath *lines = [[UIBezierPath alloc] init];
    [lines moveToPoint:CGPointMake(0, y)];
    [lines addLineToPoint:CGPointMake(200, y)];
    [lines addLineToPoint:CGPointMake(200, 280)];
    [lines setLineWidth:1];
    [[UIColor redColor] setStroke];
    float dashPattern[] = {2, 2};
    [lines setLineDash:dashPattern count:2 phase:0.0];
    [lines stroke];

    UIBezierPath *curve = [[UIBezierPath alloc] init];
    [curve moveToPoint:CGPointMake(0, 280)];
    [curve addCurveToPoint:CGPointMake(280, 0) controlPoint1:CGPointMake(adjust, 280) controlPoint2:CGPointMake(adjust, 0)];
    [curve setLineWidth:2];
    [[UIColor blueColor] setStroke];
    [curve stroke];

}

@end
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 8

立方贝塞尔曲线由4个点定义

P0 = (x0, y0) = start point,
P1 = (x1, y1) = first control point,
P2 = (x2, y2) = second control point,
P3 = (x3, y3) = end point,
Run Code Online (Sandbox Code Playgroud)

并包括所有要点

x(t) = (1-t)^3 * x0 + 3*t*(1-t)^2 * x1 + 3*t^2*(1-t) * x2 + t^3 * x3
y(t) = (1-t)^3 * y0 + 3*t*(1-t)^2 * y1 + 3*t^2*(1-t) * y2 + t^3 * y3
Run Code Online (Sandbox Code Playgroud)

t从哪里0开始1.

因此,要计算给定Y值的X,首先必须计算一个参数值T,使得0 <= T <= 1

 Y = (1-T)^3 * y0 + 3*T*(1-T)^2 * y1 + 3*T^2*(1-T) * y2 + T^3 * y3      (1)
Run Code Online (Sandbox Code Playgroud)

然后使用计算X坐标

 X = (1-T)^3 * x0 + 3*T*(1-T)^2 * x1 + 3*T^2*(1-T) * x2 + T^3 * x3      (2)
Run Code Online (Sandbox Code Playgroud)

所以你必须求解三次方程(1)T并将值代入(2).

立方方程可以明确地解决(参见例如http://en.wikipedia.org/wiki/Cubic_function)或迭代地解决(例如使用http://en.wikipedia.org/wiki/Bisection_method).

通常,三次方程可以具有多达三种不同的解.在你的具体案例中,我们有

P0 = (0, 280), P1 = (adjust, 280), P3 = (adjust, 0), P4 = (280, 0)
Run Code Online (Sandbox Code Playgroud)

等式(1)变为

Y = (1-T)^3 * 280 + 3*T*(1-T)^2 * 280
Run Code Online (Sandbox Code Playgroud)

这简化为

Y/280 = 1 - 3*T^2 + 2*T^3    (3)
Run Code Online (Sandbox Code Playgroud)

(3)的右边是T区间内的严格递减函数[0, 1],因此不难看出(3)只有一个解0 <= Y <= 280.将该溶液代入(2)得到所需的X值.