• 主页
  • 系列总集
  • OpenCV
  • CMake
  • iOS
  • Java
  • 前端
所有文章 关于我

  • 主页
  • 系列总集
  • OpenCV
  • CMake
  • iOS
  • Java
  • 前端

MKMapKit(十):动态轨迹DynamicPathOverlay

2017-03-12

动态轨迹Overlay

根据网上一些代码整理和修改,得出以下的动态轨迹Overlay,其中结构体的Scale代表了颜色的百分比,1为最大值,0为最小值

Github代码

CrumbPathOverlay.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>

typedef struct {
CLLocationCoordinate2D coordinate;
CGFloat scale;
}CrumbPoint;


CG_INLINE CrumbPoint CrumbPointMake(CLLocationCoordinate2D coordinate, CGFloat scale) {
CrumbPoint point;
point.coordinate = coordinate;
point.scale = scale;
return point;
}

@interface CrumbPathOverlay : NSObject <MKOverlay>

@property (nonatomic, weak) MKOverlayRenderer *render;
@property (nonatomic, readonly) CrumbPoint *points;
@property (nonatomic, readonly) NSUInteger pointsCount;

- (instancetype)initWithOrigin:(CrumbPoint)point;

- (void)addCoordinate:(CrumbPoint)point;
- (void)lockPointArray;
- (void)unlockPointArray;

@end

CrumbPathOverlay.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

#import <pthread.h>
#import "CrumbPathOverlay.h"

#define INITIAL_POINT_SPACE 1000
#define MINIMUM_DELTA_METERS 10.0

@interface CrumbPathOverlay()

@property (nonatomic, assign) MKMapRect boundingRect;
@property (nonatomic, assign) pthread_rwlock_t rwLock;
@property (nonatomic, assign) NSUInteger pointSpace;

@end

@implementation CrumbPathOverlay




- (instancetype)initWithOrigin:(CrumbPoint)point {
self = [super init];
if (self) {
_pointSpace = INITIAL_POINT_SPACE;
_pointsCount = 1;
_points = malloc(sizeof(CrumbPoint)*_pointSpace);
_points[0] = point;
_boundingRect = [self worldRectWithCenter:_points[0].coordinate];
pthread_rwlock_init(&_rwLock,NULL);

}
return self;}


- (CLLocationCoordinate2D)coordinate {
return _points[0].coordinate;
}

- (MKMapRect)boundingMapRect {
return _boundingRect;
}


- (MKMapRect)worldRectWithCenter:(CLLocationCoordinate2D)coordinate {
MKMapPoint center = MKMapPointForCoordinate(coordinate);
double width = MKMapSizeWorld.width/4;
double height = MKMapSizeWorld.height/4;
MKMapPoint origin = MKMapPointMake(center.x - width/2, center.y - height/2);

return MKMapRectMake(origin.x, origin.y, width , height);

}


-(void)dealloc{
free(_points);
pthread_rwlock_destroy(&_rwLock);
}



#pragma mark - Point add

- (void)addCoordinate:(CrumbPoint)point {
//LOCK Thread because we are going to changing the list of points
pthread_rwlock_wrlock(&_rwLock);

//receive new point and previous point
MKMapPoint newPoint = MKMapPointForCoordinate(point.coordinate);
MKMapPoint prevPoint = MKMapPointForCoordinate(_points[_pointsCount-1].coordinate);


//Get the distance between this new point and previous point
CLLocationDistance metersApart = MKMetersBetweenMapPoints(newPoint, prevPoint);
MKMapRect updateRect = MKMapRectNull;

if (metersApart > MINIMUM_DELTA_METERS){
//Grow (multiply 2) the points array if full
if (_pointSpace == _pointsCount){
_pointSpace *= 2;
_points = realloc(_points, sizeof(CrumbPoint) * _pointSpace);
}

//Add the new point to points array
_points[_pointsCount] = point;
_pointsCount++;

//Compute MKMapRect bounding prevPoint and newPoint
double minX = MIN(newPoint.x,prevPoint.x);
double minY = MIN(newPoint.y,prevPoint.y);
double maxX = MAX(newPoint.x, prevPoint.x);
double maxY = MAX(newPoint.y, prevPoint.y);

updateRect = MKMapRectMake(minX, minY, maxX - minX, maxY - minY);
}
//UNLOCK Thread
pthread_rwlock_unlock(&_rwLock);

//Make Update Display
if (_render) {
[_render setNeedsDisplayInMapRect:updateRect];
}
}




