Comment get une list de points d'un UIBezierPath?

J'ai un UIBezierPath dont j'ai besoin de prendre une list de points.

Dans Qt il y a une fonction appelée pointAtPercent qui correspond à mes besoins mais je ne trouve rien d'équivalent en Objective-C .

Est-ce que quelqu'un sait comment faire ça?

Vous pourriez essayer ceci:

 UIBezierPath *yourPath; // Assume this has some points in it CGPath yourCGPath = yourPath.CGPath; NSMutableArray *bezierPoints = [NSMutableArray array]; CGPathApply(yourCGPath, bezierPoints, MyCGPathApplierFunc); 

La fonction d'applicateur de path sera transmise à tour de rôle à chacun des éléments de path du path.
Découvrez CGPathApplierFunction et CGPathApply .

La fonction d'applicateur de path peut ressembler à ceci

 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; } } 

@Moritz Bonne réponse! Pour find une solution similaire à Swift, je suis tombé sur une approche dans ce post et j'ai implémenté une extension CGPath comme celle-ci pour get les points du path:

 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) } } 

Je pense que vous essayiez de faire quelque chose comme ça:

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

C'est ma méthode pour imprimer toutes les valeurs de cette fonction.

 - (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); } } 

Et la sortie est:

 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 

J'ai écrit un article pour find le point le plus proche sur UIBezierPath , qui est très similaire à ce que le PO search. J'ai également créé un projet de démonstration sur Swift: https://github.com/andrew8712/BezierPathClosestPoint

J'ai modifié le post de @FBente pour travailler avec 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) } } 

Mise à jour de l'extension de FBente pour 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) } }