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)
立方贝塞尔曲线由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值.