#pragma mark - Thread Lock

- (void)lockPointArray {
pthread_rwlock_rdlock(&_rwLock);
}

- (void)unlockPointArray {
pthread_rwlock_unlock(&_rwLock);
}

@end

动态轨迹Render

CrumbPathRender.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import "CrumbPathOverlay.h"


@interface CrumbPathRender : MKOverlayPathRenderer

- (instancetype)initWithOverlay:(CrumbPathOverlay *)overlay;

@property (nonatomic, assign) CGFloat beginHue;
@property (nonatomic, assign) CGFloat endHue;
@property (nonatomic, assign) CGFloat minScreenPointDelta;

@end

CrumbPathRender.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#import "CrumbPathRender.h"


@interface CrumbPathRender ()

@property (nonatomic, weak) CrumbPathOverlay *crumb;
@property (nonatomic, assign) CGFloat hueRange;

@end


@implementation CrumbPathRender


- (instancetype)initWithOverlay:(CrumbPathOverlay *)overlay {
self = [super initWithOverlay:overlay];
if (self){
_crumb = overlay;
_beginHue = 0.3;
_endHue = 0.03;
_minScreenPointDelta = 5.0;
_hueRange = _beginHue - _endHue;
_crumb.render = self;
self.fillColor = [UIColor blueColor];
self.lineWidth = 5;
}
return self;
}


- (id<MKOverlay>)overlay {
return _crumb;
}

- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
return _crumb?YES:NO;
}

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {

//Lock Add
[_crumb lockPointArray];

//Prepare ClipRect
CGFloat lineWidth = self.lineWidth;
lineWidth = lineWidth / zoomScale;
MKMapRect clipRect = MKMapRectInset(mapRect, -lineWidth, -lineWidth);


//Make Limit Distance
double minMapPointDelta = pow(_minScreenPointDelta / zoomScale,2);

//For to Add
CrumbPoint point,prevPoint = _crumb.points[0];
for (int i = 1;i < _crumb.pointsCount;i++){
point = _crumb.points[i];
CGMutablePathRef path = CGPathCreateMutable();


//Convert Map Point
MKMapPoint mapPoint = MKMapPointForCoordinate(point.coordinate);
MKMapPoint prevMapPoint = MKMapPointForCoordinate(prevPoint.coordinate);

//Check Delta
double pointDelta = pow(mapPoint.x - prevMapPoint.x,2) + pow(mapPoint.y - prevMapPoint.y,2);
if (pointDelta < minMapPointDelta && i < _crumb.pointsCount - 1) {
prevPoint = point;
continue;
}

//Check Area
if ([CrumbPathRender linePoint:mapPoint and:prevMapPoint intersectsRect:clipRect]) {
//Add Line
CGPoint startPoint = [self pointForMapPoint:mapPoint];
CGPoint endPoint = [self pointForMapPoint:prevMapPoint];
CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
CGPathAddLineToPoint(path, NULL, endPoint.x, endPoint.y);
//Save State
CGContextSaveGState(context);
//Line Prepare
CGPathRef pathToFill = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, self.lineCap, self.lineJoin, self.miterLimit);
CGContextAddPath(context, pathToFill);
CGContextClip(context);
//Color Prepare
UIColor *startColor, *endColor;
if(point.scale == CGFLOAT_MAX) {
startColor = self.fillColor;
endColor = self.fillColor;
} else {
CGFloat scale = [CrumbPathRender distributeScale:prevPoint.scale];
startColor = [CrumbPathRender hueColor:_beginHue - scale *_hueRange];
scale = [CrumbPathRender distributeScale:point.scale];
endColor = [CrumbPathRender hueColor:_beginHue - scale*_hueRange];
}

CGGradientRef gradient = [CrumbPathRender lineColorGradient:startColor and:endColor];
//Add Color
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, kCGGradientDrawsAfterEndLocation);
//Release Color
CGGradientRelease(gradient);
//Return State for Next
CGContextRestoreGState(context);
}
prevPoint = point;
CGPathRelease(path);
}
[_crumb unlockPointArray];
}


