好吧,所以這會是一個漫長的答案。這裏是香港專業教育學院做了什麼:
伊夫編程的MEL腳本,可以讓你在Maya中繪製貝塞爾曲線,然後 - 選擇該曲線 - 運行我的腳本,它會經過曲線分析曲線的每個貝塞爾節計算每個部分的長度和曲線點/控制點的位置。一旦它計算了所有這些數據,它就會將所有數據導出到一個。其構造是這樣貝塞爾文件:
線路1:包含在整個貝塞爾路徑個人貝塞爾曲線數量 第2行:第一貝塞爾曲線 的長度... 行X:最後貝塞爾曲線的長度
X中的第一曲線點 第一曲線點的第一控制點的第一曲線點 Z位置的第一控制點的Y位置的第一控制點的位置
X中的第一曲線的位置點號 Y位置的f第一曲線點的開始步驟曲線點 Z位置
X中的第一曲線點 的第二控制點的第一曲線點 Z位置的第二控制點的Y位置的第二控制點的位置第一曲線點
...
最後一個曲線點 最後一個曲線點的第一個控制點的Y位置的第一個控制點的X位置 最後的一個控制點的Z位置曲線點
X的最後一個曲線點 最後曲線點的最後一個曲線點 Z位置的Y位置的位置
X的最後一個曲線點的第二控制點的位置 第二個控制點的Y位置最後一個曲線點
所以對於這組類的第二個控制點的最後一個曲線點 Z位置的工作,你就需要構建一個這樣的文件。
這裏有三類伊夫然後編程處理.bezier文件:
AEBezierPath:
.h文件中:
#import <Foundation/Foundation.h>
#import "AEBezierVertex.h"
#import "AEBezierLine.h"
@interface AEBezierPath : NSObject
{
NSMutableArray *vertices;
NSMutableArray *lines;
UIBezierPath *path;
}
@property (strong) NSMutableArray *vertices;
@property (strong) NSMutableArray *lines;
@property (strong) UIBezierPath *path;
-(id) initFromFile: (NSString*) file;
-(CGPoint) positionFromDistance: (float) fromDistance;
@end
.m文件:
#import "AEBezierPath.h"
CGFloat bezierInterpolation(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) {
// see also below for another way to do this, that follows the 'coefficients'
// idea, and is a little clearer
CGFloat t2 = t * t;
CGFloat t3 = t2 * t;
return a + (-a * 3 + t * (3 * a - a * t)) * t
+ (3 * b + t * (-6 * b + b * 3 * t)) * t
+ (c * 3 - c * 3 * t) * t2
+ d * t3;
}
@implementation AEBezierPath
@synthesize vertices;
@synthesize lines;
@synthesize path;
-(id) initFromFile: (NSString*) file
{
self = [super init];
if (self) {
//Init file objects for reading
NSError *fileError;
NSStringEncoding *encoding;
vertices = [[NSMutableArray alloc] init];
lines = [[NSMutableArray alloc] init];
path = [[UIBezierPath alloc] init];
//Load the specified file's contents into an NSString
NSString *fileData = [[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"testcurve" ofType:@"bezier"] usedEncoding:&encoding error:&fileError];
NSScanner *scanner = [[NSScanner alloc] initWithString:fileData];
if(fileData == nil)
{
NSLog(@"Error reading bezier path file");
}
else
{
float x;
float y;
float cx;
float cy;
float cx2;
float cy2;
float temp;
CGPoint readPoint;
CGPoint readControlIn;
CGPoint readControlOut;
int curRead = 0;
int totalSegments = 0;
float length;
[scanner scanInt:&totalSegments];
for (int s = 0; s < totalSegments; s++) {
[scanner scanFloat:&length];
AEBezierLine *newLine = [[AEBezierLine alloc] initWithLength:length];
[lines addObject:newLine];
}
AEBezierVertex *vertex;
while ([scanner isAtEnd] == 0) {
if (curRead == 0) {
[scanner scanFloat:&x];
[scanner scanFloat:&temp];
[scanner scanFloat:&y];
[scanner scanFloat:&cx2];
[scanner scanFloat:&temp];
[scanner scanFloat:&cy2];
cx = x;
cy = y;
}
else{
[scanner scanFloat:&cx];
[scanner scanFloat:&temp];
[scanner scanFloat:&cy];
[scanner scanFloat:&x];
[scanner scanFloat:&temp];
[scanner scanFloat:&y];
if ([scanner isAtEnd] == 0) {
[scanner scanFloat:&cx2];
[scanner scanFloat:&temp];
[scanner scanFloat:&cy2];
}else
{
cx = x;
cy = y;
}
}
readPoint = CGPointMake(x, y);
readControlIn = CGPointMake(cx, cy);
readControlOut = CGPointMake(cx2, cy2);
vertex = [[AEBezierVertex alloc] initWithControl:readPoint In:readControlIn Out:readControlOut];
[vertices addObject:vertex];
curRead ++;
}
for (int c = 0; c < [vertices count]-1; c++) {
//Init CGPoints for single bezier curve segment
CGPoint p1, p2, p3, p4;
//Store starting bezier point and control point
AEBezierVertex *b1 = [vertices objectAtIndex:c];
p1 = b1.control;
p2 = b1.controlOut;
//Store ending bezier point and control point
AEBezierVertex *b2 = [vertices objectAtIndex:c+1];
p3 = b2.controlIn;
p4 = b2.control;
if (c == 0) {
[path moveToPoint:p1];
}
else
{
[path addCurveToPoint:p4 controlPoint1:p2 controlPoint2:p3];
}
}
}
}
return self;
}
-(CGPoint) positionFromDistance: (float) fromDistance
{
CGPoint position;
AEBezierLine *line;
float runningLength;
int seg = 0;
for (int c = 0; c < [lines count]; c++) {
seg = c;
line = [lines objectAtIndex:c];
runningLength += line.length;
if (runningLength > fromDistance) {
break;
}
}
CGPoint p1, p2, p3, p4;
AEBezierVertex *vert1 = [vertices objectAtIndex:seg];
p1 = vert1.control;
p2 = vert1.controlOut;
//Store ending bezier point and control point
AEBezierVertex *vert2 = [vertices objectAtIndex:seg+1];
p3 = vert2.controlIn;
p4 = vert2.control;
float travelDist;
travelDist = fromDistance;
travelDist = runningLength - travelDist;
travelDist = line.length - travelDist;
float t = travelDist/line.length;
//Create a new point to represent this position
position = CGPointMake(bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x),
bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y));
return position;
}
@end
AEBe zierVertex:
h文件:
#import <Foundation/Foundation.h>
@interface AEBezierVertex : NSObject
{
CGPoint controlIn;
CGPoint controlOut;
CGPoint control;
}
@property CGPoint controlIn;
@property CGPoint controlOut;
@property CGPoint control;
-(id) initWithControl: (CGPoint) setControl In: (CGPoint) setIn Out: (CGPoint) setOut;
@end
.m文件:
#import "AEBezierVertex.h"
@implementation AEBezierVertex
@synthesize controlIn;
@synthesize controlOut;
@synthesize control;
-(id) initWithControl: (CGPoint) setControl In: (CGPoint) setIn Out: (CGPoint) setOut
{
self = [super init];
if (self) {
//Init
control = setControl;
controlIn = setIn;
controlOut = setOut;
}
return self;
}
@end
AEBezierLine:
h文件:
#import <Foundation/Foundation.h>
@interface AEBezierLine : NSObject
{
float length;
}
@property float length;
-(id) initWithLength: (float) setLength;
@end
。M檔:
#import "AEBezierLine.h"
@implementation AEBezierLine
@synthesize length;
-(id) initWithLength: (float) setLength
{
self = [super init];
if (self) {
//Init
length = setLength;
}
return self;
}
@end
如何使用:
確保你已經創建了一個.bezier文件相適應我上面所示的結構,它在你的應用程序的包。
通過實例化一個新的AEBezierPath實例:
- (ID)initFromFile:(的NSString *)文件;
這將從名爲.bezier文件*文件中讀取的所有數據,並從中構造UIBezierPath,以及儲存必要的長度信息到AEBezierPath。
查詢的AEBezierPath用於在CGPoint形式的X/Y位置,通過發送它的距離值,以從所述路徑的開始行進,使用方法:
- (CGPoint) positionFromDistance:(float)fromDistance;
此方法將首先確定該距離通過使用先前從.bezier文件中檢索每一個貝塞爾曲線段的長度位於其貝塞爾曲線段。在此之後,該方法將使用此SO問題的前一篇文章中提到的bezierInterpolation函數計算此距離處貝塞爾路徑上的x/y位置,並將其作爲CGPoint返回。
雖然它並不完美,但長距離貝塞爾曲線與較短的緊角之間的距離仍存在一些明顯的差異,但它肯定比根本不使用該系統更明顯,而是依靠百分比值來旅行沿着貝塞爾曲線。
我知道代碼當然可以優化,這只是第一次運行,以便讓所有的工作都能正常工作,但我認爲它足夠好,可以作爲現在的答案發布。
NSBezierPath是了AppKit的一部分,因此在可可觸摸不可用。你的意思是CGPath? – 2012-01-17 03:32:26
是的,它看起來像在UIKit中,你將不得不使用'CGPath',唯一的方法是通過回調和'CGPathApply'來遍歷它。對於那個很抱歉;我的可可經驗來自多年前在桌面上。 – 2012-01-17 12:40:04
謝謝。經過大量的實驗和閱讀後,我想我終於想出了一個MEL腳本,用於將一個完整的貝塞爾曲線導出到文本文件中的MEL腳本和一個可以在該文件中讀取並返回x/y的Objective C++自定義類基於距離在貝塞爾路徑上的位置。我把所有東西都包起來,並在今晚或明天發佈我的發現。 – 2012-01-18 05:51:26