Skip to content

Instantly share code, notes, and snippets.

@chriseidhof
Created December 8, 2011 17:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save chriseidhof/1447802 to your computer and use it in GitHub Desktop.
Save chriseidhof/1447802 to your computer and use it in GitHub Desktop.
TilingView
#import <UIKit/UIKit.h>
typedef UIImage*(^getTile)(CGFloat scale, int row, int col);
@interface TilingView : UIView {
getTile getTile;
}
- (id)initWithSize:(CGSize)size levelsOfDetail:(NSInteger)levelsOfDetail tileSize:(CGSize)tileSize;
@property (nonatomic,copy) getTile getTile;
@end
#import "TilingView.h"
#import <QuartzCore/CATiledLayer.h>
@implementation TilingView
@synthesize getTile;
+ (Class)layerClass {
return [CATiledLayer class];
}
- (id)initWithSize:(CGSize)size levelsOfDetail:(NSInteger)levelsOfDetail tileSize:(CGSize)tileSize {
self = [super initWithFrame:CGRectMake(0, 0, size.width, size.height)];
if (self) {
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
tiledLayer.levelsOfDetail = levelsOfDetail;
tiledLayer.tileSize = tileSize;
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// get the scale from the context by getting the current transform matrix, then asking for
// its "a" component, which is one of the two scale components. We could also ask for "d".
// This assumes (safely) that the view is being scaled equally in both dimensions.
CGFloat scale = CGContextGetCTM(context).a;
CATiledLayer *tiledLayer = (CATiledLayer *)[self layer];
CGSize tileSize = tiledLayer.tileSize;
// Even at scales lower than 100%, we are drawing into a rect in the coordinate system of the full
// image. One tile at 50% covers the width (in original image coordinates) of two tiles at 100%.
// So at 50% we need to stretch our tiles to double the width and height; at 25% we need to stretch
// them to quadruple the width and height; and so on.
// (Note that this means that we are drawing very blurry images as the scale gets low. At 12.5%,
// our lowest scale, we are stretching about 6 small tiles to fill the entire original image area.
// But this is okay, because the big blurry image we're drawing here will be scaled way down before
// it is displayed.)
tileSize.width /= scale;
tileSize.height /= scale;
// calculate the rows and columns of tiles that intersect the rect we have been asked to draw
int firstCol = floorf(CGRectGetMinX(rect) / tileSize.width);
int lastCol = floorf((CGRectGetMaxX(rect)-1) / tileSize.width);
int firstRow = floorf(CGRectGetMinY(rect) / tileSize.height);
int lastRow = floorf((CGRectGetMaxY(rect)-1) / tileSize.height);
for (int row = firstRow; row <= lastRow; row++) {
for (int col = firstCol; col <= lastCol; col++) {
UIImage *tile = self.getTile(1/scale,row,col);
CGRect tileRect = CGRectMake(tileSize.width * col, tileSize.height * row,
tileSize.width, tileSize.height);
// if the tile would stick outside of our bounds, we need to truncate it so as to avoid
// stretching out the partial tiles at the right and bottom edges
tileRect = CGRectIntersection(self.bounds, tileRect);
[tile drawInRect:tileRect];
}
}
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment