PageRenderTime 54ms CodeModel.GetById 28ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/MapView/Map/RMCircle.m

http://github.com/route-me/route-me
Objective C | 184 lines | 114 code | 38 blank | 32 comment | 6 complexity | ef9bed78abe323a96df2bba677805caa MD5 | raw file
  1///
  2//  RMCircle.m
  3//
  4// Copyright (c) 2008-2010, 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 "RMCircle.h"
 29#import "RMMapContents.h"
 30#import "RMProjection.h"
 31#import "RMMercatorToScreenProjection.h"
 32
 33#define kDefaultLineWidth 10
 34#define kDefaultLineColor [UIColor blackColor]
 35#define kDefaultFillColor [UIColor blueColor]
 36
 37@interface RMCircle ()
 38
 39- (void)updateCirclePath;
 40
 41@end
 42
 43
 44@implementation RMCircle
 45
 46@synthesize shapeLayer;
 47@synthesize projectedLocation;
 48@synthesize enableDragging;
 49@synthesize enableRotation;
 50@synthesize lineColor;
 51@synthesize fillColor;
 52@synthesize radiusInMeters;
 53@synthesize lineWidthInPixels;
 54
 55- (id)initWithContents:(RMMapContents*)aContents radiusInMeters:(CGFloat)newRadiusInMeters latLong:(RMLatLong)newLatLong {
 56	self = [super init];
 57	
 58	if (self) {
 59		CAShapeLayer* newShapeLayer = [[CAShapeLayer alloc] init];
 60		shapeLayer = newShapeLayer;
 61		[self addSublayer:newShapeLayer];
 62		
 63		mapContents = aContents;
 64		radiusInMeters = newRadiusInMeters;
 65		latLong = newLatLong;
 66		projectedLocation = [[mapContents projection] latLongToPoint:newLatLong];
 67		[self setPosition:[[mapContents mercatorToScreenProjection] projectXYPoint:projectedLocation]];
 68//		DLog(@"Position: %f, %f", [self position].x, [self position].y);
 69		
 70		lineWidthInPixels = kDefaultLineWidth;
 71		lineColor = kDefaultLineColor;
 72		fillColor = kDefaultFillColor;
 73		
 74		scaleLineWidth = NO;
 75		enableDragging = YES;
 76		enableRotation = YES;
 77		
 78		circlePath = NULL;
 79		[self updateCirclePath];
 80	}
 81	
 82	return self;
 83}
 84
 85- (void)dealloc {
 86	[shapeLayer release];
 87	shapeLayer = nil;
 88	CGPathRelease(circlePath);
 89	[lineColor release];
 90	lineColor = nil;
 91	[fillColor release];
 92	fillColor = nil;
 93	[super dealloc];
 94}
 95
 96#pragma mark -
 97
 98- (void)updateCirclePath {
 99	CGPathRelease(circlePath);
100	
101	CGMutablePathRef newPath = CGPathCreateMutable();
102	
103	CGFloat latRadians = latLong.latitude * M_PI / 180.0f;
104	CGFloat pixelRadius = radiusInMeters / cos(latRadians) / [mapContents metersPerPixel];
105//	DLog(@"Pixel Radius: %f", pixelRadius);
106	
107	CGRect rectangle = CGRectMake(self.position.x - pixelRadius, 
108								  self.position.y - pixelRadius, 
109								  (pixelRadius * 2), 
110								  (pixelRadius * 2));
111	
112	CGFloat offset = floorf(-lineWidthInPixels / 2.0f) - 2;
113//	DLog(@"Offset: %f", offset);
114	CGRect newBoundsRect = CGRectInset(rectangle, offset, offset);
115	[self setBounds:newBoundsRect];
116	
117//	DLog(@"Circle Rectangle: %f, %f, %f, %f", rectangle.origin.x, rectangle.origin.y, rectangle.size.width, rectangle.size.height);
118//	DLog(@"Bounds Rectangle: %f, %f, %f, %f", self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height);
119	
120	CGPathAddEllipseInRect(newPath, NULL, rectangle);
121	circlePath = newPath;
122	
123	[[self shapeLayer] setPath:newPath];
124	[[self shapeLayer] setFillColor:[fillColor CGColor]];
125	[[self shapeLayer] setStrokeColor:[lineColor CGColor]];
126	[[self shapeLayer] setLineWidth:lineWidthInPixels];
127}
128
129#pragma mark Accessors
130
131- (void)setProjectedLocation:(RMProjectedPoint)newProjectedLocation {
132	projectedLocation = newProjectedLocation;
133	
134	[self setPosition:[[mapContents mercatorToScreenProjection] projectXYPoint:projectedLocation]];
135}
136
137- (void)setLineColor:(UIColor*)newLineColor {
138	if (lineColor != newLineColor) {
139		[lineColor release];
140		lineColor = [newLineColor retain];
141		[self updateCirclePath];
142	}
143}
144
145- (void)setFillColor:(UIColor*)newFillColor {
146	if (fillColor != newFillColor) {
147		[fillColor release];
148		fillColor = [newFillColor retain];
149		[self updateCirclePath];
150	}
151}
152
153- (void)setRadiusInMeters:(CGFloat)newRadiusInMeters {
154	radiusInMeters = newRadiusInMeters;
155	[self updateCirclePath];
156}
157
158- (void)setLineWidthInPixels:(CGFloat)newLineWidthInPixels {
159	lineWidthInPixels = newLineWidthInPixels;
160	[self updateCirclePath];
161}
162
163#pragma mark Map Movement and Scaling
164
165- (void)moveBy:(CGSize)delta {
166	if (enableDragging) {
167		[super moveBy:delta];
168	}
169}
170
171- (void)zoomByFactor:(float)zoomFactor near:(CGPoint)center {
172	[super zoomByFactor:zoomFactor near:center];
173	
174	[self updateCirclePath];
175}
176
177- (void)moveToLatLong:(RMLatLong)newLatLong {
178	latLong = newLatLong;
179	[self setProjectedLocation:[[mapContents projection] latLongToPoint:newLatLong]];
180	[self setPosition:[[mapContents mercatorToScreenProjection] projectXYPoint:projectedLocation]];
181//	DLog(@"Position: %f, %f", [self position].x, [self position].y);
182}
183
184@end