Reputation: 3079
For an app I am creating, I am using a UIBezierPath
to store a path. The problem is that this path continually increases in length, and at a point, the app lags and becomes jerky. Because the path is continually increasing in length, I am constantly redrawing the view 100 times a second (if there is a better way to do this, please let me know). At a certain point, the app just becomes extremely jerky. I think it is because it takes too long to stroke the path.
You can see in my drawRect
method that the graphics are translated. Very little of the path is on the screen, so is there a way to only stroke the part of the path that is visible? That is what I thought I was doing with the CGContextClip
method, but it had no noticeable improvement.
- (void)drawRect:(CGRect)rect {
CGContextRef myContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(myContext, 0, yTranslation);
[[UIColor whiteColor] setStroke];
[bPath addLineToPoint:currentPoint];
[bPath setLineWidth:lineWidth];
CGContextClip(myContext);
[bPath stroke];
}
Thank you.
Upvotes: 2
Views: 934
Reputation: 437532
A couple of thoughts:
IMHO, you shouldn't be adding data points at a regular interval at all. You should be adding data points if and only if there are new data points to be added (e.g. touchesMoved
or gesture recognizer gets called with UIGestureStateChanged
). This reduces the number of points in bezier and defers the point at which performance problems impose themselves upon you. The process should be driven by the touch events, not a timer.
If some of your drawing is off screen, you can probably speed it up by checking to see if either of the points falls within the visible portion of the view (e.g CGRectContainsPoint
). You should probably check for intersections of line segments with the CGRect
(as it's theoretically possible for neither the start nor ends to be inside the visible rectangle, but for the line segment between them to intersect the rectangle).
You can also design this process so that it determines which segments are visible only when the view port moves. This can save you from needing to constantly iterate through a very large array.
At some point, there are diminishing returns of drawing individual paths versus a bitmap image, even just for the visible portion. Sometimes it's useful to render old paths as an image, and then draw new paths over that snapshot rather than redrawing the whole path every time. For example, I've used approach where when I'm starting a new gesture, I snapshot old image and only draw new gesture on top of that.
Upvotes: 1
Reputation: 11209
Caching is a possible solution: Draw the curve once on an in memory image with transparent background. Update this image only when the curve changes. Overlay this cached image on whatever you are drawing on. It should be cheaper in processing power.
The other possibility is to remove the unneeded points from the bezier curve after determining which ones will affect the current view, then render the resulting bezier curve.
Upvotes: 1