/MapView/Map/RMLayerCollection.m
Objective C | 240 lines | 176 code | 28 blank | 36 comment | 24 complexity | 521e8baca647deef1b993710bf45c1ef MD5 | raw file
1// 2// RMLayerSet.m 3// 4// Copyright (c) 2008-2009, Route-Me Contributors 5// All rights reserved. 6// 7// Redistribution and use in source and binary forms, with or without 8// modification, are permitted provided that the following conditions are met: 9// 10// * Redistributions of source code must retain the above copyright notice, this 11// list of conditions and the following disclaimer. 12// * Redistributions in binary form must reproduce the above copyright notice, 13// this list of conditions and the following disclaimer in the documentation 14// and/or other materials provided with the distribution. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26// POSSIBILITY OF SUCH DAMAGE. 27 28#import "RMLayerCollection.h" 29#import "RMMapContents.h" 30#import "RMMercatorToScreenProjection.h" 31#import "RMMarker.h" 32 33@implementation RMLayerCollection 34 35- (id)initForContents: (RMMapContents *)_contents 36{ 37 if (![super init]) 38 return nil; 39 40 sublayers = [[NSMutableArray alloc] init]; 41 mapContents = _contents; 42 self.masksToBounds = YES; 43 rotationTransform = CGAffineTransformIdentity; 44 return self; 45} 46 47- (void) dealloc 48{ 49 [sublayers release]; 50 sublayers = nil; 51 mapContents = nil; 52 [super dealloc]; 53} 54 55 56- (void)correctScreenPosition: (CALayer *)layer 57{ 58 if ([layer conformsToProtocol:@protocol(RMMovingMapLayer)]) 59 { 60 // Kinda ugly. 61 CALayer<RMMovingMapLayer>* layer_with_proto = (CALayer<RMMovingMapLayer>*)layer; 62 if(layer_with_proto.enableDragging){ 63 RMProjectedPoint location = [layer_with_proto projectedLocation]; 64 layer_with_proto.position = [[mapContents mercatorToScreenProjection] projectXYPoint:location]; 65 } 66 if(!layer_with_proto.enableRotation){ 67 [layer_with_proto setAffineTransform:rotationTransform]; 68 } 69 } 70} 71 72 73- (void)setSublayers: (NSArray*)array 74{ 75 for (CALayer *layer in array) 76 { 77 [self correctScreenPosition:layer]; 78 } 79@synchronized(sublayers) { 80 [sublayers removeAllObjects]; 81 [sublayers addObjectsFromArray:array]; 82 [super setSublayers:array]; 83} 84} 85 86- (void)addSublayer:(CALayer *)layer 87{ 88@synchronized(sublayers) { 89 [self correctScreenPosition:layer]; 90 [sublayers addObject:layer]; 91 [super addSublayer:layer]; 92} 93} 94 95- (void)removeSublayer:(CALayer *)layer 96{ 97 @synchronized(sublayers) { 98 [sublayers removeObject:layer]; 99 [layer removeFromSuperlayer]; 100 } 101} 102 103- (void)removeSublayers:(NSArray *)layers 104{ 105 @synchronized(sublayers) { 106 for(CALayer *aLayer in layers) 107 { 108 [sublayers removeObject:aLayer]; 109 [aLayer removeFromSuperlayer]; 110 } 111 } 112} 113 114- (void)insertSublayer:(CALayer *)layer above:(CALayer *)siblingLayer 115{ 116@synchronized(sublayers) { 117 [self correctScreenPosition:layer]; 118 NSUInteger index = [sublayers indexOfObject:siblingLayer]; 119 [sublayers insertObject:layer atIndex:index + 1]; 120 [super insertSublayer:layer above:siblingLayer]; 121} 122} 123 124- (void)insertSublayer:(CALayer *)layer below:(CALayer *)siblingLayer 125{ 126@synchronized(sublayers) { 127 [self correctScreenPosition:layer]; 128 NSUInteger index = [sublayers indexOfObject:siblingLayer]; 129 [sublayers insertObject:layer atIndex:index]; 130 [super insertSublayer:layer below:siblingLayer]; 131} 132} 133 134- (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)index 135{ 136@synchronized(sublayers) { 137 [self correctScreenPosition:layer]; 138 [sublayers insertObject:layer atIndex:index]; 139 [super insertSublayer:layer atIndex:index]; 140} 141} 142 143/* 144- (void)insertSublayer:(RMMapLayer*) layer below:(RMMapLayer*)sibling; 145- (void)insertSublayer:(RMMapLayer*) layer above:(RMMapLayer*)sibling; 146- (void)removeSublayer:(RMMapLayer*) layer; 147 */ 148 149- (void)moveToProjectedPoint: (RMProjectedPoint)aPoint 150{ 151 /// \bug TODO: Test this. Does it work? 152 [self correctPositionOfAllSublayers]; 153} 154 155- (void)moveBy: (CGSize) delta 156{ 157 @synchronized(sublayers) { 158 for (id layer in sublayers) 159 { 160 if ([layer respondsToSelector:@selector(moveBy:)]) 161 [layer moveBy:delta]; 162 163 // if layer moves on and offscreen... 164 } 165 } 166} 167 168- (void)zoomByFactor: (float) zoomFactor near:(CGPoint) center 169{ 170@synchronized(sublayers) { 171 for (id layer in sublayers) 172 { 173 if ([layer respondsToSelector:@selector(zoomByFactor:near:)]) 174 [layer zoomByFactor:zoomFactor near:center]; 175 } 176} 177} 178 179- (void) correctPositionOfAllSublayers 180{ 181@synchronized(sublayers) { 182 for (id layer in sublayers) 183 { 184 [self correctScreenPosition:layer]; 185 } 186} 187} 188 189- (BOOL) hasSubLayer:(CALayer *)layer 190{ 191 return [sublayers containsObject:layer]; 192} 193 194- (void) setRotationOfAllSublayers:(float) angle 195{ 196 rotationTransform = CGAffineTransformMakeRotation(angle); // store rotation transform for subsequent layers 197 @synchronized(sublayers) { 198 for (id layer in sublayers) 199 { 200 CALayer<RMMovingMapLayer>* layer_with_proto = (CALayer<RMMovingMapLayer>*)layer; 201 if(!layer_with_proto.enableRotation){ 202 [layer_with_proto setAffineTransform:rotationTransform]; 203 } 204 } 205 } 206} 207 208NSInteger layerSort(id num1, id num2, void *context) { 209 if ([num1 isKindOfClass:[RMMarker class]] && [num2 isKindOfClass:[RMMarker class]]) { 210 // if both are markers, order based on vertical map position 211 RMMarker *first = (RMMarker *)num1; 212 RMMarker *second = (RMMarker *)num2; 213 214 double firstPos = first.projectedLocation.northing; 215 double secondPos = second.projectedLocation.northing; 216 217 if (firstPos > secondPos) { 218 return NSOrderedAscending; 219 } else if (firstPos < secondPos) { 220 return NSOrderedDescending; 221 } else { 222 return NSOrderedSame; 223 } 224 } else { 225 // if something isnt a marker, send to bottom 226 if ([num1 isKindOfClass:[RMMarker class]]) { 227 return NSOrderedDescending; 228 } else if ([num2 isKindOfClass:[RMMarker class]]) { 229 return NSOrderedAscending; 230 } else { 231 return NSOrderedSame; 232 } 233 } 234} 235 236- (void)orderLayers { 237 self.sublayers = [self.sublayers sortedArrayUsingFunction:layerSort context:NULL]; 238} 239 240@end