+ (CGFloat)distributeScale:(CGFloat)scale {
CGFloat temp = scale;
temp = temp > 1? 1: (temp < 0 ? 0 : temp);
return temp;
}

+ (UIColor *)hueColor:(CGFloat)hue {
return [UIColor colorWithHue:hue saturation:1.0f brightness:1.0f alpha:1.0f];
}


+ (BOOL)linePoint:(MKMapPoint)p0 and:(MKMapPoint)p1 intersectsRect:(MKMapRect) r {
double minX = MIN(p0.x, p1.x);
double minY = MIN(p0.y, p1.y);
double maxX = MAX(p0.x, p1.x);
double maxY = MAX(p0.y, p1.y);

MKMapRect r2 = MKMapRectMake(minX, minY, maxX - minX, maxY - minY);
return MKMapRectIntersectsRect(r, r2);
}

+ (CGGradientRef)lineColorGradient:(UIColor *)startColor and:(UIColor *)endColor {
//Color Prepare
CGFloat pc_r,pc_g,pc_b,pc_a, cc_r,cc_g,cc_b,cc_a;
[startColor getRed:&pc_r green:&pc_g blue:&pc_b alpha:&pc_a];
[endColor getRed:&cc_r green:&cc_g blue:&cc_b alpha:&cc_a];
CGFloat gradientColors[8] = {pc_r,pc_g,pc_b,pc_a, cc_r,cc_g,cc_b,cc_a};
CGFloat gradientLocation[2] = {0,1};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradientColors, gradientLocation, 2);
CGColorSpaceRelease(colorSpace);
return gradient;
}

@end

赏

请问老板还招人么(/ω\)

支付宝
微信
  • iOS
  • MKMapKit
  • Overlay
  • Tutorial

扫一扫,分享到微信

微信分享二维码
MKMapKit(OVA):自定义追踪模式下如何平滑动画
MKMapKit(九):动态圆形DynamicCircleOverlay
© 2021 Alan Li
Hexo Theme Yilia by Litten
  • 所有文章
  • 关于我

tag:

  • iOS
  • Java
  • Collection
  • Python
  • Shell
  • CMake
  • Memory
  • JavaScript
  • Architecture
  • AnchorPoint
  • Android
  • Web
  • Annotation
  • AFNetworking
  • Window
  • ViewController
  • AutoLayout
  • Dozer
  • CoreAnimation
  • Cycle Retain
  • Block
  • UI
  • IDE
  • FrontEnd
  • CSS
  • Category
  • TableViewCell
  • Security
  • Net
  • JSP
  • Spring
  • C
  • MyBatis
  • Date
  • React
  • GCD
  • UITouch
  • Gesture
  • UIControl
  • Git
  • HTML
  • HTTPS
  • HTTP
  • Servlet
  • Server
  • DataBase
  • MySQL
  • Linux
  • Tutorial
  • Ajax
  • Type
  • JQuery
  • JSON
  • Exception
  • Parameter
  • Reflect
  • Thread
  • Sort
  • KVO
  • MKMapKit
  • Overlay
  • Maven
  • Configure
  • Tips
  • Transaction
  • Swift
  • NavigationBar
  • Nginx
  • Runtime
  • OpenCV
  • Property
  • Playground
  • Protocol
  • Redux
  • ScrollView
  • Session
  • Cookie
  • Shiro
  • Error
  • Singleton
  • RegEx
  • StackView
  • StatusBar
  • Base64
  • Socket
  • TCP
  • IP
  • TextField
  • CALayer
  • UILabel
  • View
  • Animation
  • Xcode
  • Hexo
  • Terminal
  • OC
  • Device
  • Log
  • Image
  • JUnit
  • Oval
  • Archive
  • XSS
  • Compiler
  • Aspect
  • Responder
  • Class
  • FireWall
  • RetainCount
  • Const
  • Frame
  • String
  • Symbols
  • Framework
  • CocoaPods
  • Unity
  • Message
  • Button
  • AuthorizationStatus
  • Struct
  • XCTest
  • NSNotification
  • Contact

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

我写的,大概率是错的。。。。。