PageRenderTime 31ms CodeModel.GetById 2ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/MapView/Map/RMLayerCollection.m

http://github.com/route-me/route-me
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