Authored by Joseph G

Readded source

Showing 58 changed files with 4169 additions and 0 deletions

Too many changes to show.

To preserve performance only 58 of 58+ files are displayed.

<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.02">
<data>
<int key="IBDocument.SystemTarget">528</int>
<string key="IBDocument.SystemVersion">9E17</string>
<string key="IBDocument.InterfaceBuilderVersion">672</string>
<string key="IBDocument.AppKitVersion">949.33</string>
<string key="IBDocument.HIToolboxVersion">352.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="12"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBProxyObject" id="841351856">
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
</object>
<object class="IBProxyObject" id="427554174">
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
</object>
<object class="IBUICustomObject" id="664661524"/>
<object class="IBUIViewController" id="943309135">
<string key="IBUINibName">MapViewViewController</string>
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
</object>
<object class="IBUIWindow" id="117978783">
<reference key="NSNextResponder"/>
<int key="NSvFlags">292</int>
<string key="NSFrameSize">{320, 480}</string>
<reference key="NSSuperview"/>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">1</int>
<bytes key="NSRGB">MSAxIDEAA</bytes>
</object>
<bool key="IBUIOpaque">NO</bool>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
<bool key="IBUIVisibleAtLaunch">YES</bool>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">delegate</string>
<reference key="source" ref="841351856"/>
<reference key="destination" ref="664661524"/>
</object>
<int key="connectionID">4</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">viewController</string>
<reference key="source" ref="664661524"/>
<reference key="destination" ref="943309135"/>
</object>
<int key="connectionID">11</int>
</object>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">window</string>
<reference key="source" ref="664661524"/>
<reference key="destination" ref="117978783"/>
</object>
<int key="connectionID">14</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<object class="NSArray" key="object" id="957960031">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="841351856"/>
<reference key="parent" ref="957960031"/>
<string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">3</int>
<reference key="object" ref="664661524"/>
<reference key="parent" ref="957960031"/>
<string key="objectName">MapView App Delegate</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="427554174"/>
<reference key="parent" ref="957960031"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">10</int>
<reference key="object" ref="943309135"/>
<reference key="parent" ref="957960031"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">12</int>
<reference key="object" ref="117978783"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="parent" ref="957960031"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.CustomClassName</string>
<string>-2.CustomClassName</string>
<string>10.CustomClassName</string>
<string>10.IBEditorWindowLastContentRect</string>
<string>10.IBPluginDependency</string>
<string>12.IBEditorWindowLastContentRect</string>
<string>12.IBPluginDependency</string>
<string>3.CustomClassName</string>
<string>3.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>UIApplication</string>
<string>UIResponder</string>
<string>MapViewViewController</string>
<string>{{579, 209}, {320, 480}}</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>{{522, 321}, {320, 480}}</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
<string>MapViewAppDelegate</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">15</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">MapViewAppDelegate</string>
<string key="superclassName">NSObject</string>
<object class="NSMutableDictionary" key="outlets">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>viewController</string>
<string>window</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>MapViewViewController</string>
<string>UIWindow</string>
</object>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">Classes/MapViewAppDelegate.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MapViewAppDelegate</string>
<string key="superclassName">NSObject</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">MapViewViewController</string>
<string key="superclassName">UIViewController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">Classes/MapViewViewController.h</string>
</object>
</object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.LastKnownRelativeProjectPath">MapView.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
</data>
</archive>
... ...
//
// MapViewAppDelegate.h
// MapView
//
// Created by Joseph Gentle on 17/09/08.
// Copyright __MyCompanyName__ 2008. All rights reserved.
//
#import <UIKit/UIKit.h>
@class MapViewViewController;
@interface MapViewAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MapViewViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet MapViewViewController *viewController;
@end
... ...
//
// MapViewAppDelegate.m
// MapView
//
// Created by Joseph Gentle on 17/09/08.
// Copyright __MyCompanyName__ 2008. All rights reserved.
//
#import "MapViewAppDelegate.h"
#import "MapViewViewController.h"
#import "RMMapView.h"
@implementation MapViewAppDelegate
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Make sure it doesn't strip mapview.
[RMMapView class];
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end
... ...
//
// MapViewViewController.h
// MapView
//
// Created by Joseph Gentle on 17/09/08.
// Copyright __MyCompanyName__ 2008. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface MapViewViewController : UIViewController {
}
@end
... ...
//
// MapViewViewController.m
// MapView
//
// Created by Joseph Gentle on 17/09/08.
// Copyright __MyCompanyName__ 2008. All rights reserved.
//
#import "MapViewViewController.h"
@implementation MapViewViewController
/*
// Override initWithNibName:bundle: to load the view using a nib file then perform additional customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[super dealloc];
}
@end
... ...
<?xml version="1.0" encoding="UTF-8"?>
<archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="7.02">
<data>
<int key="IBDocument.SystemTarget">528</int>
<string key="IBDocument.SystemVersion">9E17</string>
<string key="IBDocument.InterfaceBuilderVersion">672</string>
<string key="IBDocument.AppKitVersion">949.33</string>
<string key="IBDocument.HIToolboxVersion">352.00</string>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</object>
<object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBProxyObject" id="372490531">
<string key="IBProxiedObjectIdentifier">IBFilesOwner</string>
</object>
<object class="IBProxyObject" id="843779117">
<string key="IBProxiedObjectIdentifier">IBFirstResponder</string>
</object>
<object class="IBUIView" id="774585933">
<nil key="NSNextResponder"/>
<int key="NSvFlags">274</int>
<string key="NSFrameSize">{320, 460}</string>
<object class="NSColor" key="IBUIBackgroundColor">
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC43NQA</bytes>
<object class="NSColorSpace" key="NSCustomColorSpace">
<int key="NSID">2</int>
</object>
</object>
<bool key="IBUIClearsContextBeforeDrawing">NO</bool>
<object class="IBUISimulatedStatusBarMetrics" key="IBUISimulatedStatusBarMetrics"/>
</object>
</object>
<object class="IBObjectContainer" key="IBDocument.Objects">
<object class="NSMutableArray" key="connectionRecords">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBConnectionRecord">
<object class="IBCocoaTouchOutletConnection" key="connection">
<string key="label">view</string>
<reference key="source" ref="372490531"/>
<reference key="destination" ref="774585933"/>
</object>
<int key="connectionID">7</int>
</object>
</object>
<object class="IBMutableOrderedSet" key="objectRecords">
<object class="NSArray" key="orderedObjects">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBObjectRecord">
<int key="objectID">0</int>
<object class="NSArray" key="object" id="360949347">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<reference key="children" ref="1000"/>
<nil key="parent"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">-1</int>
<reference key="object" ref="372490531"/>
<reference key="parent" ref="360949347"/>
<string type="base64-UTF8" key="objectName">RmlsZSdzIE93bmVyA</string>
</object>
<object class="IBObjectRecord">
<int key="objectID">-2</int>
<reference key="object" ref="843779117"/>
<reference key="parent" ref="360949347"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">6</int>
<reference key="object" ref="774585933"/>
<reference key="parent" ref="360949347"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSMutableArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>-1.CustomClassName</string>
<string>-2.CustomClassName</string>
<string>6.CustomClassName</string>
<string>6.IBEditorWindowLastContentRect</string>
<string>6.IBPluginDependency</string>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
<string>MapViewViewController</string>
<string>UIResponder</string>
<string>RMMapView</string>
<string>{{534, 446}, {320, 480}}</string>
<string>com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
</object>
</object>
<object class="NSMutableDictionary" key="unlocalizedProperties">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="activeLocalization"/>
<object class="NSMutableDictionary" key="localizations">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSArray" key="dict.sortedKeys">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
<object class="NSMutableArray" key="dict.values">
<bool key="EncodedWithXMLCoder">YES</bool>
</object>
</object>
<nil key="sourceID"/>
<int key="maxID">7</int>
</object>
<object class="IBClassDescriber" key="IBDocument.Classes">
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="IBPartialClassDescription">
<string key="className">MapViewViewController</string>
<string key="superclassName">UIViewController</string>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBProjectSource</string>
<string key="minorKey">Classes/MapViewViewController.h</string>
</object>
</object>
<object class="IBPartialClassDescription">
<string key="className">RMMapView</string>
<string key="superclassName">UIView</string>
<object class="NSMutableDictionary" key="outlets">
<string key="NS.key.0">tileSource</string>
<string key="NS.object.0">id</string>
</object>
<object class="IBClassDescriptionSource" key="sourceIdentifier">
<string key="majorKey">IBUserSource</string>
<string key="minorKey"/>
</object>
</object>
</object>
</object>
<int key="IBDocument.localizationMode">0</int>
<string key="IBDocument.LastKnownRelativeProjectPath">MapView.xcodeproj</string>
<int key="IBDocument.defaultPropertyAccessControl">3</int>
</data>
</archive>
... ...
//
// main.m
// MapView
//
// Created by Joseph Gentle on 17/09/08.
// Copyright __MyCompanyName__ 2008. All rights reserved.
//
#import <UIKit/UIKit.h>
int main(int argc, char *argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}
... ...
//
// CoreAnimationRenderer.h
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMapRenderer.h"
@class RMLayeredTileLoader;
@interface RMCoreAnimationRenderer : RMMapRenderer {
// CALayer *layer;
RMLayeredTileLoader *tileLoader;
}
@end
... ...
//
// CoreAnimationRenderer.m
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMCoreAnimationRenderer.h"
#import "RMMapView.h"
#import <QuartzCore/QuartzCore.h>
#import "RMLayeredTileLoader.h"
#import "RMMathUtils.h"
#import "RMLayerToScreenProjection.h"
@implementation RMCoreAnimationRenderer
- (id) initWithView: (RMMapView *)_view
{
RMScreenProjection *_proj = [[RMScreenProjection alloc] initWithBounds:[_view bounds]];
//[[LayerToScreenProjection alloc] initWithBounds:[_view bounds] InLayer:[_view layer]];
if (![super initWithView:_view ProjectingIn:_proj])
return nil;
// tileLayer.position = CGPointMake(0.0f,0.0f);
// tileLayer.transform = CATransform3DIdentity;
// tileLayer.bounds = [view bounds];
tileLoader = [[RMLayeredTileLoader alloc] initForScreen:screenProjection FromImageSource:[view tileSource]];
/*
layer = [CAScrollLayer layer];
layer.anchorPoint = CGPointMake(0.0f, 0.0f);
layer.frame = [view bounds];
*/
// [layer addSublayer:sublayer];
[view.layer addSublayer:[tileLoader layer]];
return self;
}
-(void)mapImageLoaded: (NSNotification*)notification
{
}
-(void) recalculateImageSet
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.0f]
forKey:kCATransactionAnimationDuration];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[tileLoader assemble];
[CATransaction commit];
}
-(void) moveToMercator: (RMMercatorPoint) point
{
[tileLoader clearLoadedBounds];
[super moveToMercator:point];
}
-(void) moveToLatLong: (CLLocationCoordinate2D) point
{
[tileLoader clearLoadedBounds];
[super moveToLatLong:point];
}
- (void)moveBy: (CGSize) delta
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.0f]
forKey:kCATransactionAnimationDuration];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[super moveBy:delta];
[tileLoader moveBy:delta];
[CATransaction commit];
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.0f]
forKey:kCATransactionAnimationDuration];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
[super zoomByFactor:zoomFactor Near:center];
[tileLoader zoomByFactor:zoomFactor Near:center];
[CATransaction commit];
}
@end
... ...
//
// FileCache.h
// Images
//
// Created by Joseph Gentle on 31/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTileCache.h"
@interface RMDiskCache : NSObject<RMTileCache>
{
}
@end
... ...
//
// FileCache.m
// Images
//
// Created by Joseph Gentle on 31/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMDiskCache.h"
@implementation RMDiskCache
-(RMTileImage*) cachedImage:(RMTile)tile
{
return nil;
}
-(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
{
}
@end
... ...
//
// FileTileImage.h
// RouteMe
//
// Created by Joseph Gentle on 2/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTileImage.h"
@interface RMFileTileImage : RMTileImage {
}
-(id)initWithTile: (RMTile) _tile FromFile: (NSString*) filename;
@end
... ...
//
// FileTileImage.m
// RouteMe
//
// Created by Joseph Gentle on 2/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMFileTileImage.h"
@implementation RMFileTileImage
-(id)initWithTile: (RMTile) _tile FromFile: (NSString*) file
{
if (![super initWithTile:_tile])
return nil;
// From the example in the documentation... :-/
/* CFURLRef url = CFURLCreateWithFileSystemPath (NULL, (CFStringRef)file, kCFURLPOSIXPathStyle, false);
CGDataProviderRef provider = CGDataProviderCreateWithURL (url);
CFRelease (url);
image = CGImageCreateWithPNGDataProvider (provider, NULL, true, kCGRenderingIntentDefault);
*/
image = [[UIImage alloc] initWithContentsOfFile:file];
[image retain];
// [self setImageToData:data];
return self;
}
@end
... ...
//
// FractalTileProjection.h
// Images
//
// Created by Joseph Gentle on 27/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMercator.h"
#import "RMTile.h"
@class RMScreenProjection;
@interface RMFractalTileProjection : NSObject {
// Maximum zoom for which our tile server stores images
int maxZoom;
// Mercator bounds of the earth
RMMercatorRect bounds;
// Normally 256. This class assumes tiles are square.
int tileSideLength;
// The deal is, we have a scale which stores how many mercator gradiants per pixel
// in the image.
// If you run the maths, scale = bounds.width/(2^zoom * tileSideLength)
// or if you want, z = log(bounds.width/tileSideLength) - log(s)
// So here we'll cache the first term for efficiency.
// I'm using width arbitrarily - I'm not sure what the effect of using the other term is when they're not the same.
double scaleFactor;
}
@property(readonly, nonatomic) RMMercatorRect bounds;
@property(readonly, nonatomic) int maxZoom;
@property(readonly, nonatomic) int tileSideLength;
-(id) initWithBounds: (RMMercatorRect)bounds TileSideLength:(int)tileSideLength MaxZoom: (int) max_zoom;
-(RMTilePoint) project: (RMMercatorPoint)mercator AtZoom:(float)zoom;
-(RMTileRect) projectRect: (RMMercatorRect)mercatorRect AtZoom:(float)zoom;
-(RMTilePoint) project: (RMMercatorPoint)mercator AtScale:(float)scale;
-(RMTileRect) projectRect: (RMMercatorRect)mercatorRect AtScale:(float)scale;
// This is a helper for projectRect above. Much simpler for the caller.
-(RMTileRect) project: (RMScreenProjection*)screen;
-(float) normaliseZoom: (float) zoom;
-(float) calculateZoomFromScale: (float) scale;
-(float) calculateNormalisedZoomFromScale: (float) scale;
-(float) calculateScaleFromZoom: (float) zoom;
@end
... ...
//
// FractalTileProjection.m
// Images
//
// Created by Joseph Gentle on 27/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMFractalTileProjection.h"
#import "RMScreenProjection.h"
#import <math.h>
@implementation RMFractalTileProjection
@synthesize maxZoom, tileSideLength, bounds;
-(id) initWithBounds: (RMMercatorRect)_bounds TileSideLength:(int)_tileSideLength MaxZoom: (int)_maxZoom
{
if (![super init])
return nil;
bounds = _bounds;
tileSideLength = _tileSideLength;
maxZoom = _maxZoom;
scaleFactor = log2(bounds.size.width / tileSideLength);
return self;
}
-(float) normaliseZoom: (float) zoom
{
float normalised_zoom = roundf(zoom);
//16;
if (normalised_zoom > maxZoom)
normalised_zoom = maxZoom;
if (normalised_zoom < 0)
normalised_zoom = 0;
return normalised_zoom;
}
-(float) limitFromNormalisedZoom: (float) zoom
{
return exp2f(zoom);
}
-(RMTilePoint) projectInternal: (RMMercatorPoint)mercator AtNormalisedZoom:(float)zoom Limit:(float) limit
{
RMTilePoint tile;
double x = (mercator.x - bounds.origin.x) / bounds.size.width * limit;
// Unfortunately, y is indexed from the bottom left.. hence we have to translate it.
double y = (double)limit * ((bounds.origin.y - mercator.y) / bounds.size.height + 1);
tile.tile.x = (int)x;
tile.tile.y = (int)y;
tile.tile.zoom = zoom;
tile.offset.x = (float)x - tile.tile.x;
tile.offset.y = (float)y - tile.tile.y;
return tile;
}
-(RMTilePoint) project: (RMMercatorPoint)mercator AtZoom:(float)zoom
{
float normalised_zoom = [self normaliseZoom:zoom];
float limit = [self limitFromNormalisedZoom:normalised_zoom];
return [self projectInternal:mercator AtNormalisedZoom:normalised_zoom Limit:limit];
}
-(RMTileRect) projectRect: (RMMercatorRect)mercator AtZoom:(float)zoom
{
int normalised_zoom = [self normaliseZoom:zoom];
float limit = [self limitFromNormalisedZoom:normalised_zoom];
RMTileRect rect;
// The origin for projectInternal will have to be the top left instead of the bottom left.
RMMercatorPoint topLeft = mercator.origin;
topLeft.y += mercator.size.height;
rect.origin = [self projectInternal:topLeft AtNormalisedZoom:normalised_zoom Limit:limit];
rect.size.width = mercator.size.width / bounds.size.width * limit;
rect.size.height = mercator.size.height / bounds.size.height * limit;
return rect;
}
-(RMTilePoint) project: (RMMercatorPoint)mercator AtScale:(float)scale
{
return [self project:mercator AtZoom:[self calculateZoomFromScale:scale]];
}
-(RMTileRect) projectRect: (RMMercatorRect)mercatorRect AtScale:(float)scale
{
return [self projectRect:mercatorRect AtZoom:[self calculateZoomFromScale:scale]];
}
-(RMTileRect) project: (RMScreenProjection*)screen;
{
return [self projectRect:[screen mercatorBounds] AtScale:[screen scale]];
}
-(float) calculateZoomFromScale: (float) scale
{ // zoom = log2(bounds.width/tileSideLength) - log2(s)
return scaleFactor - log2(scale);
}
-(float) calculateNormalisedZoomFromScale: (float) scale
{
return [self normaliseZoom:[self calculateZoomFromScale:scale]];
}
-(float) calculateScaleFromZoom: (float) zoom
{
return bounds.size.width / 256 / exp2(zoom);
}
@end
... ...
//
// LayerToScreenProjection.h
// RouteMe
//
// Created by Joseph Gentle on 11/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMScreenProjection.h"
@class CALayer;
// This is a nasty little class which pretends to be a regular screenprojection
// in order to
@interface RMLayerToScreenProjection : RMScreenProjection {
CALayer *layer;
}
-(id) initWithBounds: (CGRect) bounds InLayer: (CALayer *)layer;
@end
... ...
//
// LayerToScreenProjection.m
// RouteMe
//
// Created by Joseph Gentle on 11/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMLayerToScreenProjection.h"
#import <QuartzCore/QuartzCore.h>
#import "RMMathUtils.h"
@implementation RMLayerToScreenProjection
-(id) initWithBounds: (CGRect) _bounds InLayer: (CALayer *)_layer
{
if (![super initWithBounds:_bounds])
return nil;
layer = [_layer retain];
return self;
}
-(id) initWithBounds: (CGRect) bounds
{
@throw([NSException exceptionWithName:@"InvalidInitialiser" reason:@"Use designated initialiser for LayertoScreenProjection" userInfo:nil]);
[self dealloc];
return nil;
}
-(void) dealloc
{
[layer release];
[super dealloc];
}
// NSLog(@"Frame at %f %f %f,%f", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
// frame = CGRectApplyAffineTransform(frame, CGAffineTransformInvert([layer affineTransform]));
//frame.origin.x -= layer.position.x;
//frame.origin.y -= layer.position.y;
//
//NSLog(@"Frame at %f %f %f,%f", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
-(void) moveToMercator: (RMMercatorPoint) point
{
[super moveToMercator:point];
NSLog(@"fix moveToMercator");
// @throw([NSException exceptionWithName:@"NotImplemented" reason:@"method not yet implemented" userInfo:nil]);
}
- (void)moveBy: (CGSize) delta
{
layer.position = RMTranslateCGPointBy(layer.position, delta);
[super moveBy:delta];
}
// Center given in screen coordinates.
- (void)zoomByFactor: (float) factor Near:(CGPoint) center
{
CATransform3D transform = layer.transform;
transform = CATransform3DTranslate(transform, center.x, center.y, 0.0f);
transform = CATransform3DScale(transform, factor, factor, 1.0f);
transform = CATransform3DTranslate(transform, -center.x, -center.y, 0.0f);
layer.transform = transform;
[super zoomByFactor:factor Near:center];
}
- (void)zoomBy: (float) factor
{
[self zoomByFactor:factor Near:CGPointMake(0,0)];
}
-(CGPoint) projectMercatorPoint: (RMMercatorPoint) merc
{
NSLog(@"projectMercatorPoint");
CGPoint point = [super projectMercatorPoint: merc];
point.x -= layer.position.x;
point.y -= layer.position.y;
return point;
}
//-(CGRect) projectMercatorRect: (MercatorRect) rect
//{
// CGRect rect = [super projectMercatorPoint: point];
//
// point.x -= layer.position.x;
// point.y -= layer.position.y;
//
// return point;
//}
//-(MercatorPoint) projectInversePoint: (CGPoint) point;
//-(MercatorRect) projectInverseRect: (CGRect) rect;
//-(MercatorRect) mercatorBounds;
//-(CGRect) screenBounds;
@end
... ...
//
// LayeredTileImageSet.h
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTileLoader.h"
#import "RMMercator.h"
@interface RMLayeredTileLoader : RMTileLoader {
CALayer *layer;
}
@property (readonly, nonatomic) CALayer *layer;
- (id) initForScreen: (RMScreenProjection*)screen FromImageSource: (id<RMTileSource>)source;
@end
... ...
//
// LayeredTileImageSet.m
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMLayeredTileLoader.h"
#import "RMScreenProjection.h"
#import <QuartzCore/QuartzCore.h>
#import "RMTileImage.h"
@implementation RMLayeredTileLoader
@synthesize layer;
- (id) init
{
if (![self initForScreen:nil FromImageSource:nil])
return nil;
return self;
}
- (id) initForScreen: (RMScreenProjection*)screen FromImageSource: (id<RMTileSource>)source
{
if (![super initForScreen:screen FromImageSource:source])
return nil;
layer = [CAScrollLayer layer];
layer.anchorPoint = CGPointMake(0.0f, 0.0f);
layer.masksToBounds = YES;
if (screen != nil)
{
layer.frame = [screen screenBounds];
// layerPositionOffset = [screen topLeft];
}
// CALayer *sublayer = [CALayer layer];
// sublayer.frame = CGRectMake(160, 100, 256, 256);
// NSString *path = [[NSBundle mainBundle] pathForResource:@"loading" ofType:@"png"];
// CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename([path UTF8String]);
// CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, FALSE, kCGRenderingIntentDefault);
// sublayer.contents = (id)image;
// [layer addSublayer:sublayer];
return self;
}
- (void)tileAdded: (RMTile) tile WithImage: (RMTileImage*) image;
{
[image makeLayer];
CALayer *sublayer = [image layer];
// CGRect frame = image.screenLocation;
// frame.origin.x -= layer.position.x;
// frame.origin.y -= layer.position.y;
// NSLog(@"Frame at %f %f %f,%f", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
// NSLog(@"frame position %f,%f", layer.position.x, layer.position.y);
// sublayer.frame = frame;//GRectMake(layer.position.x, layer.position.y, 256, 256);
[layer addSublayer:sublayer];
// NSLog(@"added subimage");
}
-(void) tileRemoved: (RMTile) tile
{
RMTileImage *image = [images imageWithTile:tile];
[[image layer] removeFromSuperlayer];
[[NSNotificationCenter defaultCenter] postNotificationName:MapImageRemovedFromScreenNotification object:image];
// NSLog(@"subimage removed");
}
//-(id) initWithBounds:
@end
... ...
//
// MapRenderer.h
// RouteMe
//
// Created by Joseph Gentle on 8/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMercator.h"
@class RMMapView;
@class RMScreenProjection;
@interface RMMapRenderer : NSObject
{
RMScreenProjection *screenProjection;
RMMapView *view;
}
// Designated initialiser
- (id) initWithView: (RMMapView *)_view ProjectingIn: (RMScreenProjection*) _screenProjection;
// This makes a screen projection from the view
- (id) initWithView: (RMMapView *)view;
- (void)drawRect:(CGRect)rect;
-(void) moveToMercator: (RMMercatorPoint) point;
-(void) moveToLatLong: (CLLocationCoordinate2D) point;
- (void)moveBy: (CGSize) delta;
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center;
-(void) recalculateImageSet;
- (void)setNeedsDisplay;
@property (readwrite) double scale;
@property (readonly) RMScreenProjection *screenProjection;
@end
... ...
//
// MapRenderer.m
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMMapRenderer.h"
#import "RMScreenProjection.h"
#import "RMFractalTileProjection.h"
#import "RMMapView.h"
#import "RMTileSource.h"
#import "RMTileImage.h"
@implementation RMMapRenderer
@synthesize screenProjection;
// Designated initialiser
- (id) initWithView: (RMMapView *)_view ProjectingIn: (RMScreenProjection*) _screenProjection
{
if (![super init])
return nil;
view = _view;
screenProjection = [_screenProjection retain];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mapImageLoaded:) name:RMMapImageLoadedNotification object:nil];
return self;
}
- (id) initWithView: (RMMapView *)_view
{
RMScreenProjection *_screenProjection = [[RMScreenProjection alloc] initWithBounds:[_view bounds]];
return [self initWithView:_view ProjectingIn:_screenProjection];
}
-(void) dealloc
{
[screenProjection release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
-(void)mapImageLoaded: (NSNotification*)notification
{
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{ }
-(void) moveToMercator: (RMMercatorPoint) point
{
[screenProjection moveToMercator:point];
[self setNeedsDisplay];
}
-(void) moveToLatLong: (CLLocationCoordinate2D) point
{
[screenProjection moveToLatLong:point];
[self setNeedsDisplay];
}
- (void)moveBy: (CGSize) delta
{
[screenProjection moveBy:delta];
[view setNeedsDisplay];
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
[screenProjection zoomByFactor:zoomFactor Near:center];
[view setNeedsDisplay];
}
-(void) recalculateImageSet
{
}
- (void)setNeedsDisplay
{
[self recalculateImageSet];
[view setNeedsDisplay];
}
- (double) scale
{
return [screenProjection scale];
}
- (void) setScale: (double) scale
{
[screenProjection setScale:scale];
[self setNeedsDisplay];
}
@end
... ...
//
// MapView.h
// Images
//
// Created by Joseph Gentle on 13/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMercator.h"
//#import "MapRenderer.h"
//#import "TileSource.h"
typedef struct {
CGPoint center;
float averageDistanceFromCenter;
int numTouches;
} RMGestureDetails;
@protocol RMTileSource;
@class RMMapRenderer;
//@class TileSource;
//@class TileImageSet;
@interface RMMapView : UIView {
id<RMTileSource> tileSource;
RMMapRenderer *renderer;
bool enableDragging;
bool enableZoom;
RMGestureDetails lastGesture;
}
-(void) moveToMercator: (RMMercatorPoint) point;
-(void) moveToLatLong: (CLLocationCoordinate2D) point;
- (void)moveBy: (CGSize) delta;
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center;
@property (readwrite) CLLocationCoordinate2D location;
@property (readwrite) float scale;
@property (assign, readwrite, nonatomic) bool enableDragging;
@property (assign, readwrite, nonatomic) bool enableZoom;
@property (retain, readwrite, nonatomic) id<RMTileSource> tileSource;
@end
... ...
//
// MapView.m
// Images
//
// Created by Joseph Gentle on 13/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMMapView.h"
#import "RMOpenStreetMapsSource.h"
#import "RMTileImage.h"
#import "RMTile.h"
//#import "TileImageSet.h"
//#import "TiledLayerController.h"
#import "RMFractalTileProjection.h"
#import "RMMemoryCache.h"
#import "RMQuartzRenderer.h"
#import "RMCoreAnimationRenderer.h"
#import "RMScreenProjection.h"
@implementation RMMapView
@synthesize enableDragging, enableZoom, tileSource;
-(void) makeTileSource
{
if (tileSource != nil)
return;
tileSource = [[RMOpenStreetMapsSource alloc] init];
}
-(void) makeRenderer
{
if (tileSource == nil)
{
[self makeTileSource];
}
if (renderer != nil)
return;
// renderer = [[QuartzRenderer alloc] initWithView:self];
renderer = [[RMCoreAnimationRenderer alloc] initWithView:self];
}
/*
-(void) makeProjection
{
if (tileSource == nil)
[self makeTileSource];
screenProjection = [[TiledLayerController alloc] initWithTileSource: tileSource];
[self layer].masksToBounds = YES;
[[self layer] addSublayer:[screenProjection layer]];
[[self layer] setNeedsDisplay];
CLLocationCoordinate2D here;
// here.latitude = -33.9264;
here.latitude = -33.9464;
here.longitude = 151.2381;
[screenProjection setScale:[[tileSource tileProjection] calculateScaleFromZoom:18]];
[screenProjection centerLatLong:here Animate: NO];
}*/
-(void) configureCaching
{
// Unfortunately, the iPhone doesn't seem to support disk caches using NSURLCache. This works fine in the
// simulator though.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSLocalDomainMask, YES);
if ([paths count] > 0)
{
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"mapTiles/"];
NSLog(@"Using cache path: %@", path);
NSURLCache *newCache = [[NSURLCache alloc] initWithMemoryCapacity:1024 * 1024 diskCapacity:1024 * 1024 * 10
diskPath:path];
[NSURLCache setSharedURLCache:newCache];
[newCache release];
}
}
-(void) initValues
{
renderer = nil;
tileSource = nil;
[self makeTileSource];
[self makeRenderer];
CLLocationCoordinate2D here;
here.latitude = -33.9464;
here.longitude = 151.2381;
[self setScale:10];
[self setLocation:here];
// NSLog(@"set to %f %f", here.latitude, here.longitude);
//
// here = [self location];
// NSLog(@"set to %f %f", here.latitude, here.longitude);
// [screenProjection setScale:[[[view tileSource] tileProjection] calculateScaleFromZoom:16]];
// imageSet = [[TileImageSet alloc] init];
enableDragging = YES;
enableZoom = YES;
// [self recalculateImageSet];
if (enableZoom)
[self setMultipleTouchEnabled:TRUE];
[renderer setNeedsDisplay];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self initValues];
}
return self;
}
- (void)awakeFromNib
{
[self initValues];
}
-(void) dealloc
{
[tileSource release];
[renderer release];
[super dealloc];
}
-(void) moveToMercator: (RMMercatorPoint) point
{
[renderer moveToMercator:point];
}
-(void) moveToLatLong: (CLLocationCoordinate2D) point
{
[renderer moveToLatLong:point];
}
- (void)moveBy: (CGSize) delta
{
[renderer moveBy:delta];
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
[renderer zoomByFactor:zoomFactor Near:center];
}
- (CLLocationCoordinate2D) location
{
RMMercatorRect rect = [[renderer screenProjection] mercatorBounds];
RMMercatorPoint center = rect.origin;
center.x += rect.size.width / 2;
center.y += rect.size.height / 2;
return [RMMercator toLatLong:center];
}
- (void) setLocation: (CLLocationCoordinate2D) location
{
[self moveToLatLong:location];
}
- (float) scale
{
return [[renderer screenProjection] scale];
}
- (void) setScale: (float) scale
{
[[renderer screenProjection] setScale:scale];
[renderer setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
// imageSet = [tileSource tileImagesForScreen: screenProjection];
// if ([imageSet needsRedraw])
{
// [self recalculateImageSet];
// NSLog(@"WARNING - Image set needs redraw and we're in drawRect.");
}
[renderer drawRect:rect];
// [self setNeedsDisplay];
}
/*
- (NSSet*) touchesOnScreenIn: (UIEvent *)event
{
NSSet *allTouches = [event allTouches];
NSMutableSet *interestingTouches = [[[NSMutableSet alloc] init] autorelease];
for (UITouch *touch in allTouches)
{
if ([touch phase] == UITouchPhaseBegan
|| [touch phase] == UITouchPhaseMoved
|| [touch phase] == UITouchPhaseStationary)
{
[interestingTouches addObject:touch];
}
}
return interestingTouches;
}*/
- (RMGestureDetails) getGestureDetails: (NSSet*) touches
{
RMGestureDetails gesture;
gesture.center.x = gesture.center.y = 0;
gesture.averageDistanceFromCenter = 0;
int interestingTouches = 0;
for (UITouch *touch in touches)
{
if ([touch phase] != UITouchPhaseBegan
&& [touch phase] != UITouchPhaseMoved
&& [touch phase] != UITouchPhaseStationary)
continue;
// NSLog(@"phase = %d", [touch phase]);
interestingTouches++;
CGPoint location = [touch locationInView: self];
gesture.center.x += location.x;
gesture.center.y += location.y;
}
if (interestingTouches == 0)
{
gesture.center = lastGesture.center;
gesture.numTouches = 0;
gesture.averageDistanceFromCenter = 0.0f;
return gesture;
}
// NSLog(@"interestingTouches = %d", interestingTouches);
gesture.center.x /= interestingTouches;
gesture.center.y /= interestingTouches;
for (UITouch *touch in touches)
{
if ([touch phase] != UITouchPhaseBegan
&& [touch phase] != UITouchPhaseMoved
&& [touch phase] != UITouchPhaseStationary)
continue;
CGPoint location = [touch locationInView: self];
// NSLog(@"For touch at %.0f, %.0f:", location.x, location.y);
float dx = location.x - gesture.center.x;
float dy = location.y - gesture.center.y;
// NSLog(@"delta = %.0f, %.0f distance = %f", dx, dy, sqrtf((dx*dx) + (dy*dy)));
gesture.averageDistanceFromCenter += sqrtf((dx*dx) + (dy*dy));
}
gesture.averageDistanceFromCenter /= interestingTouches;
gesture.numTouches = interestingTouches;
// NSLog(@"center = %.0f,%.0f dist = %f", gesture.center.x, gesture.center.y, gesture.averageDistanceFromCenter);
return gesture;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// NSLog(@"touchesBegan %d", [[event allTouches] count]);
lastGesture = [self getGestureDetails:[event allTouches]];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// I don't understand what the difference between this and touchesEnded is.
[self touchesEnded:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
lastGesture = [self getGestureDetails:[event allTouches]];
// NSLog(@"touchesEnded %d ... lastgesture at %f, %f", [[event allTouches] count], lastGesture.center.x, lastGesture.center.y);
// NSLog(@"Assemble.");
if (lastGesture.numTouches == 0)
[renderer recalculateImageSet];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
RMGestureDetails newGesture = [self getGestureDetails:[event allTouches]];
if (enableDragging && newGesture.numTouches == lastGesture.numTouches)
{
// NSLog(@"newGesture at %f, %f", newGesture.center.x, newGesture.center.y);
CGSize delta;
delta.width = newGesture.center.x - lastGesture.center.x;
delta.height = newGesture.center.y - lastGesture.center.y;
if (enableZoom && newGesture.numTouches > 1)
{
NSAssert (lastGesture.averageDistanceFromCenter > 0.0f && newGesture.averageDistanceFromCenter > 0.0f,
@"Distance from center is zero despite >1 touches on the screen");
// NSLog(@"delta %f %f", delta.width, delta.height);
[renderer moveBy:delta];
double zoomFactor = newGesture.averageDistanceFromCenter / lastGesture.averageDistanceFromCenter;
// lastZoomDistance = gesture.averageDistanceFromCenter;
// NSLog(@"zoom by %f", zoomFactor);
[renderer zoomByFactor: zoomFactor Near: newGesture.center];
}
else
{
// NSLog(@"delta %f %f", delta.width, delta.height);
// [self dragBy: delta TrySlideImages: YES];
[renderer moveBy:delta];
}
}
lastGesture = newGesture;
// NSLog(@"touchesMoved %d ... lastgesture at %f, %f", [[event allTouches] count], lastGesture.center.x, lastGesture.center.y);
}
@end
... ...
/*
* MathUtils.c
* RouteMe
*
* Created by Joseph Gentle on 8/09/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#include "RMMathUtils.h"
CGRect RMScaleCGRectAboutPoint(CGRect rect, float factor, CGPoint point)
{
rect.origin.x = (rect.origin.x - point.x) * factor + point.x;
rect.origin.y = (rect.origin.y - point.y) * factor + point.y;
rect.size.width *= factor;
rect.size.height *= factor;
return rect;
}
CGPoint RMTranslateCGPointBy(CGPoint point, CGSize delta)
{
point.x += delta.width;
point.y += delta.height;
return point;
}
CGRect RMTranslateCGRectBy(CGRect rect, CGSize delta)
{
rect.origin = RMTranslateCGPointBy(rect.origin, delta);
return rect;
}
... ...
/*
* MathUtils.h
* RouteMe
*
* Created by Joseph Gentle on 8/09/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#ifndef _MATHUTILS_H_
#define _MATHUTILS_H_
#include <CoreGraphics/CGGeometry.h>
CGRect RMScaleCGRectAboutPoint(CGRect rect, float factor, CGPoint point);
CGRect RMTranslateCGRectBy(CGRect rect, CGSize delta);
CGPoint RMTranslateCGPointBy(CGPoint point, CGSize delta);
#endif
\ No newline at end of file
... ...
//
// MemoryCache.h
// Images
//
// Created by Joseph Gentle on 30/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RMTile.h"
#import "RMTileCache.h"
@interface RMMemoryCache : NSObject<RMTileCache> {
NSMutableDictionary *cache;
int capacity;
}
-(id)initWithCapacity: (NSUInteger) _capacity;
@end
... ...
//
// MemoryCache.m
// Images
//
// Created by Joseph Gentle on 30/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMMemoryCache.h"
#import "RMTileImage.h"
@implementation RMMemoryCache
-(id)initWithCapacity: (NSUInteger) _capacity
{
if (![super init])
return nil;
cache = [[NSMutableDictionary alloc] initWithCapacity:_capacity];
if (_capacity < 1)
_capacity = 1;
capacity = _capacity;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(imageLoadingCancelled:)
name:RMMapImageLoadingCancelledNotification
object:nil];
return self;
}
-(id)init
{
return [self initWithCapacity:16];
}
-(void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[cache release];
[super dealloc];
}
-(void) removeTile: (RMTile) tile
{
// NSLog(@"tile %d %d %d removed from cache", tile.x, tile.y, tile.zoom);
[cache removeObjectForKey:[RMTileCache tileHash: tile]];
}
-(void) imageLoadingCancelled: (NSNotification*)notification
{
[self removeTile: [[notification object] tile]];
}
-(RMTileImage*) cachedImage:(RMTile)tile
{
NSNumber *key = [RMTileCache tileHash: tile];
RMTileImage *image = [cache objectForKey:key];
/* if (image == nil)
NSLog(@"cache miss %@", key);
else
NSLog(@"cache hit %@", key);
*/
return image;
}
-(void)makeSpaceInCache
{
while ([cache count] >= capacity)
{
// Rather than scanning I would really like to be using a priority queue
// backed by a heap here.
NSEnumerator *enumerator = [cache objectEnumerator];
RMTileImage *image;
NSDate *oldestDate = nil;
RMTileImage *oldestImage = nil;
while ((image = (RMTileImage*)[enumerator nextObject]))
{
if (oldestDate == nil
|| ([oldestDate timeIntervalSinceReferenceDate] > [[image lastUsedTime] timeIntervalSinceReferenceDate]))
{
oldestDate = [image lastUsedTime];
oldestImage = image;
}
}
[self removeTile:[oldestImage tile]];
}
}
-(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
{
if (RMTileIsDummy(tile))
return;
// NSLog(@"cache add %@", key);
[self makeSpaceInCache];
NSNumber *key = [RMTileCache tileHash: tile];
[cache setObject:image forKey:key];
}
@end
... ...
//
// Mercator.h
// Images
//
// Created by Joseph Gentle on 21/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
//#import <Foundation/Foundation.h>
typedef struct {
double x, y;
} RMMercatorPoint;
typedef struct {
RMMercatorPoint origin;
CGSize size;
} RMMercatorRect;
@interface RMMercator : NSObject {
}
+ (CLLocationCoordinate2D) mercatorAsCLLocation: (RMMercatorPoint) merc;
+ (RMMercatorPoint) cLlocationAsMercator: (CLLocationCoordinate2D) coordinate;
+ (CLLocationCoordinate2D) toLatLong: (RMMercatorPoint) coordinate;
+ (RMMercatorPoint) toMercator: (CLLocationCoordinate2D) coordinate;
+ (RMMercatorPoint) clipPoint: (RMMercatorPoint)point ToBounds: (RMMercatorRect) bounds;
//+ (MercatorRect) clipRect: (MercatorRect)rect ToBounds: (MercatorRect) bounds;
@end
... ...
//
// Mercator.m
// Images
//
// Created by Joseph Gentle on 21/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMMercator.h"
#import "RMProjection.h"
@implementation RMMercator
+ (CLLocationCoordinate2D) mercatorAsCLLocation: (RMMercatorPoint) merc
{
CLLocationCoordinate2D point;
point.latitude = merc.y;
point.longitude = merc.x;
return point;
}
+ (RMMercatorPoint) cLlocationAsMercator: (CLLocationCoordinate2D) coordinate
{
RMMercatorPoint point;
point.x = coordinate.longitude;
point.y = coordinate.latitude;
return point;
}
+ (CLLocationCoordinate2D) toLatLong: (RMMercatorPoint) coordinate
{
return [[RMProjection EPSGGoogle] projectInverse:[RMMercator mercatorAsCLLocation:coordinate]];
}
+ (RMMercatorPoint) toMercator: (CLLocationCoordinate2D) coordinate
{
return [RMMercator cLlocationAsMercator:[[RMProjection EPSGGoogle] projectForward:coordinate]];
}
+ (RMMercatorPoint) clipPoint: (RMMercatorPoint)point ToBounds: (RMMercatorRect) bounds
{
if (point.x < bounds.origin.x)
point.x = bounds.origin.x;
else if (point.x > (bounds.origin.x + bounds.size.width))
point.x = bounds.origin.x + bounds.size.width;
if (point.y < bounds.origin.y)
point.y = bounds.origin.y;
else if (point.y > (bounds.origin.y + bounds.size.height))
point.y = bounds.origin.y + bounds.size.height;
return point;
}
/* Not complete.
+ (MercatorRect) clipRect: (MercatorRect)rect ToBounds: (MercatorRect) bounds
{
if (rect.origin.x < bounds.origin.x)
{
rect.size.width -= bounds.origin.x - rect.origin.x;
rect.origin.x = bounds.origin.x;
}
else if (rect.origin.x > (bounds.origin.x + bounds.size.width))
{
rect.origin.x = bounds.origin.x + bounds.size.width;
rect.size.width = 0;
}
if ((rect.origin.x + rect.size.width) > (bounds.origin.x + bounds.size.width))
{
rect.size.width -= (rect.origin.x + rect.size.width) - (bounds.origin.x + bounds.size.width);
rect.origin.x = bounds.origin.x + bounds.size.width;
}
if (rect.origin.y < bounds.origin.y)
rect.origin.y = bounds.origin.y;
else if (rect.origin.y > (bounds.origin.y + bounds.size.height))
rect.origin.y = bounds.origin.y + bounds.size.height;
}*/
@end
... ...
//
// OpenStreetMapsSource.h
// Images
//
// Created by Joseph Gentle on 19/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RMTileSource.h"
#import "RMTile.h"
@class RMTileImage;
@class RMFractalTileProjection;
@interface RMOpenStreetMapsSource : NSObject <RMTileSource> {
NSString *baseURL;
RMFractalTileProjection *tileProjection;
}
-(RMTileImage *) tileImage: (RMTile)tile;
//-(TileImageSet*) tileImagesForScreen: (ScreenProjection*) screen;
//@property (readwrite, retain) TileCache *cache;
//@property (readonly) FractalTileProjection *tileProjection;
@end
... ...
//
// OpenStreetMapsSource.m
// Images
//
// Created by Joseph Gentle on 19/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMOpenStreetMapsSource.h"
#import "RMProjection.h"
#import "RMTransform.h"
#import "RMTileImage.h"
#import "RMTileLoader.h"
#import "RMFractalTileProjection.h"
#import "RMTiledLayerController.h"
@implementation RMOpenStreetMapsSource
-(id) init
{
if (![super init])
return nil;
// trans = [[Transform alloc] initFrom:latlong To:google];
baseURL = @"http://a.tile.openstreetmap.org/";
RMMercatorRect bounds;
bounds.origin.x = -20037508.34;
bounds.origin.y = -20037508.34;
bounds.size.width = 20037508.34 * 2;
bounds.size.height = 20037508.34 * 2;
tileProjection = [[RMFractalTileProjection alloc] initWithBounds:bounds TileSideLength:256 MaxZoom:18];
return self;
}
-(void) dealloc
{
[tileProjection release];
[super dealloc];
}
-(NSString*) tileURL: (RMTile) tile
{
return [NSString stringWithFormat:@"http://tile.openstreetmap.org/%d/%d/%d.png", tile.zoom, tile.x, tile.y];
}
-(RMTileImage *) tileImage: (RMTile)tile
{
RMTileImage* image = [RMTileImage imageWithTile: tile FromURL:[self tileURL:tile]];
// [cache addTile:tile WithImage:image];
return image;
}
-(RMFractalTileProjection*) tileProjection
{
return [[tileProjection retain] autorelease];
}
-(RMMercatorRect) bounds
{
return [tileProjection bounds];
}
//@synthesize cache;
@end
... ...
//
// Projection.h
// Images
//
// Created by Joseph Gentle on 18/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "proj_api.h"
@interface RMProjection : NSObject {
projPJ internalProjection;
}
-(id) initWithString: (NSString*)params;
-(id) init;
-(CLLocationCoordinate2D) projectForward: (CLLocationCoordinate2D)point;
-(CLLocationCoordinate2D) projectInverse: (CLLocationCoordinate2D)point;
@property (readonly) projPJ internalProjection;
+(RMProjection*) EPSGGoogle;
+(RMProjection*) EPSGLatLong;
@end
/*
bool is_initialized() const;
bool is_geographic() const;
*/
\ No newline at end of file
... ...
//
// Projection.m
// Images
//
// Created by Joseph Gentle on 18/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMProjection.h"
#import "proj_api.h"
@implementation RMProjection
@synthesize internalProjection;
-(id) initWithString: (NSString*)params
{
if (![super init])
return nil;
internalProjection = pj_init_plus([params UTF8String]);
if (internalProjection == NULL)
{
NSLog(@"Unhandled error creating projection. String is %@", params);
[self dealloc];
return nil;
}
return self;
}
-(id) init
{
return [self initWithString:@"+proj=latlong +ellps=WGS84"];
}
-(void) dealloc
{
if (internalProjection)
pj_free(internalProjection);
[super dealloc];
}
-(CLLocationCoordinate2D) projectForward: (CLLocationCoordinate2D)point
{
projUV uv = {
point.longitude * DEG_TO_RAD,
point.latitude * DEG_TO_RAD
};
projUV result = pj_fwd(uv, internalProjection);
CLLocationCoordinate2D result_point = {
result.v,
result.u,
};
return result_point;
}
-(CLLocationCoordinate2D) projectInverse: (CLLocationCoordinate2D)point
{
projUV uv = {
point.longitude,
point.latitude,
};
projUV result = pj_inv(uv, internalProjection);
CLLocationCoordinate2D result_point = {
result.v * RAD_TO_DEG,
result.u * RAD_TO_DEG,
};
return result_point;
}
static RMProjection* _google = nil;
static RMProjection* _latlong = nil;
+(RMProjection*) EPSGGoogle
{
if (_google)
{
return _google;
}
else
{
_google = [[RMProjection alloc] initWithString:@"+title= Google Mercator EPSG:900913 +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"];
return _google;
}
}
+(RMProjection*) EPSGLatLong;
{
if (_latlong)
{
return _latlong;
}
else
{
_latlong = [[RMProjection alloc] initWithString:@"+proj=latlong +ellps=WGS84"];
return _latlong;
}
}
@end
... ...
//
// QuartzRenderer.h
// RouteMe
//
// Created by Joseph Gentle on 8/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMapRenderer.h"
@class RMScreenProjection;
@class RMMapView;
@class RMTileLoader;
@interface RMQuartzRenderer : RMMapRenderer {
RMTileLoader *tileLoader;
}
@end
... ...
//
// QuartzRenderer.m
// RouteMe
//
// Created by Joseph Gentle on 8/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMQuartzRenderer.h"
#import "RMTileLoader.h"
#import "RMMapView.h"
#import "RMFractalTileProjection.h"
#import "RMTileSource.h"
#import "RMScreenProjection.h"
@implementation RMQuartzRenderer
- (id) initWithView: (RMMapView *)_view
{
if (![super initWithView:_view])
return nil;
tileLoader = [[RMTileLoader alloc] initForScreen:screenProjection FromImageSource:[view tileSource]];
return self;
}
-(void) dealloc
{
[tileLoader release];
[super dealloc];
}
-(void) recalculateImageSet
{
[tileLoader assemble];
}
- (void)drawRect:(CGRect)rect
{
[tileLoader draw];
}
-(void) moveToMercator: (RMMercatorPoint) point
{
[tileLoader clearLoadedBounds];
[super moveToMercator:point];
}
-(void) moveToLatLong: (CLLocationCoordinate2D) point
{
[tileLoader clearLoadedBounds];
[super moveToLatLong:point];
}
- (void)moveBy: (CGSize) delta
{
[super moveBy:delta];
[tileLoader moveBy:delta];
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
[super zoomByFactor:zoomFactor Near:center];
[tileLoader zoomByFactor:zoomFactor Near:center];
}
- (void)tileDidFinishLoading: (RMTileImage *)image
{
[view setNeedsDisplay];
}
@end
... ...
//
// ScreenProjection.h
// Images
//
// Created by Joseph Gentle on 28/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMercator.h"
#import <CoreLocation/CoreLocation.h>
@interface RMScreenProjection : NSObject {
RMMercatorPoint topLeft;
// Bounds of the screen in pixels
CGRect bounds;
// Scale is how many meters in 1 pixel. Larger scale means bigger things are smaller on the screen.
// Scale of 1 means 1 pixel == 1 meter.
// Scale of 10 means 1 pixel == 10 meters.
float scale;
}
-(id) initWithBounds: (CGRect) bounds;
-(void) moveToMercator: (RMMercatorPoint) point;
-(void) moveToLatLong: (CLLocationCoordinate2D) point;
- (void)moveBy: (CGSize) delta;
// Center given in screen coordinates.
- (void)zoomByFactor: (float) factor Near:(CGPoint) center;
- (void)zoomBy: (float) factor;
-(CGPoint) projectMercatorPoint: (RMMercatorPoint) point;
-(CGRect) projectMercatorRect: (RMMercatorRect) rect;
-(RMMercatorPoint) projectInversePoint: (CGPoint) point;
-(RMMercatorRect) projectInverseRect: (CGRect) rect;
-(RMMercatorRect) mercatorBounds;
-(CGRect) screenBounds;
@property (assign, readwrite) float scale;
@property (readonly) RMMercatorPoint topLeft;
//@property (assign, readwrite) CGSize viewSize;
@end
... ...
//
// ScreenProjection.m
// Images
//
// Created by Joseph Gentle on 28/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMScreenProjection.h"
@implementation RMScreenProjection
@synthesize scale, topLeft;
-(id) initWithBounds: (CGRect) _bounds
{
if (![super init])
return nil;
bounds = _bounds;
topLeft.x = 0;
topLeft.y = 0;
scale = 1;
return self;
}
-(void) moveToMercator: (RMMercatorPoint) point
{
topLeft = point;
topLeft.x -= bounds.size.width * scale / 2;
topLeft.y -= bounds.size.height * scale / 2;
}
-(void) moveToLatLong: (CLLocationCoordinate2D) point;
{
[self moveToMercator:[RMMercator toMercator:point]];
}
-(void) moveBy: (CGSize) delta
{
topLeft.x -= delta.width * scale;
topLeft.y += delta.height * scale;
}
-(void) zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
// NSLog(@"zoomBy: %f", zoomFactor);
topLeft.x += center.x * scale;
topLeft.y += (bounds.size.height - center.y) * scale;
scale /= zoomFactor;
topLeft.x -= center.x * scale;
topLeft.y -= (bounds.size.height - center.y) * scale;
}
- (void)zoomBy: (float) factor
{
scale *= factor;
}
-(CGPoint) projectMercatorPoint: (RMMercatorPoint) mercator
{
CGPoint point;
point.x = (mercator.x - topLeft.x) / scale;
point.y = -(mercator.y - topLeft.y) / scale;
return point;
}
-(CGRect) projectMercatorRect: (RMMercatorRect) mercator
{
CGRect rect;
rect.origin = [self projectMercatorPoint: mercator.origin];
mercator.size.width = rect.size.width / scale;
mercator.size.height = rect.size.height / scale;
return rect;
}
-(RMMercatorPoint) projectInversePoint: (CGPoint) point
{
RMMercatorPoint mercator;
mercator.x = (scale * point.x) + topLeft.x;
mercator.y = -(scale * point.y) + topLeft.y;
return mercator;
}
-(RMMercatorRect) projectInverseRect: (CGRect) rect
{
RMMercatorRect mercator;
mercator.origin = [self projectInversePoint: rect.origin];
mercator.size.width = rect.size.width * scale;
mercator.size.height = rect.size.height * scale;
return mercator;
}
-(CGRect) screenBounds
{
return bounds;
}
-(RMMercatorRect) mercatorBounds
{
RMMercatorRect rect;
rect.origin = topLeft;
rect.size.width = bounds.size.width * scale;
rect.size.height = bounds.size.height * scale;
return rect;
}
@end
... ...
/*
* Tile.c
* RouteMe
*
* Created by Joseph Gentle on 9/09/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#include "RMTile.h"
#import <math.h>
uint64_t RMTileHash(RMTile tile)
{
uint64_t accumulator = 0;
for (int i = 0; i < tile.zoom; i++) {
accumulator |= ((uint64_t)tile.x & (1LL<<i)) << i;
accumulator |= ((uint64_t)tile.y & (1LL<<i)) << (i+1);
}
accumulator |= 1LL<<(tile.zoom * 2);
return accumulator;
}
RMTile RMTileDummy()
{
RMTile t;
t.x = -1;
t.y = -1;
t.zoom = -1;
return t;
}
char RMTileIsDummy(RMTile tile)
{
return tile.x == -1 && tile.y == -1 && tile.zoom == -1;
}
char RMTilesEqual(RMTile one, RMTile two)
{
return (one.x == two.x) && (one.y == two.y) && (one.zoom == two.zoom);
}
// Round the rectangle to whole numbers of tiles
RMTileRect RMTileRectRound(RMTileRect rect)
{
rect.size.width = ceilf(rect.size.width + rect.origin.offset.x);
rect.size.height = ceilf(rect.size.height + rect.origin.offset.y);
rect.origin.offset.x = 0;
rect.origin.offset.y = 0;
return rect;
}
int maxi(int a, int b)
{
return a > b ? a : b;
}
int mini(int a, int b)
{
return a < b ? a : b;
}
float maxf(float a, float b)
{
return a > b ? a : b;
}
float minf(float a, float b)
{
return a < b ? a : b;
}
/*
// Calculate and return the intersection of two rectangles
TileRect TileRectIntersection(TileRect one, TileRect two)
{
TileRect intersection;
// NSCAssert (one.origin.tile.zoom != two.origin.tile.zoom, @"Intersecting tiles do not have matching zoom");
intersection.origin.tile.x = maxi(one.origin.tile.x, two.origin.tile.x);
intersection.origin.tile.y = maxi(one.origin.tile.y, two.origin.tile.y);
return intersection;
}
// Calculate and return the union of two rectangles
TileRect TileRectUnion(TileRect one, TileRect two);*/
\ No newline at end of file
... ...
/*
* Tile.h
* Images
*
* Created by Joseph Gentle on 29/08/08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#ifndef _TILE_H_
#define _TILE_H_
#include <CoreGraphics/CGGeometry.h>
#include <stdint.h>
typedef struct{
uint32_t x, y;
short zoom;
} RMTile;
typedef struct{
RMTile tile;
CGPoint offset;
} RMTilePoint;
typedef struct{
RMTilePoint origin;
CGSize size;
} RMTileRect;
char RMTilesEqual(RMTile one, RMTile two);
char RMTileIsDummy(RMTile tile);
RMTile RMTileDummy();
// Return a hash of the tile
uint64_t RMTileHash(RMTile tile);
// Round the rectangle to whole numbers of tiles
RMTileRect RMTileRectRound(RMTileRect rect);
/*
// Calculate and return the intersection of two rectangles
TileRect TileRectIntersection(TileRect one, TileRect two);
// Calculate and return the union of two rectangles
TileRect TileRectUnion(TileRect one, TileRect two);
*/
#endif
\ No newline at end of file
... ...
//
// TileImageCache.h
// Images
//
// Created by Joseph Gentle on 30/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RMTile.h"
#import "RMTileSource.h"
@class RMTileImage;
@protocol RMTileCache<NSObject>
// Returns the cached image if it exists. nil otherwise.
-(RMTileImage*) cachedImage:(RMTile)tile;
@optional
-(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image;
@end
@interface RMTileCache : NSObject<RMTileCache>
{
NSMutableArray *caches;
}
+(RMTileCache*)sharedCache;
+(NSNumber*) tileHash: (RMTile)tile;
// Add tile to cache
-(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image;
-(void)addCache: (id<RMTileCache>)cache;
@end
\ No newline at end of file
... ...
//
// TileCache.m
// RouteMe
//
// Created by Joseph Gentle on 2/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTileCache.h"
#import "RMMemoryCache.h"
#import "RMDiskCache.h"
static RMTileCache *cache = nil;
@implementation RMTileCache
-(id)init
{
if (![super init])
return nil;
RMMemoryCache *memoryCache = [[RMMemoryCache alloc] init];
RMDiskCache *diskCache = [[RMDiskCache alloc] init];
caches = [[NSMutableArray alloc] init];
[self addCache:memoryCache];
[self addCache:diskCache];
[memoryCache release];
[diskCache release];
return self;
}
-(void) dealloc
{
[caches release];
[super dealloc];
}
+(RMTileCache*)sharedCache
{
if (cache == nil)
{
cache = [[RMTileCache alloc] init];
}
return cache;
}
-(void)addCache: (id<RMTileCache>)cache
{
[caches addObject:cache];
}
+(NSNumber*) tileHash: (RMTile)tile
{
return [NSNumber numberWithUnsignedLongLong: RMTileHash(tile)];
}
// Returns the cached image if it exists. nil otherwise.
-(RMTileImage*) cachedImage:(RMTile)tile
{
for (id<RMTileCache> cache in caches)
{
RMTileImage *image = [cache cachedImage:tile];
if (image != nil)
return image;
}
return nil;
}
-(void)addTile: (RMTile)tile WithImage: (RMTileImage*)image
{
for (id<RMTileCache> cache in caches)
{
if ([cache respondsToSelector:@selector(addTile:WithImage:)])
{
[cache addTile:tile WithImage:image];
}
}
}
@end
... ...
//
// Tile.h
// Images
//
// Created by Joseph Gentle on 13/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
//#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import "RMTile.h"
@class RMTileImage;
extern NSString * const RMMapImageLoadedNotification;
extern NSString * const RMMapImageLoadingCancelledNotification;
@interface RMTileImage : NSObject {
UIImage *image;
// CGImageRef image;
// I know this is a bit nasty.
RMTile tile;
CGRect screenLocation;
int loadingPriorityCount;
// Used by cache
NSDate *lastUsedTime;
// Only used when appropriate
CALayer *layer;
}
- (id) initWithTile: (RMTile)tile;
+ (RMTileImage*) dummyTile: (RMTile)tile;
//- (id) increaseLoadingPriority;
//- (id) decreaseLoadingPriority;
+ (RMTileImage*)imageWithTile: (RMTile) tile FromURL: (NSString*)url;
+ (RMTileImage*)imageWithTile: (RMTile) tile FromFile: (NSString*)filename;
- (void)drawInRect:(CGRect)rect;
- (void)draw;
- (void)moveBy: (CGSize) delta;
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center;
- (void)makeLayer;
-(void) cancelLoading;
- (void)setImageToData: (NSData*) data;
-(void) touch;
@property (readwrite, assign) CGRect screenLocation;
@property (readonly, assign) RMTile tile;
@property (readonly) CALayer *layer;
@property (readonly) UIImage *image;
@property (readonly) NSDate *lastUsedTime;
@end
... ...
//
// Tile.m
// Images
//
// Created by Joseph Gentle on 13/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTileImage.h"
#import "RMWebTileImage.h"
#import "RMTileLoader.h"
#import "RMFileTileImage.h"
#import "RMTileCache.h"
#import "RMMathUtils.h"
#import <QuartzCore/QuartzCore.h>
NSString * const RMMapImageLoadedNotification = @"MapImageLoaded";
NSString * const RMMapImageLoadingCancelledNotification = @"MapImageLoadingCancelled";
@implementation RMTileImage
@synthesize tile, layer, image, lastUsedTime;
- (id) initBlankTile: (RMTile)_tile
{
if (![super init])
return nil;
tile = _tile;
image = nil;
layer = nil;
loadingPriorityCount = 0;
lastUsedTime = nil;
[self touch];
return self;
}
- (id) initWithTile: (RMTile)_tile
{
if (![self initBlankTile: _tile])
return nil;
if ([[self class] isEqual:[RMTileImage class]])
{
[NSException raise:@"Abstract Class Exception" format:@"Error, attempting to instantiate TileImage directly."];
[self release];
return nil;
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(tileRemovedFromScreen:)
name:MapImageRemovedFromScreenNotification object:self];
// Should this be done as a notification?
[[RMTileCache sharedCache] addTile:tile WithImage:self];
return self;
}
-(void) tileRemovedFromScreen: (NSNotification*) notification
{
[self cancelLoading];
}
-(id) init
{
[NSException raise:@"Invalid initialiser" format:@"Use the designated initialiser for TileImage"];
[self release];
return nil;
}
+ (RMTileImage*) dummyTile: (RMTile)tile
{
return [[[RMTileImage alloc] initBlankTile:tile] autorelease];
}
- (void)dealloc
{
// NSLog(@"Removing tile image %d %d %d", tile.x, tile.y, tile.zoom);
[[NSNotificationCenter defaultCenter] removeObserver:self];
// if (image)
// CGImageRelease(image);
[image release];
[layer release];
[lastUsedTime release];
[super dealloc];
}
/*
- (id) increaseLoadingPriority
{
loadingPriorityCount++;
return self;
}
- (id) decreaseLoadingPriority
{
loadingPriorityCount--;
if (loadingPriorityCount == 0)
[self cancelLoading];
return self;
}*/
- (void)drawInRect:(CGRect)rect
{
[image drawInRect:rect];
/* if (image != NULL)
{
CGContextRef context = UIGraphicsGetCurrentContext();
NSLog(@"image width = %f", CGImageGetWidth(image));
// CGContextClipToRect(context, rect);
CGContextDrawImage(context, rect, image);
}*/
}
-(void)draw
{
[self drawInRect:screenLocation];
}
+ (RMTileImage*)imageWithTile: (RMTile) _tile FromURL: (NSString*)url
{
return [[[RMWebTileImage alloc] initWithTile:_tile FromURL:url] autorelease];
}
+ (RMTileImage*)imageWithTile: (RMTile) _tile FromFile: (NSString*)filename
{
return [[[RMFileTileImage alloc] initWithTile: _tile FromFile:filename] autorelease];
}
-(void) cancelLoading
{
[[NSNotificationCenter defaultCenter] postNotificationName:RMMapImageLoadingCancelledNotification
object:self];
}
//
//- (void)setImageToData: (NSData*) data
//{
// image = [[UIImage imageWithData:data] retain];
//}
- (void)setImageToData: (NSData*) data
{
// CGContextRef context =
CGDataProviderRef provider = CGDataProviderCreateWithCFData ((CFDataRef)data);
CGImageRef cgImage = CGImageCreateWithPNGDataProvider(provider, NULL, FALSE, kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
// CGImageRetain(image);
if (layer == nil)
{
image = [[UIImage imageWithCGImage:cgImage] retain];
}
else
{
// NSLog(@"Replacing image contents with data");
layer.contents = (id)cgImage;
}
CGImageRelease(cgImage);
NSDictionary *d = [NSDictionary dictionaryWithObject:data forKey:@"data"];
[[NSNotificationCenter defaultCenter] postNotificationName:RMMapImageLoadedNotification
object:self
userInfo:d];
}
- (NSUInteger)hash
{
return (NSUInteger)RMTileHash(tile);
}
-(void) touch
{
[lastUsedTime release];
lastUsedTime = [NSDate init];
}
- (BOOL)isEqual:(id)anObject
{
if (![anObject isKindOfClass:[RMTileImage class]])
return NO;
return RMTilesEqual(tile, [(RMTileImage*)anObject tile]);
}
- (void)makeLayer
{
if (layer == nil)
{
layer = [[CALayer alloc] init];
layer.contents = nil;
layer.anchorPoint = CGPointMake(0.0f, 0.0f);
layer.bounds = CGRectMake(0, 0, screenLocation.size.width, screenLocation.size.height);
layer.position = screenLocation.origin;
}
if (image != nil)
{
layer.contents = (id)[image CGImage];
[image release];
image = nil;
}
}
- (void)moveBy: (CGSize) delta
{
self.screenLocation = RMTranslateCGRectBy(screenLocation, delta);
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
self.screenLocation = RMScaleCGRectAboutPoint(screenLocation, zoomFactor, center);
}
- (CGRect) screenLocation
{
return screenLocation;
}
- (void) setScreenLocation: (CGRect)newScreenLocation
{
// NSLog(@"location moving from %f %f to %f %f", screenLocation.origin.x, screenLocation.origin.y, newScreenLocation.origin.x, newScreenLocation.origin.y);
screenLocation = newScreenLocation;
if (layer != nil)
{
// layer.frame = screenLocation;
layer.position = screenLocation.origin;
layer.bounds = CGRectMake(0, 0, screenLocation.size.width, screenLocation.size.height);
}
[self touch];
}
@end
... ...
//
// TileImageSet.h
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTile.h"
@class RMTileImage;
@protocol RMTileImageSetDelegate<NSObject>
-(RMTileImage*) makeTileImageFor:(RMTile) tile;
@optional
-(void) tileRemoved: (RMTile) tile;
-(void) tileAdded: (RMTile) tile WithImage: (RMTileImage*) image;
@end
@interface RMTileImageSet : NSObject {
IBOutlet id<RMTileImageSetDelegate> delegate;
NSCountedSet *images;
// This fixes an image resizing bug which causes thin lines along image borders
BOOL nudgeTileSize;
}
-(id) initWithDelegate: (id<RMTileImageSetDelegate>) _delegate;
-(void) addTile: (RMTile) tile WithImage: (RMTileImage *)image At: (CGRect) screenLocation;
-(void) addTile: (RMTile) tile At: (CGRect) screenLocation;
// Add tiles inside rect protected to bounds. Return rectangle containing bounds
// extended to full tile loading area
-(CGRect) addTiles: (RMTileRect)rect ToDisplayIn:(CGRect)bounds;
-(RMTileImage*) imageWithTile: (RMTile) tile;
-(void) removeTile: (RMTile) tile;
-(void) removeTiles: (RMTileRect)rect;
-(NSUInteger) count;
- (void)moveBy: (CGSize) delta;
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center;
- (void) draw;
@property (assign, nonatomic, readwrite) id<RMTileImageSetDelegate> delegate;
@property (readwrite, assign, nonatomic) BOOL nudgeTileSize;
@end
... ...
//
// TileImageSet.m
// RouteMe
//
// Created by Joseph Gentle on 9/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTileImageSet.h"
#import "RMTileImage.h"
#import "RMMathUtils.h"
@implementation RMTileImageSet
@synthesize delegate, nudgeTileSize;
-(id) initWithDelegate: (id<RMTileImageSetDelegate>) _delegate
{
if (![super init])
return nil;
self.delegate = _delegate;
images = [[NSCountedSet alloc] init];
nudgeTileSize = YES;
return self;
}
-(void) dealloc
{
[images release];
[super dealloc];
}
-(void) removeTile: (RMTile) tile
{
RMTileImage *dummyTile = [RMTileImage dummyTile:tile];
if ([images countForObject:dummyTile] == 1)
{
if ([delegate respondsToSelector: @selector(tileRemoved:)])
{
[delegate tileRemoved:tile];
}
}
[images removeObject:dummyTile];
}
-(void) removeTiles: (RMTileRect)rect
{
RMTileRect roundedRect = RMTileRectRound(rect);
// The number of tiles we'll load in the vertical and horizontal directions
int tileRegionWidth = (int)roundedRect.size.width;
int tileRegionHeight = (int)roundedRect.size.height;
RMTile t;
t.zoom = rect.origin.tile.zoom;
for (t.x = roundedRect.origin.tile.x; t.x < roundedRect.origin.tile.x + tileRegionWidth; t.x++)
{
for (t.y = (roundedRect.origin.tile.y); t.y <= roundedRect.origin.tile.y + tileRegionHeight; t.y++)
{
[self removeTile:t];
}
}
}
/* Untested.
-(BOOL) hasTile: (Tile) tile
{
NSEnumerator *enumerator = [images objectEnumerator];
TileImage *object;
while ((object = [enumerator nextObject])) {
if (TilesEqual(tile, [object tile]))
return YES;
}
return NO;
}*/
-(void) addTile: (RMTile) tile WithImage: (RMTileImage *)image At: (CGRect) screenLocation
{
image.screenLocation = screenLocation;
[images addObject:image];
if (!RMTileIsDummy(image.tile) && [delegate respondsToSelector:@selector(tileAdded:WithImage:)])
{
[delegate tileAdded:tile WithImage:image];
}
}
-(void) addTile: (RMTile) tile At: (CGRect) screenLocation
{
// NSLog(@"addTile: %d %d", tile.x, tile.y);
RMTileImage *dummyTile = [RMTileImage dummyTile:tile];
if ([images containsObject:dummyTile])
{
[images addObject:dummyTile];
}
else
{
if (delegate != nil)
{
RMTileImage *image = [delegate makeTileImageFor:tile];
if (image != nil)
[self addTile:tile WithImage:image At:screenLocation];
}
}
}
// Add tiles inside rect protected to bounds. Return rectangle containing bounds
// extended to full tile loading area
-(CGRect) addTiles: (RMTileRect)rect ToDisplayIn:(CGRect)bounds
{
// NSLog(@"addTiles: %d %d - %f %f", rect.origin.tile.x, rect.origin.tile.y, rect.size.width, rect.size.height);
RMTile t;
t.zoom = rect.origin.tile.zoom;
// ... Should be the same as equivalent calculation for height.
float pixelsPerTile = bounds.size.width / rect.size.width;
CGRect screenLocation;
screenLocation.size.width = pixelsPerTile;
screenLocation.size.height = pixelsPerTile;
// Corrects a bug in quartz's resizing code
if (nudgeTileSize)
{
screenLocation.size.width += 0.5;
screenLocation.size.height += 0.5;
}
RMTileRect roundedRect = RMTileRectRound(rect);
// The number of tiles we'll load in the vertical and horizontal directions
int tileRegionWidth = (int)roundedRect.size.width;
int tileRegionHeight = (int)roundedRect.size.height;
for (t.x = roundedRect.origin.tile.x; t.x < roundedRect.origin.tile.x + tileRegionWidth; t.x++)
{
for (t.y = (roundedRect.origin.tile.y); t.y <= roundedRect.origin.tile.y + tileRegionHeight; t.y++)
{
screenLocation.origin.x = bounds.origin.x + (t.x - (rect.origin.offset.x + rect.origin.tile.x)) * pixelsPerTile;
screenLocation.origin.y = bounds.origin.y + (t.y - (rect.origin.offset.y + rect.origin.tile.y)) * pixelsPerTile;
[self addTile:t At:screenLocation];
}
}
// Now we translate the loaded region back into screen space for loadedBounds.
CGRect newLoadedBounds;
newLoadedBounds.origin.x = bounds.origin.x - (rect.origin.offset.x * pixelsPerTile);
newLoadedBounds.origin.y = bounds.origin.y - (rect.origin.offset.y * pixelsPerTile);
newLoadedBounds.size.width = tileRegionWidth * pixelsPerTile;
newLoadedBounds.size.height = tileRegionHeight * pixelsPerTile;
return newLoadedBounds;
}
-(RMTileImage*) imageWithTile: (RMTile) tile
{
NSEnumerator *enumerator = [images objectEnumerator];
RMTileImage *object;
while ((object = [enumerator nextObject])) {
if (RMTilesEqual(tile, [object tile]))
return object;
}
return nil;
}
-(NSUInteger) count
{
return [images count];
}
- (void)moveBy: (CGSize) delta
{
for (RMTileImage *image in images)
{
[image moveBy: delta];
}
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
for (RMTileImage *image in images)
{
[image zoomByFactor:zoomFactor Near:center];
}
}
- (void) draw
{
for (RMTileImage *image in images)
{
[image draw];
}
}
@end
... ...
//
// TimeImageSet.h
// Images
//
// Created by Joseph Gentle on 29/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTile.h"
#import "RMTileImageSet.h"
@class RMTileImage;
@class RMTileImageSet;
@class RMScreenProjection;
extern NSString * const MapImageRemovedFromScreenNotification;
@protocol RMTileSource;
@interface RMTileLoader : NSObject <RMTileImageSetDelegate> {
// Set of locatedtileimages
RMTileImageSet *images;
// NSMutableSet *buffer;
// BOOL dirty;
RMScreenProjection* screenProjection;
id<RMTileSource> tileSource;
CGRect loadedBounds;
int loadedZoom;
RMTileRect loadedTiles;
}
// Designated initialiser
-(id) initForScreen: (RMScreenProjection*)screen FromImageSource: (id<RMTileSource>)source;
//-(id) initFromRect:(TileRect) rect FromImageSource: (id<TileSource>)source ToDisplayIn:(CGRect)bounds WithTileDelegate: (id)delegate;
-(void) dealloc;
// Invalidate all current image data.
//-(void) setNeedsRedraw;
//-(BOOL) needsRedraw;
-(void) assemble;
- (void)moveBy: (CGSize) delta;
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center;
-(void) clearLoadedBounds;
@property (readonly, nonatomic) CGRect loadedBounds;
@property (readonly, nonatomic) int loadedZoom;
-(BOOL) containsRect: (CGRect)bounds;
//-(void) assembleFromRect:(TileRect) rect FromImageSource: (id<TileSource>)source ToDisplayIn:(CGRect)bounds WithTileDelegate: (id)delegate;
-(void) draw;
@end
... ...
//
// TimeImageSet.m
// Images
//
// Created by Joseph Gentle on 29/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTileLoader.h"
#import "RMTileImage.h"
#import "RMTileSource.h"
#import "RMMathUtils.h"
#import "RMScreenProjection.h"
#import "RMFractalTileProjection.h"
#import "RMTileImageSet.h"
#import "RMTileCache.h"
NSString* const MapImageRemovedFromScreenNotification = @"MapImageRemovedFromScreen";
@implementation RMTileLoader
@synthesize loadedBounds, loadedZoom;
/*
-(id) initFromRect:(TileRect) rect FromImageSource: (id<TileSource>)source ToDisplayIn:(CGRect)bounds WithTileDelegate: (id)delegate
{
if (![self init])
return nil;
[self assembleFromRect:rect FromImageSource: source ToDisplayIn:bounds WithTileDelegate: delegate];
return self;
}*/
-(RMTileImage*) makeTileImageFor:(RMTile) tile
{
RMTileImage *cachedImage = [[RMTileCache sharedCache] cachedImage:tile];
if (cachedImage != nil)
{
return cachedImage;
}
else
{
return [tileSource tileImage:tile];
}
}
-(id) init
{
if (![self initForScreen:nil FromImageSource:nil])
return nil;
return self;
}
-(id) initForScreen: (RMScreenProjection*)screen FromImageSource: (id<RMTileSource>)source
{
if (![super init])
return nil;
images = [[RMTileImageSet alloc] initWithDelegate:self];
[self clearLoadedBounds];
loadedTiles.origin.tile = RMTileDummy();
screenProjection = [screen retain];
tileSource = [source retain];
return self;
}
-(void) dealloc
{
NSLog(@"Imageset dealloced");
[images release];
// [buffer release];
[screenProjection release];
[tileSource release];
[super dealloc];
}
/*
-(void) swapBuffers
{
NSMutableSet *temp = images;
images = buffer;
buffer = temp;
}*/
-(void) clearLoadedBounds
{
loadedBounds = CGRectMake(0, 0, 0, 0);
}
-(BOOL) screenIsLoaded
{
// return CGRectContainsRect(loadedBounds, [screenProjection screenBounds])
// && loadedZoom == [[tileSource tileProjection] calculateNormalisedZoomFromScale:[screenProjection scale]];
BOOL contained = CGRectContainsRect(loadedBounds, [screenProjection screenBounds]);
float targetZoom = [[tileSource tileProjection] calculateNormalisedZoomFromScale:[screenProjection scale]];
// && loadedZoom == ;
if (contained == NO)
{
NSLog(@"reassembling because its not contained");
}
if (targetZoom != loadedZoom)
{
NSLog(@"reassembling because target zoom = %f, loaded zoom = %d", targetZoom, loadedZoom);
}
return contained && targetZoom == loadedZoom;
}
-(void) tileRemoved: (RMTile) tile
{
RMTileImage *image = [images imageWithTile:tile];
[[NSNotificationCenter defaultCenter] postNotificationName:MapImageRemovedFromScreenNotification object:image];
}
-(void) tileAdded: (RMTile) tile WithImage: (RMTileImage*) image
{
// [[NSNotificationCenter defaultCenter] postNotificationName:MapImageRemovedFromScreenNotification object:[NSValue valueWithBytes:&tile objCType:@encode(Tile)]];
}
-(CGRect) currentRendererBounds
{
return [screenProjection screenBounds];
}
-(void) assemble
{
if ([self screenIsLoaded])
return;
if (tileSource == nil || screenProjection == nil)
return;
// NSLog(@"assemble count = %d", [images count]);
RMFractalTileProjection *tileProjection = [tileSource tileProjection];
RMTileRect newTileRect = [tileProjection project:screenProjection];
CGRect newLoadedBounds = [images addTiles:newTileRect ToDisplayIn:[self currentRendererBounds]];
if (!RMTileIsDummy(loadedTiles.origin.tile))
[images removeTiles:loadedTiles];
// NSLog(@"-> count = %d", [images count]);
loadedBounds = newLoadedBounds;
loadedZoom = newTileRect.origin.tile.zoom;
loadedTiles = newTileRect;
}
- (void)moveBy: (CGSize) delta
{
[images moveBy:delta];
loadedBounds = RMTranslateCGRectBy(loadedBounds, delta);
// [self assemble];
}
- (void)zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
[images zoomByFactor:zoomFactor Near:center];
loadedBounds = RMScaleCGRectAboutPoint(loadedBounds, zoomFactor, center);
// [self assemble];
}
-(BOOL) containsRect: (CGRect)bounds
{
return CGRectContainsRect(loadedBounds, bounds);
}
-(void) draw
{
// [self assemble];
[images draw];
}
@end
... ...
//
// TileProxy.h
// Images
//
// Created by Joseph Gentle on 1/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTile.h"
@class RMTileImage;
@interface RMTileProxy : NSObject {
}
+(RMTileImage*) bestProxyFor: (RMTile) t;
+(RMTileImage*) errorTile;
+(RMTileImage*) loadingTile;
@end
... ...
//
// TileProxy.m
// Images
//
// Created by Joseph Gentle on 1/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTileProxy.h"
#import "RMTileImage.h"
@implementation RMTileProxy
+(RMTileImage*) bestProxyFor: (RMTile) t
{
return nil;
}
//static TileImage *_errorTile = nil;
static RMTileImage *_loadingTile = nil;
+(RMTileImage*) errorTile
{
return nil;
}
+(RMTileImage*) loadingTile
{
if (_loadingTile != nil)
return _loadingTile;
RMTile t = RMTileDummy();
NSString* file = [[NSBundle mainBundle] pathForResource:@"loading" ofType:@"png"];
_loadingTile = [[RMTileImage imageWithTile:t FromFile:file] retain];
return _loadingTile;
// return nil;
}
@end
... ...
//
// TileSource.h
// Images
//
// Created by Joseph Gentle on 13/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
//#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "RMTile.h"
#import "RMMercator.h"
@class RMTileImage;
@class RMFractalTileProjection;
@class RMTileLoader;
@class RMTiledLayerController;
@class RMTileCache;
@protocol RMTileSource <NSObject>
-(RMTileImage *) tileImage: (RMTile) tile;
-(RMFractalTileProjection*) tileProjection;
-(RMMercatorRect) bounds;
//
//@optional
//
//-(void) setCache: (TileCache*)cache;
@end
... ...
//
// ScreenProjection.h
// Images
//
// Created by Joseph Gentle on 28/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMMercator.h"
#import <CoreLocation/CoreLocation.h>
#import <QuartzCore/QuartzCore.h>
@protocol RMTileSource;
////////////////////////////// NOT COMPLETE. DO NOT USE
@interface RMTiledLayerController : NSObject
{
CATiledLayer *layer;
// MercatorPoint topLeft;
// Size in pixels
// CGSize viewSize;
// Scale is how many meters in 1 pixel. Larger scale means bigger things are smaller on the screen.
// Scale of 1 means 1 pixel == 1 meter.
// Scale of 10 means 1 pixel == 10 meters.
float scale;
id tileSource;
}
-(id) initWithTileSource: (id <RMTileSource>) tileSource;
-(void) setScale: (float) scale;
-(void) centerMercator: (RMMercatorPoint) point Animate: (BOOL) animate;
-(void) centerLatLong: (CLLocationCoordinate2D) point Animate: (BOOL) animate;
-(void) dragBy: (CGSize) delta;
-(void) zoomByFactor: (float) zoomFactor Near:(CGPoint) center;
/*
-(CGPoint) projectMercatorPoint: (MercatorPoint) point;
-(CGRect) projectMercatorRect: (MercatorRect) rect;
-(MercatorPoint) projectInversePoint: (CGPoint) point;
-(MercatorRect) projectInverseRect: (CGRect) rect;
-(MercatorRect) bounds;
*/
@property (assign, readwrite, nonatomic) float scale;
@property (readonly, nonatomic) CATiledLayer *layer;
@end
... ...
//
// ScreenProjection.m
// Images
//
// Created by Joseph Gentle on 28/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTiledLayerController.h"
#import "RMFractalTileProjection.h"
#import "RMTileSource.h"
@implementation RMTiledLayerController
@synthesize layer;
-(id) initWithTileSource: (id <RMTileSource>) _tileSource
{
if (![super init])
return nil;
@throw [NSException exceptionWithName:@"NotImplementedExcption" reason:@"TiledLayerController is not complete. Use CoreAnimationRenderer instead." userInfo:nil];
tileSource = _tileSource;
[tileSource retain];
RMFractalTileProjection *tileProjection = [tileSource tileProjection];
layer = [CATiledLayer layer];
layer.delegate = self;
layer.levelsOfDetail = tileProjection.maxZoom + 1; // check this.
layer.levelsOfDetailBias = 1; // Allows zoom level 0.
layer.tileSize = CGSizeMake(tileProjection.tileSideLength,
tileProjection.tileSideLength);
RMMercatorRect mercBounds = tileProjection.bounds;
layer.bounds = CGRectMake(mercBounds.origin.x, mercBounds.origin.y, mercBounds.size.width, mercBounds.size.height) ;
layer.position = CGPointMake(0, 0);
[self setScale:1];
[layer setNeedsDisplay];
return self;
}
-(void) dealloc
{
layer.delegate = nil;
[layer release];
[super dealloc];
}
-(void) setScale: (float) _scale
{
scale = _scale;
layer.transform = CATransform3DMakeScale(1/scale,1/scale, 1.0f);
}
- (float) scale
{
return scale;
}
-(void) centerMercator: (RMMercatorPoint) point Animate: (BOOL) animate
{
if (animate == NO)
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.0f]
forKey:kCATransactionAnimationDuration];
}
// layer.position = CGPointMake(point.x, point.y);
if (animate == NO)
{
[CATransaction commit];
}
// topLeft = point;
// topLeft.x -= viewSize.width * scale / 2;
// topLeft.y -= viewSize.height * scale / 2;
}
-(void) centerLatLong: (CLLocationCoordinate2D) point Animate: (BOOL) animate
{
[self centerMercator:[RMMercator toMercator:point] Animate: animate];
}
-(void) dragBy: (CGSize) delta
{
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:0.0f]
forKey:kCATransactionAnimationDuration];
layer.position = CGPointMake(layer.position.x + delta.width,
layer.position.y + delta.height);
[CATransaction commit];
}
-(void) zoomByFactor: (float) zoomFactor Near:(CGPoint) center
{
// NSLog(@"zoomBy: %f", zoomFactor);
/* topLeft.x += center.x * scale;
topLeft.y += (viewSize.height - center.y) * scale;
scale *= zoomFactor;
topLeft.x -= center.x * scale;
topLeft.y -= (viewSize.height - center.y) * scale;
*/
[self setScale: scale * zoomFactor];
}
- (void)drawLayer:(CALayer *)theLayer
inContext:(CGContextRef)theContext
{
NSLog(@"drawLayer:inContext:");
// CGRect visibleRect = [self visibleRect];
// NSLog(@"visibleRect: %d %d %d %d", visibleRect.origin.x, visibleRect.origin.y, visibleRect.size.width, visibleRect.size.height);
CGRect rect = CGContextGetClipBoundingBox(theContext);
// NSLog(@"rect: %d %d %d %d", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
//CGAffineTransform transform = CGContextGetCTM(theContext);
// NSLog(@"transform scale: a:%f b:%f c:%f d:%f tx:%f ty:%f", transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty);
NSString *path = [[NSBundle mainBundle] pathForResource:@"loading" ofType:@"png"];
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename([path UTF8String]);
CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, FALSE, kCGRenderingIntentDefault);
CGContextDrawImage(theContext, rect, image);
}
/*
-(CGPoint) projectMercatorPoint: (MercatorPoint) mercator
{
CGPoint point;
point.x = (mercator.x - topLeft.x) / scale;
point.y = -(mercator.y - topLeft.y) / scale;
return point;
}
-(CGRect) projectMercatorRect: (MercatorRect) mercator
{
CGRect rect;
rect.origin = [self projectMercatorPoint: mercator.origin];
mercator.size.width = rect.size.width / scale;
mercator.size.height = rect.size.height / scale;
return rect;
}
-(MercatorPoint) projectInversePoint: (CGPoint) point
{
MercatorPoint mercator;
mercator.x = (scale * point.x) + topLeft.x;
mercator.y = -(scale * point.y) + topLeft.y;
return mercator;
}
-(MercatorRect) projectInverseRect: (CGRect) rect
{
MercatorRect mercator;
mercator.origin = [self projectInversePoint: rect.origin];
mercator.size.width = rect.size.width * scale;
mercator.size.height = rect.size.height * scale;
return mercator;
}
-(MercatorRect) bounds
{
MercatorRect rect;
rect.origin = topLeft;
rect.size.width = viewSize.width * scale;
rect.size.height = viewSize.height * scale;
return rect;
}*/
@end
... ...
//
// Transform.h
// Images
//
// Created by Joseph Gentle on 18/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
@class RMProjection;
@interface RMTransform : NSObject {
RMProjection* source;
RMProjection* destination;
bool is_source_latlong;
bool is_dest_latlong;
}
-(id) initFrom: (RMProjection*)source To: (RMProjection*)dest;
-(CLLocationCoordinate2D) projectForward: (CLLocationCoordinate2D)point AtZoom: (double)z;
-(CLLocationCoordinate2D) projectInverse: (CLLocationCoordinate2D)point AtZoom: (double)z;
@end
/*
proj_transform(projection const& source,
projection const& dest);
bool forward (double& x, double& y , double& z) const;
bool backward (double& x, double& y , double& z) const;
*/
\ No newline at end of file
... ...
//
// Transform.m
// Images
//
// Created by Joseph Gentle on 18/08/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMTransform.h"
#import "RMProjection.h"
@implementation RMTransform
-(id) initFrom: (RMProjection*)_source To: (RMProjection*)_dest
{
if (![super init])
return nil;
source = _source;
destination = _dest;
is_source_latlong = pj_is_latlong(source.internalProjection);
is_dest_latlong = pj_is_latlong(destination.internalProjection);
if (source == nil || destination == nil)
{
[self dealloc];
return nil;
}
return self;
}
-(void) dealloc
{
[source release];
[destination release];
[super dealloc];
}
-(CLLocationCoordinate2D) projectForward: (CLLocationCoordinate2D)point AtZoom: (double)z
{
double zo = z;
if (is_source_latlong)
{
point.latitude *= DEG_TO_RAD;
point.longitude *= DEG_TO_RAD;
}
int retval = pj_transform(source.internalProjection, destination.internalProjection, 1, 0,
&point.longitude, &point.latitude, &z);
if (is_dest_latlong)
{
point.latitude *= RAD_TO_DEG;
point.longitude *= RAD_TO_DEG;
}
if (z != zo)
{
NSLog(@"z changed....");
}
if (retval != 0)
{ // This should be fixed to handle these errors...
NSLog(@"Error occured during pj_transform: %s", pj_strerrno(retval));
}
return point;
}
-(CLLocationCoordinate2D) projectInverse: (CLLocationCoordinate2D)point AtZoom: (double)z
{
pj_transform(destination.internalProjection, source.internalProjection, 1, 0,
&point.longitude,&point.latitude,&z);
return point;
}
@end
... ...
//
// WebTileImage.h
// Images
//
// Created by Joseph Gentle on 1/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RMTileImage.h"
@interface RMWebTileImage : RMTileImage {
// Before image is completely loaded a proxy image can be used.
// This will typically be a boilerplate image or a zoomed in or zoomed out version of another image.
RMTileImage *proxy;
NSURLConnection *connection;
// Data accumulator during loading.
NSMutableData *data;
}
- (id) initWithTile: (RMTile)tile FromURL:(NSString*)url;
@end
... ...
//
// WebTileImage.m
// Images
//
// Created by Joseph Gentle on 1/09/08.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
#import "RMWebTileImage.h"
#import "RMTileProxy.h"
#import <QuartzCore/CALayer.h>
@implementation RMWebTileImage
- (id) initWithTile: (RMTile)_tile FromURL:(NSString*)urlStr
{
if (![super initWithTile:_tile])
return nil;
// NSLog(@"Loading image from URL %@ ...", urlStr);
NSURL *url = [NSURL URLWithString: urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSCachedURLResponse *cachedData = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
proxy = [RMTileProxy loadingTile];
[proxy retain];
// NSURLCache *cache = [NSURLCache sharedURLCache];
// NSLog(@"Cache mem size: %d / %d disk size: %d / %d", [cache currentMemoryUsage], [cache memoryCapacity], [cache currentDiskUsage], [cache diskCapacity]);
if (cachedData != nil)
{
// NSLog(@"Using cached image");
[self setImageToData:[cachedData data]];
}
else
{
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
if (connection == nil)
{
NSLog(@"Error: Connection is nil ?!?");
proxy = [RMTileProxy errorTile];
[proxy retain];
}
}
// NSLog(@"... done. data size = %d", [imageData length]);
return self;
}
-(void) dealloc
{
// NSLog(@"Image dealloced");
[proxy release];
// NSLog(@"loading cancelled because image dealloced");
[self cancelLoading];
[super dealloc];
}
-(void) cancelLoading
{
if (connection == nil)
return;
// NSLog(@"Image loading cancelled");
[connection cancel];
[connection release];
connection = nil;
[data release];
data = nil;
[super cancelLoading];
}
- (void)makeLayer
{
[super makeLayer];
if (image == nil
&& layer != nil
&& layer.contents == nil)
{
layer.contents = (id)[[proxy image] CGImage];
}
}
- (void)drawInRect:(CGRect)rect
{
if (image)
[super drawInRect:rect];
else
[proxy drawInRect:rect];
}
// Delegate methods for loading the image
//– connection:didCancelAuthenticationChallenge: delegate method
//– connection:didReceiveAuthenticationChallenge: delegate method
//Connection Data and Responses
//– connection:willCacheResponse: delegate method
//– connection:didReceiveResponse: delegate method
//– connection:didReceiveData: delegate method
//– connection:willSendRequest:redirectResponse: delegate method
//Connection Completion
//– connection:didFailWithError: delegate method
//– connectionDidFinishLoading: delegate method
- (void)connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response
{
if (data != nil)
[data release];
data = [[NSMutableData alloc] initWithCapacity:[response expectedContentLength]];
}
- (void)connection:(NSURLConnection *)_connection didReceiveData:(NSData *)newData
{
[data appendData:newData];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)_connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return cachedResponse;
}
- (void)connection:(NSURLConnection *)_connection didFailWithError:(NSError *)error
{
proxy = [RMTileProxy errorTile];
[data release];
data = nil;
NSLog(@"Tile could not be loaded: %@", [error localizedDescription]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)_connection
{
[self setImageToData:data];
[data release];
data = nil;
[connection release];
connection = nil;
// NSLog(@"finished loading image");
}
@end
... ...
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.catchme.${PRODUCT_NAME:identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSMainNibFile</key>
<string>MainWindow</string>
</dict>
</plist>
... ...