ポイントのリストを取得する必要がある IBezierPath があります。
Qt
には、自分のニーズに合うpointAtPercent
という関数がありますが、Objective-C
で同等の関数を見つけることができません。
誰でもこれを行う方法を知っていますか?
あなたはこれを試すかもしれません:
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;
}
}
@モリッツ素晴らしい答え! 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)
}
}
私はあなたがこのようなことをやろうとしていたと思います:
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
私は IBezierPath上の最も近い点を見つける に関する記事を書きました。これはOPが探しているものと非常に似ています。 Swiftでデモプロジェクトも作成しました: https://github.com/andrew8712/BezierPathClosestPoint
@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)
}
}
Swift 3のFBenteの拡張機能を更新しました:
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)
}
}
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
}
})