Rewrite recursive block using stack and while loop.

This commit is contained in:
Mikael Sand
2017-12-28 16:55:06 +02:00
parent 77dbd3c306
commit f49eabf8e8
+21 -19
View File
@@ -135,12 +135,12 @@ void GetBezierElements(void *info, const CGPathElement *element)
} }
- (void (^)(CGFloat *, NSInteger *, NSMutableArray *, NSMutableArray *, BOOL *)) getTextProperties{ - (void (^)(CGFloat *, NSInteger *, NSMutableArray *, NSMutableArray *, BOOL *)) getTextProperties{
return ^(CGFloat *lengthP, NSInteger *lineCountP, NSMutableArray * lengths, NSMutableArray * lines, BOOL *isClosedP) { return ^(CGFloat *lengthP, NSInteger *lineCountP, NSMutableArray * lengths, NSMutableArray * lines, BOOL *isClosedP) {
__block CGPoint origin = CGPointMake (0.0, 0.0); CGPoint origin = CGPointMake (0.0, 0.0);
__block CGPoint last = CGPointMake (0.0, 0.0); CGPoint last = CGPointMake (0.0, 0.0);
__block NSInteger lineCount = 0; NSInteger lineCount = 0;
__block CGFloat length = 0; CGFloat length = 0;
__block BOOL isClosed = NO; BOOL isClosed = NO;
NSArray * elements = self.elements; NSArray * elements = self.elements;
for (BezierElement *element in elements) { for (BezierElement *element in elements) {
switch (element.elementType) switch (element.elementType)
@@ -175,34 +175,36 @@ void GetBezierElements(void *info, const CGPathElement *element)
break; break;
} }
// ok, this is the bezier for our current element // this is the bezier for our current element
CGPoint bezier[4] = { last, ctrl1, ctrl2, curveTo }; CGPoint bezier[4] = { last, ctrl1, ctrl2, curveTo };
NSValue *arr = [NSValue valueWithBytes:&bezier objCType:@encode(CGPoint[4])];
NSMutableArray *curves = [NSMutableArray arrayWithObjects:arr, nil];
NSInteger count = 1;
while (count-- > 0) {
CGPoint bez[4];
[curves[count] getValue:&bez];
[curves removeLastObject];
// define our recursive function that will
// help us split the curve up as needed
__weak void (^ __block weakFlattenCurve)(CGPoint bez[4]);
void (^ __block flattenCurve)(CGPoint bez[4]) = ^(CGPoint bez[4]){
// calculate the error rate of the curve vs // calculate the error rate of the curve vs
// a line segement between the start and end points // a line segement between the start and end points
CGPoint onCurve = bezierPointAtT(bez, .5); CGPoint onCurve = bezierPointAtT(bez, .5);
CGPoint next = bez[3]; CGPoint next = bez[3];
CGFloat error = distanceOfPointToLine(onCurve, last, next); CGFloat error = distanceOfPointToLine(onCurve, last, next);
// if the error is less than our accepted level of error, // if the error is less than our accepted level of error
// then add a line, // then add a line, else, split the curve in half
// otherwise, split the curve in half and recur
if (error <= idealFlatness) { if (error <= idealFlatness) {
addLine(&last, &next, lines, &length, lengths); addLine(&last, &next, lines, &length, lengths);
lineCount++; lineCount++;
} else { } else {
CGPoint bez1[4], bez2[4]; CGPoint bez1[4], bez2[4];
subdivideBezierAtT(bez, bez1, bez2, .5); subdivideBezierAtT(bez, bez1, bez2, .5);
weakFlattenCurve(bez1); [curves addObject:[NSValue valueWithBytes:&bez2 objCType:@encode(CGPoint[4])]];
weakFlattenCurve(bez2); [curves addObject:[NSValue valueWithBytes:&bez1 objCType:@encode(CGPoint[4])]];
count += 2;
} }
}; }
weakFlattenCurve = flattenCurve;
weakFlattenCurve(bezier);
last = curveTo; last = curveTo;
break; break;
} }