Advertisement
starkrights

Untitled

Jul 10th, 2024
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Based on code from Erica Sadun
  2.  
  3. #import "UIBezierPath+Smoothing.h"
  4.  
  5. void getPointsFromBezier(void *info, const CGPathElement *element);
  6. NSArray *pointsFromBezierPath(UIBezierPath *bpath);
  7.  
  8.  
  9. #define VALUE(_INDEX_) [NSValue valueWithCGPoint:points[_INDEX_]]
  10. #define POINT(_INDEX_) [(NSValue *)[points objectAtIndex:_INDEX_] CGPointValue]
  11.  
  12. @implementation UIBezierPath (Smoothing)
  13.  
  14. // Get points from Bezier Curve
  15. void getPointsFromBezier(void *info, const CGPathElement *element)
  16. {
  17.     NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;    
  18.  
  19.     // Retrieve the path element type and its points
  20.     CGPathElementType type = element->type;
  21.     CGPoint *points = element->points;
  22.  
  23.     // Add the points if they're available (per type)
  24.     if (type != kCGPathElementCloseSubpath)
  25.     {
  26.         [bezierPoints addObject:VALUE(0)];
  27.         if ((type != kCGPathElementAddLineToPoint) &&
  28.             (type != kCGPathElementMoveToPoint))
  29.             [bezierPoints addObject:VALUE(1)];
  30.     }    
  31.     if (type == kCGPathElementAddCurveToPoint)
  32.         [bezierPoints addObject:VALUE(2)];
  33. }
  34.  
  35. NSArray *pointsFromBezierPath(UIBezierPath *bpath)
  36. {
  37.     NSMutableArray *points = [NSMutableArray array];
  38.     CGPathApply(bpath.CGPath, (__bridge void *)points, getPointsFromBezier);
  39.     return points;
  40. }
  41.  
  42. - (UIBezierPath*)smoothedPathWithGranularity:(NSInteger)granularity;
  43. {
  44.     NSMutableArray *points = [pointsFromBezierPath(self) mutableCopy];
  45.  
  46.     if (points.count < 4) return [self copy];
  47.  
  48.     // Add control points to make the math make sense
  49.     [points insertObject:[points objectAtIndex:0] atIndex:0];
  50.     [points addObject:[points lastObject]];
  51.  
  52.     UIBezierPath *smoothedPath = [self copy];
  53.     [smoothedPath removeAllPoints];
  54.  
  55.     [smoothedPath moveToPoint:POINT(0)];
  56.  
  57.     for (NSUInteger index = 1; index < points.count - 2; index++)
  58.     {
  59.         CGPoint p0 = POINT(index - 1);
  60.         CGPoint p1 = POINT(index);
  61.         CGPoint p2 = POINT(index + 1);
  62.         CGPoint p3 = POINT(index + 2);
  63.  
  64.         // now add n points starting at p1 + dx/dy up until p2 using Catmull-Rom splines
  65.         for (int i = 1; i < granularity; i++)
  66.         {
  67.             float t = (float) i * (1.0f / (float) granularity);
  68.             float tt = t * t;
  69.             float ttt = tt * t;
  70.  
  71.             CGPoint pi; // intermediate point
  72.             pi.x = 0.5 * (2*p1.x+(p2.x-p0.x)*t + (2*p0.x-5*p1.x+4*p2.x-p3.x)*tt + (3*p1.x-p0.x-3*p2.x+p3.x)*ttt);
  73.             pi.y = 0.5 * (2*p1.y+(p2.y-p0.y)*t + (2*p0.y-5*p1.y+4*p2.y-p3.y)*tt + (3*p1.y-p0.y-3*p2.y+p3.y)*ttt);
  74.             [smoothedPath addLineToPoint:pi];
  75.         }
  76.  
  77.         // Now add p2
  78.         [smoothedPath addLineToPoint:p2];
  79.     }
  80.  
  81.     // finish by adding the last point
  82.     [smoothedPath addLineToPoint:POINT(points.count - 1)];
  83.  
  84.     return smoothedPath;
  85. }
  86.  
  87.  
  88. @end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement