答案 0 :(得分:64)
你可以试试这个:
UIBezierPath *yourPath; // Assume this has some points in it
CGPath yourCGPath = yourPath.CGPath;
NSMutableArray *bezierPoints = [NSMutableArray array];
CGPathApply(yourCGPath, bezierPoints, MyCGPathApplierFunc);
路径应用程序功能将依次传递每个路径的路径元素 查看CGPathApplierFunction和CGPathApply。
路径应用程序功能可能看起来像这样
void MyCGPathApplierFunc (void *info, const CGPathElement *element) {
NSMutableArray *bezierPoints = (NSMutableArray *)info;
CGPoint *points = element->points;
CGPathElementType type = element->type;
switch(type) {
case kCGPathElementMoveToPoint: // contains 1 point
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
break;
case kCGPathElementAddLineToPoint: // contains 1 point
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
break;
case kCGPathElementAddQuadCurveToPoint: // contains 2 points
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
[bezierPoints addObject:[NSValue valueWithCGPoint:points[1]]];
break;
case kCGPathElementAddCurveToPoint: // contains 3 points
[bezierPoints addObject:[NSValue valueWithCGPoint:points[0]]];
[bezierPoints addObject:[NSValue valueWithCGPoint:points[1]]];
[bezierPoints addObject:[NSValue valueWithCGPoint:points[2]]];
break;
case kCGPathElementCloseSubpath: // contains no point
break;
}
}
答案 1 :(得分:14)
@Moritz很棒的回答!为了找到类似Swift的解决方案,我在这个post中搜索了一个方法并实现了这样的CGPath扩展来从路径中获取点:
extension CGPath {
func points() -> [CGPoint]
{
var bezierPoints = [CGPoint]()
self.forEach({ (element: CGPathElement) in
let numberOfPoints: Int = {
switch element.type {
case .MoveToPoint, .AddLineToPoint: // contains 1 point
return 1
case .AddQuadCurveToPoint: // contains 2 points
return 2
case .AddCurveToPoint: // contains 3 points
return 3
case .CloseSubpath:
return 0
}
}()
for index in 0..<numberOfPoints {
let point = element.points[index]
bezierPoints.append(point)
}
})
return bezierPoints
}
func forEach(@noescape body: @convention(block) (CGPathElement) -> Void) {
typealias Body = @convention(block) (CGPathElement) -> Void
func callback(info: UnsafeMutablePointer<Void>, element: UnsafePointer<CGPathElement>) {
let body = unsafeBitCast(info, Body.self)
body(element.memory)
}
let unsafeBody = unsafeBitCast(body, UnsafeMutablePointer<Void>.self)
CGPathApply(self, unsafeBody, callback)
}
}
答案 2 :(得分:6)
我认为你试图做这样的事情:
https://math.stackexchange.com/questions/26846/is-there-an-explicit-form-for-cubic-bézier-curves
y=u0(1−x^3)+3u1(1−x^2)x+3u2(1−x)x^2+u3x^3
这是我打印该功能的所有值的方法。
- (void)logXY {
float u0 = 0;
float u1 = 0.05;
float u2 = 0.25;
float u3 = 1;
for (float x = 0; x <= 10.0; x = x + 0.1) {
float y = u0 * (1 - x * x * x) + 3 * u1 * (1 - x * x) * x + 3 * u2 * (1 - x) * x * x + u3 * x * x * x;
NSLog(@"x: %f\ty: %f", x, y);
}
}
输出是:
x: 0.000000 y: 0.000000
x: 0.100000 y: 0.022600
x: 0.200000 y: 0.060800
x: 0.300000 y: 0.115200
x: 0.400000 y: 0.186400
x: 0.500000 y: 0.275000
x: 0.600000 y: 0.381600
x: 0.700000 y: 0.506800
x: 0.800000 y: 0.651200
x: 0.900000 y: 0.815400
x: 1.000000 y: 1.000000
x: 1.100000 y: 1.205600
x: 1.200000 y: 1.432800
x: 1.300000 y: 1.682200
x: 1.400000 y: 1.954401
x: 1.500000 y: 2.250001
x: 1.600000 y: 2.569601
x: 1.700000 y: 2.913801
x: 1.800000 y: 3.283201
x: 1.900000 y: 3.678401
x: 2.000000 y: 4.100001
x: 2.100000 y: 4.548601
x: 2.200000 y: 5.024800
x: 2.300000 y: 5.529200
x: 2.400000 y: 6.062399
x: 2.500000 y: 6.625000
x: 2.600000 y: 7.217597
x: 2.700000 y: 7.840797
x: 2.799999 y: 8.495197
x: 2.899999 y: 9.181394
x: 2.999999 y: 9.899996
答案 3 :(得分:2)
我写了一篇关于finding the closest point on UIBezierPath的文章,这与OP正在寻找的非常相似。我还在Swift上创建了一个演示项目:https://github.com/andrew8712/BezierPathClosestPoint
答案 4 :(得分:2)
我修改了@FBente帖子以使用swift 3
extension CGPath {
func points() -> [CGPoint]
{
var bezierPoints = [CGPoint]()
self.forEach(body: { (element: CGPathElement) in
let numberOfPoints: Int = {
switch element.type {
case .moveToPoint, .addLineToPoint: // contains 1 point
return 1
case .addQuadCurveToPoint: // contains 2 points
return 2
case .addCurveToPoint: // contains 3 points
return 3
case .closeSubpath:
return 0
}
}()
for index in 0..<numberOfPoints {
let point = element.points[index]
bezierPoints.append(point)
}
})
return bezierPoints
}
func forEach( body: @convention(block) (CGPathElement) -> Void) {
typealias Body = @convention(block) (CGPathElement) -> Void
func callback(info: UnsafeMutableRawPointer, element: UnsafePointer<CGPathElement>) {
let body = unsafeBitCast(info, to: Body.self)
body(element.pointee)
}
let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self)
self.apply(info: unsafeBody, function: callback as! CGPathApplierFunction)
}
}
答案 5 :(得分:0)
更新了FBente对Swift 3的扩展名:
extension CGPath {
func points() -> [CGPoint]
{
var bezierPoints = [CGPoint]()
self.forEach({ (element: CGPathElement) in
let numberOfPoints: Int = {
switch element.type {
case .moveToPoint, .addLineToPoint: // contains 1 point
return 1
case .addQuadCurveToPoint: // contains 2 points
return 2
case .addCurveToPoint: // contains 3 points
return 3
case .closeSubpath:
return 0
}
}()
for index in 0..<numberOfPoints {
let point = element.points[index]
bezierPoints.append(point)
}
})
return bezierPoints
}
func forEach(_ body: @convention(block) (CGPathElement) -> Void) {
typealias Body = @convention(block) (CGPathElement) -> Void
func callback(info: UnsafeMutableRawPointer, element: UnsafePointer<CGPathElement>) {
let body = unsafeBitCast(info, to: Body.self)
body(element.pointee)
}
let unsafeBody = unsafeBitCast(body, to: UnsafeMutableRawPointer.self)
self.apply(info: unsafeBody, function: callback as! CGPathApplierFunction)
}
}
答案 6 :(得分:0)
swift 4.0:
var bezierPoints = NSMutableArray()
yourPath.apply(info: &bezierPoints, function: { info, element in
guard let resultingPoints = info?.assumingMemoryBound(to: NSMutableArray.self) else {
return
}
let points = element.pointee.points
let type = element.pointee.type
switch type {
case .moveToPoint:
resultingPoints.pointee.add([NSNumber(value: Float(points[0].x)), NSNumber(value: Float(points[0].y))])
case .addLineToPoint:
resultingPoints.pointee.add([NSNumber(value: Float(points[0].x)), NSNumber(value: Float(points[0].y))])
case .addQuadCurveToPoint:
resultingPoints.pointee.add([NSNumber(value: Float(points[0].x)), NSNumber(value: Float(points[0].y))])
resultingPoints.pointee.add([NSNumber(value: Float(points[1].x)), NSNumber(value: Float(points[1].y))])
case .addCurveToPoint:
resultingPoints.pointee.add([NSNumber(value: Float(points[0].x)), NSNumber(value: Float(points[0].y))])
resultingPoints.pointee.add([NSNumber(value: Float(points[1].x)), NSNumber(value: Float(points[1].y))])
resultingPoints.pointee.add([NSNumber(value: Float(points[2].x)), NSNumber(value: Float(points[2].y))])
case .closeSubpath:
break
}
})