I am using CATiledLayer to draw map tiles and when zooming it, I start to see some artifacts, which I guess, are caused by precision problem.
I scale my CATiledLayer up to 2^18 (262'144x), the artifacts start to appear at about 15'000x
I thought CoreAnimation would be smart enough to handle those large scales, but apparently not.
Before I start writing my tile engine implementation from scratch to handle this, I was wondering if you had any suggestion.
This is how I setup my layer:
self.tiledLayer.tileSize = CGSizeMake(256, 256);
self.tiledLayer.levelsOfDetail = 1;
self.tiledLayer.levelsOfDetailBias = 10000;
My example, drawing code is really simple:
- (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)context
{
CGRect rect = CGContextGetClipBoundingBox(context);
CGContextSetFillColorWithColor(context, [NSColor colorWithCalibratedRed:((CGFloat)rand() / (CGFloat)RAND_MAX) green:((CGFloat)rand() / (CGFloat)RAND_MAX) blue:0 alpha:1].CGColor);
CGContextFillRect(context, rect);
}
This is how I set the scale on the layer:
CGAffineTransform t = CGAffineTransformIdentity;
CGFloat scale = pow(2, self.zoomLevel); // self.zoomLevel ranges from 0 to 18
t = CGAffineTransformScale(t, scale, scale);
NSLog(@"%g", scale);
self.tiledLayer.affineTransform = t;
NOTE: I discovered that the artifacts appears only "far from the origin" of the layer. If I look the tiles near the origin, they are not deformed, if I look far from the origin (screenshot if from the center) it get worse.
Here is an example of the artifacts I see:
Ok, I just found a very simple solution while cooking, just modulo the scale to something reasonable and loop with a hint to the drawing code. So for example when the scale hits 64, reset it to 1 and give 64 to the drawing code, so when the scale is 2, the drawing code will pick tiles for the zoom at 128.
I will try this tomorrow and see how I can work with CATiledLayer caching mechanism to ensure a smooth experience.
EDIT: I just took a few minutes to try this method, but I effectively got a problem with caching, as when I set the scale back to a preview value, drawInContext isn't called again. I tried calling setNeedsDisplay, but it kills the smoothness of the zoom and makes everything super slow.
EDIT 2: After tinkering with this solution for a few hours, I was unable to get a smooth zooming and panning. I tried a simplistic approach drawing my tiles in a single NSView drawRect:, it works, but would require significant work to be smooth and fast. So I'm keeping this question open to suggestions.
EDIT 3: I finally wrote my own implementation from scratch that doesn't have this bug.