[ios] Refactor user location heading indicator into its own class
This commit is contained in:
@@ -216,6 +216,9 @@
|
||||
9620BB391E69FE1700705A1D /* MGLSDKUpdateChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 9620BB361E69FE1700705A1D /* MGLSDKUpdateChecker.h */; };
|
||||
9620BB3A1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; };
|
||||
9620BB3B1E69FE1700705A1D /* MGLSDKUpdateChecker.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9620BB371E69FE1700705A1D /* MGLSDKUpdateChecker.mm */; };
|
||||
966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */; };
|
||||
966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; };
|
||||
966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */; };
|
||||
968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
96E027231E57C76E004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027251E57C76E004B8E66 /* Localizable.strings */; };
|
||||
DA00FC8E1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -686,6 +689,8 @@
|
||||
9660916D1E5BBFDB00A9A03B /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
9660916E1E5BBFDC00A9A03B /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
9660916F1E5BBFDE00A9A03B /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingBeamLayer.h; sourceTree = "<group>"; };
|
||||
966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLUserLocationHeadingBeamLayer.m; sourceTree = "<group>"; };
|
||||
968F36B41E4D0FC6003A5522 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
96E027241E57C76E004B8E66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
96E027271E57C77A004B8E66 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@@ -1588,8 +1593,8 @@
|
||||
DAD165841CF4D06B001FF4B9 /* Annotations */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */,
|
||||
404326881D5B9B1A007111BD /* MGLAnnotationContainerView_Private.h */,
|
||||
40EDA1BD1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.h */,
|
||||
40EDA1BE1CFE0D4A00D9EA68 /* MGLAnnotationContainerView.m */,
|
||||
DA8848401CBAFB9800AB86E3 /* MGLAnnotationImage_Private.h */,
|
||||
DA8848341CBAFB8500AB86E3 /* MGLAnnotationImage.h */,
|
||||
@@ -1608,6 +1613,8 @@
|
||||
359F57451D2FDBD5005217F1 /* MGLUserLocationAnnotationView_Private.h */,
|
||||
354B83941D2E873E005D9406 /* MGLUserLocationAnnotationView.h */,
|
||||
354B83951D2E873E005D9406 /* MGLUserLocationAnnotationView.m */,
|
||||
966FCF4A1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h */,
|
||||
966FCF4B1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m */,
|
||||
);
|
||||
name = Annotations;
|
||||
sourceTree = "<group>";
|
||||
@@ -1696,6 +1703,7 @@
|
||||
408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */,
|
||||
DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */,
|
||||
558DE7A01E5615E400C7916D /* MGLFoundation_Private.h in Headers */,
|
||||
966FCF4C1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.h in Headers */,
|
||||
DA88483D1CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h in Headers */,
|
||||
DA17BE301CC4BAC300402C41 /* MGLMapView_Private.h in Headers */,
|
||||
DAD165781CF4CDFF001FF4B9 /* MGLShapeCollection.h in Headers */,
|
||||
@@ -2266,6 +2274,7 @@
|
||||
35B82BFA1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
|
||||
7E016D861D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */,
|
||||
DA8848521CBAFB9800AB86E3 /* MGLAPIClient.m in Sources */,
|
||||
966FCF4E1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */,
|
||||
DA8848301CBAFA6200AB86E3 /* NSProcessInfo+MGLAdditions.m in Sources */,
|
||||
353AFA161D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
|
||||
35D13AC51D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
|
||||
@@ -2349,6 +2358,7 @@
|
||||
35B82BFB1D6C5F8400B1B721 /* NSPredicate+MGLAdditions.mm in Sources */,
|
||||
7E016D871D9E890300A29A21 /* MGLPolygon+MGLAdditions.m in Sources */,
|
||||
DAA4E4311CBB730400178DFB /* MGLMapboxEvents.m in Sources */,
|
||||
966FCF4F1F3A5C9200F2B6DE /* MGLUserLocationHeadingBeamLayer.m in Sources */,
|
||||
DAA4E4231CBB730400178DFB /* MGLPolygon.mm in Sources */,
|
||||
353AFA171D65AB17005A69F4 /* NSDate+MGLAdditions.mm in Sources */,
|
||||
35D13AC61D3D19DD00AFB4E0 /* MGLFillStyleLayer.mm in Sources */,
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "MGLUserLocationAnnotationView.h"
|
||||
|
||||
const CGFloat MGLUserLocationAnnotationDotSize = 22.0;
|
||||
const CGFloat MGLUserLocationAnnotationHaloSize = 115.0;
|
||||
|
||||
const CGFloat MGLUserLocationAnnotationPuckSize = 45.0;
|
||||
const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6;
|
||||
|
||||
@interface MGLFaux3DUserLocationAnnotationView : MGLUserLocationAnnotationView
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -2,14 +2,7 @@
|
||||
|
||||
#import "MGLMapView.h"
|
||||
#import "MGLUserLocation.h"
|
||||
|
||||
const CGFloat MGLUserLocationAnnotationDotSize = 22.0;
|
||||
const CGFloat MGLUserLocationAnnotationHaloSize = 115.0;
|
||||
|
||||
const CGFloat MGLUserLocationAnnotationPuckSize = 45.0;
|
||||
const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6;
|
||||
|
||||
#pragma mark -
|
||||
#import "MGLUserLocationHeadingBeamLayer.h"
|
||||
|
||||
@implementation MGLFaux3DUserLocationAnnotationView
|
||||
{
|
||||
@@ -18,8 +11,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
|
||||
CALayer *_puckDot;
|
||||
CAShapeLayer *_puckArrow;
|
||||
|
||||
CALayer *_headingIndicatorLayer;
|
||||
CAShapeLayer *_headingIndicatorMaskLayer;
|
||||
MGLUserLocationHeadingBeamLayer *_headingIndicatorLayer;
|
||||
CALayer *_accuracyRingLayer;
|
||||
CALayer *_dotBorderLayer;
|
||||
CALayer *_dotLayer;
|
||||
@@ -56,21 +48,18 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
|
||||
|
||||
- (void)setTintColor:(UIColor *)tintColor
|
||||
{
|
||||
CGColorRef newTintColor = [tintColor CGColor];
|
||||
|
||||
if (_puckModeActivated)
|
||||
{
|
||||
_puckArrow.fillColor = [tintColor CGColor];
|
||||
_puckArrow.fillColor = newTintColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_accuracyRingLayer)
|
||||
{
|
||||
_accuracyRingLayer.backgroundColor = [tintColor CGColor];
|
||||
}
|
||||
|
||||
_haloLayer.backgroundColor = [tintColor CGColor];
|
||||
_dotLayer.backgroundColor = [tintColor CGColor];
|
||||
|
||||
_headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage];
|
||||
_accuracyRingLayer.backgroundColor = newTintColor;
|
||||
_haloLayer.backgroundColor = newTintColor;
|
||||
_dotLayer.backgroundColor = newTintColor;
|
||||
[_headingIndicatorLayer updateTintColor:newTintColor];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +127,6 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
|
||||
self.layer.sublayers = nil;
|
||||
|
||||
_headingIndicatorLayer = nil;
|
||||
_headingIndicatorMaskLayer = nil;
|
||||
_accuracyRingLayer = nil;
|
||||
_haloLayer = nil;
|
||||
_dotBorderLayer = nil;
|
||||
@@ -232,47 +220,21 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
|
||||
if (showHeadingIndicator)
|
||||
{
|
||||
_headingIndicatorLayer.hidden = NO;
|
||||
CLLocationDirection headingAccuracy = self.userLocation.heading.headingAccuracy;
|
||||
|
||||
// heading indicator (tinted, semi-circle)
|
||||
//
|
||||
if ( ! _headingIndicatorLayer && self.userLocation.heading.headingAccuracy)
|
||||
if ( ! _headingIndicatorLayer && headingAccuracy)
|
||||
{
|
||||
CGFloat headingIndicatorSize = MGLUserLocationAnnotationHaloSize;
|
||||
|
||||
_headingIndicatorLayer = [CALayer layer];
|
||||
_headingIndicatorLayer.bounds = CGRectMake(0, 0, headingIndicatorSize, headingIndicatorSize);
|
||||
_headingIndicatorLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0);
|
||||
_headingIndicatorLayer.contents = (__bridge id)[[self headingIndicatorTintedGradientImage] CGImage];
|
||||
_headingIndicatorLayer.contentsGravity = kCAGravityBottom;
|
||||
_headingIndicatorLayer.contentsScale = [UIScreen mainScreen].scale;
|
||||
_headingIndicatorLayer.opacity = 0.4;
|
||||
_headingIndicatorLayer.shouldRasterize = YES;
|
||||
_headingIndicatorLayer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
_headingIndicatorLayer.drawsAsynchronously = YES;
|
||||
|
||||
_headingIndicatorLayer = [[MGLUserLocationHeadingBeamLayer alloc] initWithUserLocationAnnotationView:self];
|
||||
[self.layer insertSublayer:_headingIndicatorLayer below:_dotBorderLayer];
|
||||
|
||||
_oldHeadingAccuracy = headingAccuracy;
|
||||
}
|
||||
|
||||
// heading indicator accuracy mask (fan-shaped)
|
||||
//
|
||||
if ( ! _headingIndicatorMaskLayer && self.userLocation.heading.headingAccuracy)
|
||||
else if (_oldHeadingAccuracy != headingAccuracy)
|
||||
{
|
||||
_headingIndicatorMaskLayer = [CAShapeLayer layer];
|
||||
_headingIndicatorMaskLayer.frame = _headingIndicatorLayer.bounds;
|
||||
_headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath];
|
||||
|
||||
// apply the mask to the halo-radius-sized gradient layer
|
||||
_headingIndicatorLayer.mask = _headingIndicatorMaskLayer;
|
||||
|
||||
_oldHeadingAccuracy = self.userLocation.heading.headingAccuracy;
|
||||
|
||||
}
|
||||
else if (_oldHeadingAccuracy != self.userLocation.heading.headingAccuracy)
|
||||
{
|
||||
// recalculate the clipping mask based on updated accuracy
|
||||
_headingIndicatorMaskLayer.path = [[self headingIndicatorClippingMask] CGPath];
|
||||
|
||||
_oldHeadingAccuracy = self.userLocation.heading.headingAccuracy;
|
||||
[_headingIndicatorLayer updateHeadingAccuracy:headingAccuracy];
|
||||
_oldHeadingAccuracy = headingAccuracy;
|
||||
}
|
||||
|
||||
if (self.userLocation.heading.trueHeading >= 0)
|
||||
@@ -283,9 +245,7 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
|
||||
else
|
||||
{
|
||||
[_headingIndicatorLayer removeFromSuperlayer];
|
||||
[_headingIndicatorMaskLayer removeFromSuperlayer];
|
||||
_headingIndicatorLayer = nil;
|
||||
_headingIndicatorMaskLayer = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -464,65 +424,4 @@ const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuck
|
||||
return self.userLocation.location.horizontalAccuracy / [self.mapView metersPerPointAtLatitude:self.userLocation.coordinate.latitude] * 2.0;
|
||||
}
|
||||
|
||||
- (UIImage *)headingIndicatorTintedGradientImage
|
||||
{
|
||||
UIImage *image;
|
||||
|
||||
CGFloat haloRadius = MGLUserLocationAnnotationHaloSize / 2.0;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(MGLUserLocationAnnotationHaloSize, haloRadius), NO, 0);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
// gradient from the tint color to no-alpha tint color
|
||||
CGFloat gradientLocations[] = {0.0, 1.0};
|
||||
CGGradientRef gradient = CGGradientCreateWithColors(
|
||||
colorSpace,
|
||||
(__bridge CFArrayRef)@[
|
||||
(id)[self.mapView.tintColor CGColor],
|
||||
(id)[[self.mapView.tintColor colorWithAlphaComponent:0] CGColor]],
|
||||
gradientLocations);
|
||||
|
||||
// draw the gradient from the center point to the edge (full halo radius)
|
||||
CGPoint centerPoint = CGPointMake(haloRadius, haloRadius);
|
||||
CGContextDrawRadialGradient(context, gradient,
|
||||
centerPoint, 0.0,
|
||||
centerPoint, haloRadius,
|
||||
kNilOptions);
|
||||
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
CGGradientRelease(gradient);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIBezierPath *)headingIndicatorClippingMask
|
||||
{
|
||||
CGFloat accuracy = self.userLocation.heading.headingAccuracy;
|
||||
|
||||
// size the mask using accuracy, but keep within a good display range
|
||||
CGFloat clippingDegrees = 90 - accuracy;
|
||||
clippingDegrees = fmin(clippingDegrees, 70); // most accurate
|
||||
clippingDegrees = fmax(clippingDegrees, 10); // least accurate
|
||||
|
||||
CGRect ovalRect = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize);
|
||||
UIBezierPath *ovalPath = UIBezierPath.bezierPath;
|
||||
|
||||
// clip the oval to ± incoming accuracy degrees (converted to radians), from the top
|
||||
[ovalPath addArcWithCenter:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))
|
||||
radius:CGRectGetWidth(ovalRect) / 2.0
|
||||
startAngle:MGLRadiansFromDegrees(-180 + clippingDegrees)
|
||||
endAngle:MGLRadiansFromDegrees(-clippingDegrees)
|
||||
clockwise:YES];
|
||||
|
||||
[ovalPath addLineToPoint:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))];
|
||||
[ovalPath closePath];
|
||||
|
||||
return ovalPath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
10
platform/ios/src/MGLUserLocationHeadingBeamLayer.h
Normal file
10
platform/ios/src/MGLUserLocationHeadingBeamLayer.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "MGLUserLocationAnnotationView.h"
|
||||
|
||||
@interface MGLUserLocationHeadingBeamLayer : CALayer
|
||||
|
||||
- (instancetype)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView;
|
||||
- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy;
|
||||
- (void)updateTintColor:(CGColorRef)color;
|
||||
|
||||
@end
|
||||
104
platform/ios/src/MGLUserLocationHeadingBeamLayer.m
Normal file
104
platform/ios/src/MGLUserLocationHeadingBeamLayer.m
Normal file
@@ -0,0 +1,104 @@
|
||||
#import "MGLUserLocationHeadingBeamLayer.h"
|
||||
|
||||
#import "MGLFaux3DUserLocationAnnotationView.h"
|
||||
#import "MGLGeometry.h"
|
||||
|
||||
@implementation MGLUserLocationHeadingBeamLayer
|
||||
{
|
||||
CAShapeLayer *_maskLayer;
|
||||
}
|
||||
|
||||
- (instancetype)initWithUserLocationAnnotationView:(MGLUserLocationAnnotationView *)userLocationView
|
||||
{
|
||||
CGFloat size = MGLUserLocationAnnotationHaloSize;
|
||||
|
||||
self = [super init];
|
||||
self.bounds = CGRectMake(0, 0, size, size);
|
||||
self.position = CGPointMake(CGRectGetMidX(userLocationView.bounds), CGRectGetMidY(userLocationView.bounds));
|
||||
self.contents = (__bridge id)[self gradientImageWithTintColor:userLocationView.tintColor.CGColor];
|
||||
self.contentsGravity = kCAGravityBottom;
|
||||
self.contentsScale = UIScreen.mainScreen.scale;
|
||||
self.opacity = 0.4;
|
||||
self.shouldRasterize = YES;
|
||||
self.rasterizationScale = UIScreen.mainScreen.scale;
|
||||
self.drawsAsynchronously = YES;
|
||||
|
||||
_maskLayer = [CAShapeLayer layer];
|
||||
_maskLayer.frame = self.bounds;
|
||||
_maskLayer.path = [self clippingMaskForAccuracy:0];
|
||||
self.mask = _maskLayer;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateHeadingAccuracy:(CLLocationDirection)accuracy
|
||||
{
|
||||
// recalculate the clipping mask based on updated accuracy
|
||||
_maskLayer.path = [self clippingMaskForAccuracy:accuracy];
|
||||
}
|
||||
|
||||
- (void)updateTintColor:(CGColorRef)color
|
||||
{
|
||||
// redraw the raw tinted gradient
|
||||
self.contents = (__bridge id)[self gradientImageWithTintColor:color];
|
||||
}
|
||||
|
||||
- (CGImageRef)gradientImageWithTintColor:(CGColorRef)tintColor
|
||||
{
|
||||
UIImage *image;
|
||||
|
||||
CGFloat haloRadius = MGLUserLocationAnnotationHaloSize / 2.0;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(MGLUserLocationAnnotationHaloSize, haloRadius), NO, 0);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
// gradient from the tint color to no-alpha tint color
|
||||
CGFloat gradientLocations[] = {0.0, 1.0};
|
||||
CGGradientRef gradient = CGGradientCreateWithColors(
|
||||
colorSpace,
|
||||
(__bridge CFArrayRef)@[(__bridge id)tintColor,
|
||||
(id)CFBridgingRelease(CGColorCreateCopyWithAlpha(tintColor, 0))],
|
||||
gradientLocations);
|
||||
|
||||
// draw the gradient from the center point to the edge (full halo radius)
|
||||
CGPoint centerPoint = CGPointMake(haloRadius, haloRadius);
|
||||
CGContextDrawRadialGradient(context, gradient,
|
||||
centerPoint, 0.0,
|
||||
centerPoint, haloRadius,
|
||||
kNilOptions);
|
||||
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
CGGradientRelease(gradient);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
return image.CGImage;
|
||||
}
|
||||
|
||||
- (CGPathRef)clippingMaskForAccuracy:(CGFloat)accuracy
|
||||
{
|
||||
// size the mask using accuracy, but keep within a good display range
|
||||
CGFloat clippingDegrees = 90 - accuracy;
|
||||
clippingDegrees = fmin(clippingDegrees, 70); // most accurate
|
||||
clippingDegrees = fmax(clippingDegrees, 10); // least accurate
|
||||
|
||||
CGRect ovalRect = CGRectMake(0, 0, MGLUserLocationAnnotationHaloSize, MGLUserLocationAnnotationHaloSize);
|
||||
UIBezierPath *ovalPath = UIBezierPath.bezierPath;
|
||||
|
||||
// clip the oval to ± incoming accuracy degrees (converted to radians), from the top
|
||||
[ovalPath addArcWithCenter:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))
|
||||
radius:CGRectGetWidth(ovalRect) / 2.0
|
||||
startAngle:MGLRadiansFromDegrees(-180 + clippingDegrees)
|
||||
endAngle:MGLRadiansFromDegrees(-clippingDegrees)
|
||||
clockwise:YES];
|
||||
|
||||
[ovalPath addLineToPoint:CGPointMake(CGRectGetMidX(ovalRect), CGRectGetMidY(ovalRect))];
|
||||
[ovalPath closePath];
|
||||
|
||||
return ovalPath.CGPath;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user