summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Wray <jason@mapbox.com>2017-08-09 15:43:33 -0400
committerJason Wray <jason@mapbox.com>2017-09-06 18:21:38 -0400
commitc6708442c98665df36eabf3b0b7ca7ba38dfbdb4 (patch)
tree5682ce58f395e15bd8c7665213856db435175d86
parentcb7eb5cafb18ed24d01a9d091b68ed4f0584966b (diff)
downloadqtlocation-mapboxgl-c6708442c98665df36eabf3b0b7ca7ba38dfbdb4.tar.gz
[ios] Refactor user location heading indicator into its own class
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj12
-rw-r--r--platform/ios/src/MGLFaux3DUserLocationAnnotationView.h7
-rw-r--r--platform/ios/src/MGLFaux3DUserLocationAnnotationView.m133
-rw-r--r--platform/ios/src/MGLUserLocationHeadingBeamLayer.h10
-rw-r--r--platform/ios/src/MGLUserLocationHeadingBeamLayer.m104
5 files changed, 147 insertions, 119 deletions
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 76b35be2de..6408eb9087 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -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 */,
diff --git a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h
index c48dd6b27b..d5dae3a919 100644
--- a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h
+++ b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.h
@@ -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
-
diff --git a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
index 5f67f24f4e..36c5292127 100644
--- a/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
+++ b/platform/ios/src/MGLFaux3DUserLocationAnnotationView.m
@@ -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];
- }
-
- // heading indicator accuracy mask (fan-shaped)
- //
- if ( ! _headingIndicatorMaskLayer && self.userLocation.heading.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;
+ _oldHeadingAccuracy = headingAccuracy;
}
- else if (_oldHeadingAccuracy != self.userLocation.heading.headingAccuracy)
+ else if (_oldHeadingAccuracy != 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
diff --git a/platform/ios/src/MGLUserLocationHeadingBeamLayer.h b/platform/ios/src/MGLUserLocationHeadingBeamLayer.h
new file mode 100644
index 0000000000..9a5d4a8f14
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingBeamLayer.h
@@ -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
diff --git a/platform/ios/src/MGLUserLocationHeadingBeamLayer.m b/platform/ios/src/MGLUserLocationHeadingBeamLayer.m
new file mode 100644
index 0000000000..efe7e4db93
--- /dev/null
+++ b/platform/ios/src/MGLUserLocationHeadingBeamLayer.m
@@ -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