initial
This commit is contained in:
Generated
+30
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// MATraceReplayOverlay+Addition.h
|
||||
// MAMapKit
|
||||
//
|
||||
// Created by shaobin on 2017/4/20.
|
||||
// Copyright © 2017年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MATraceReplayOverlay.h"
|
||||
|
||||
@interface MATraceReplayOverlay (Addition)
|
||||
|
||||
/**
|
||||
* @brief 每次帧绘制时调用
|
||||
* @param timeDelta 时间
|
||||
* @param zoomLevel 地图zoom
|
||||
*/
|
||||
- (void)drawStepWithTime:(NSTimeInterval)timeDelta zoomLevel:(CGFloat)zoomLevel;
|
||||
|
||||
/**
|
||||
* @brief 获取内部mutlipolyine
|
||||
*/
|
||||
- (MAMultiPolyline *)getMultiPolyline;
|
||||
|
||||
/**
|
||||
* @brief 获取内部patchLine
|
||||
*/
|
||||
- (MAPolyline *)getPatchPolyline;
|
||||
|
||||
@end
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// MATraceReplayOverlay.h
|
||||
// MAMapKit
|
||||
//
|
||||
// Created by shaobin on 2017/4/20.
|
||||
// Copyright © 2017年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AMapNaviKit/MAMapKit.h>
|
||||
|
||||
///轨迹回放overlay(since 5.1.0)
|
||||
@interface MATraceReplayOverlay : MABaseOverlay
|
||||
|
||||
///是否启动点抽稀,默认YES
|
||||
@property (nonatomic, assign) BOOL enablePointsReduce;
|
||||
|
||||
///小汽车移动速度,默认80 km/h, 单位米每秒
|
||||
@property (nonatomic, assign) CGFloat speed;
|
||||
|
||||
///是否自动调整车头方向,默认NO
|
||||
@property (nonatomic, assign) BOOL enableAutoCarDirection;
|
||||
|
||||
///是否暂停, 初始为YES
|
||||
@property (nonatomic, assign) BOOL isPaused;
|
||||
|
||||
///各个点权重设置,取值1-5,5最大。权重为5则不对此点做抽稀。格式为:{weight:indices}
|
||||
@property (nonatomic, strong) NSDictionary<NSNumber*, NSArray*> *pointsWeight;
|
||||
|
||||
/**
|
||||
* @brief 重置为初始状态
|
||||
*/
|
||||
- (void)reset;
|
||||
|
||||
/**
|
||||
* @brief 根据map point设置轨迹点
|
||||
* @param points map point数据,points对应的内存会拷贝,调用者负责该内存的释放
|
||||
* @param count map point个数
|
||||
* @return 返回是否成功
|
||||
*/
|
||||
- (BOOL)setWithPoints:(MAMapPoint *)points count:(NSInteger)count;
|
||||
|
||||
/**
|
||||
* @brief 根据经纬度坐标设置轨迹点
|
||||
* @param coords 经纬度坐标数据,coords对应的内存会拷贝,调用者负责该内存的释放
|
||||
* @param count 经纬度坐标个数
|
||||
* @return 返回是否成功
|
||||
*/
|
||||
- (BOOL)setWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSInteger)count;
|
||||
|
||||
/**
|
||||
* @brief 获取当前car所在位置点索引
|
||||
*/
|
||||
- (NSInteger)getOrigPointIndexOfCar;
|
||||
|
||||
/**
|
||||
* @brief 获取抽稀后当前car所在位置点索引
|
||||
*/
|
||||
- (NSInteger)getReducedPointIndexOfCar;
|
||||
|
||||
/**
|
||||
* @brief 获取行进方向,in radian
|
||||
*/
|
||||
- (CGFloat)getRunningDirection;
|
||||
|
||||
/**
|
||||
* @brief 获取索引index对应的mapPoint
|
||||
*/
|
||||
- (MAMapPoint)getMapPointOfIndex:(NSInteger)origIndex;
|
||||
|
||||
/**
|
||||
* @brief 获取小车位置
|
||||
*/
|
||||
- (MAMapPoint)getCarPosition;
|
||||
|
||||
/**
|
||||
* @brief 预处理,加快后面的操作流畅度. 调用前不要把overlay加到mapview,在callback中再把overlay加到mapview
|
||||
*/
|
||||
- (void)prepareAsync:(void(^)())callback;
|
||||
|
||||
@end
|
||||
+523
@@ -0,0 +1,523 @@
|
||||
//
|
||||
// MATraceReplayOverlay.m
|
||||
// MAMapKit
|
||||
//
|
||||
// Created by shaobin on 2017/4/20.
|
||||
// Copyright © 2017年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MATraceReplayOverlay.h"
|
||||
#import "MATraceReplayOverlay+Addition.h"
|
||||
|
||||
struct MATraceReplayPoint{
|
||||
double x; ///<x坐标
|
||||
double y; ///<y坐标
|
||||
int weight; ///<权重
|
||||
int flag; ///<标志位, 1保留,0去除
|
||||
double distance; ///<和下一点的距离
|
||||
};
|
||||
|
||||
typedef struct MATraceReplayPoint MATraceReplayPoint;
|
||||
|
||||
@interface MATraceReplayOverlay () {
|
||||
MAMultiPolyline *_multiPolyline;
|
||||
MAPolyline *_patchLine; //小车位置到下一个轨迹点的线段
|
||||
MAMapPoint _patchLinePoints[2];
|
||||
|
||||
MATraceReplayPoint *_origMapPoints;
|
||||
NSInteger _origPointCount;
|
||||
|
||||
NSInteger _carIndexInOrigArray;
|
||||
NSInteger _reducedPointIndexOfCar;
|
||||
|
||||
BOOL _needRecalculateMapPoints;
|
||||
|
||||
CGFloat _zoomLevel;
|
||||
|
||||
CGFloat _accumulatedDistance;
|
||||
MAMapPoint _carMapPoint;
|
||||
CGFloat _runningDirection;
|
||||
|
||||
BOOL _readyForDrawing;
|
||||
|
||||
NSMutableDictionary *_reducedPointsCache; //{zoomLevel:IndexArray}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MATraceReplayOverlay
|
||||
|
||||
- (id)init {
|
||||
self = [super init];
|
||||
|
||||
if(self) {
|
||||
|
||||
self.isPaused = YES;
|
||||
_multiPolyline = [MAMultiPolyline polylineWithCoordinates:NULL count:0 drawStyleIndexes:nil];
|
||||
_patchLine = [MAPolyline polylineWithPoints:NULL count:0];
|
||||
_enablePointsReduce = YES;
|
||||
_zoomLevel = 0;
|
||||
_speed = 80.0*1000/3600;
|
||||
|
||||
_reducedPointsCache = [NSMutableDictionary dictionaryWithCapacity:20];
|
||||
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if(_origMapPoints) {
|
||||
free(_origMapPoints);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setEnablePointsReduce:(BOOL)enablePointsReduce {
|
||||
if(_enablePointsReduce != enablePointsReduce) {
|
||||
_enablePointsReduce = enablePointsReduce;
|
||||
_needRecalculateMapPoints = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
self.isPaused = YES;
|
||||
_carIndexInOrigArray = 0;
|
||||
_multiPolyline.drawStyleIndexes = nil;
|
||||
_readyForDrawing = NO;
|
||||
}
|
||||
|
||||
- (BOOL)setWithPoints:(MAMapPoint *)points count:(NSInteger)count {
|
||||
if(points == NULL || count <= 0) {
|
||||
if (_origMapPoints != NULL) {
|
||||
free(_origMapPoints), _origMapPoints = NULL;
|
||||
}
|
||||
_origPointCount = 0;
|
||||
|
||||
[_reducedPointsCache removeAllObjects];
|
||||
|
||||
_needRecalculateMapPoints = YES;
|
||||
[self recalculateMapPoints];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
MATraceReplayPoint *oldPoints = _origMapPoints;
|
||||
_origMapPoints = (MATraceReplayPoint*)calloc(count, sizeof(MATraceReplayPoint));
|
||||
if(_origMapPoints == NULL) {
|
||||
_origMapPoints = oldPoints;
|
||||
return NO;
|
||||
}
|
||||
|
||||
_origPointCount = count;
|
||||
MATraceReplayPoint *curP1 = _origMapPoints;
|
||||
MAMapPoint *curP2 = points;
|
||||
for(int i = 0; i < count; ++i) {
|
||||
curP1->x = curP2->x;
|
||||
curP1->y = curP2->y;
|
||||
curP1->weight = 1;
|
||||
curP1->flag = 1;
|
||||
|
||||
curP1++;
|
||||
curP2++;
|
||||
}
|
||||
|
||||
for(int i = 0; i < count - 1; ++i) {
|
||||
MAMapPoint p1 = MAMapPointMake(_origMapPoints[i].x, _origMapPoints[i].y);
|
||||
MAMapPoint p2 = MAMapPointMake(_origMapPoints[i+1].x, _origMapPoints[i+1].y);
|
||||
_origMapPoints[i].distance = MAMetersBetweenMapPoints(p1, p2);
|
||||
}
|
||||
|
||||
if(oldPoints != NULL) {
|
||||
free(oldPoints);
|
||||
}
|
||||
|
||||
[_reducedPointsCache removeAllObjects];
|
||||
|
||||
_needRecalculateMapPoints = YES;
|
||||
[self recalculateMapPoints];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)setWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSInteger)count {
|
||||
if(coords == NULL || count <= 0) {
|
||||
if (_origMapPoints != NULL) {
|
||||
free(_origMapPoints), _origMapPoints = NULL;
|
||||
}
|
||||
_origPointCount = 0;
|
||||
|
||||
[_reducedPointsCache removeAllObjects];
|
||||
|
||||
_needRecalculateMapPoints = YES;
|
||||
[self recalculateMapPoints];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
MATraceReplayPoint *oldPoints = _origMapPoints;
|
||||
_origMapPoints = (MATraceReplayPoint*)calloc(count, sizeof(MATraceReplayPoint));
|
||||
if(_origMapPoints == NULL) {
|
||||
_origMapPoints = oldPoints;
|
||||
return NO;
|
||||
}
|
||||
|
||||
_origPointCount = count;
|
||||
MATraceReplayPoint *curP1 = _origMapPoints;
|
||||
for(int i = 0; i < count; ++i) {
|
||||
MAMapPoint p = MAMapPointForCoordinate(coords[i]);
|
||||
curP1->x = p.x;
|
||||
curP1->y = p.y;
|
||||
curP1->weight = 1;
|
||||
curP1->flag = 1;
|
||||
|
||||
curP1++;
|
||||
}
|
||||
|
||||
for(int i = 0; i < count - 1; ++i) {
|
||||
MAMapPoint p1 = MAMapPointMake(_origMapPoints[i].x, _origMapPoints[i].y);
|
||||
MAMapPoint p2 = MAMapPointMake(_origMapPoints[i+1].x, _origMapPoints[i+1].y);
|
||||
_origMapPoints[i].distance = MAMetersBetweenMapPoints(p1, p2);
|
||||
}
|
||||
|
||||
if(oldPoints != NULL) {
|
||||
free(oldPoints);
|
||||
}
|
||||
|
||||
[_reducedPointsCache removeAllObjects];
|
||||
|
||||
_needRecalculateMapPoints = YES;
|
||||
[self recalculateMapPoints];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setPointsWeight:(NSDictionary<NSNumber *,NSArray *> *)pointsWeight {
|
||||
_pointsWeight = pointsWeight;
|
||||
for(NSNumber *key in [pointsWeight allKeys]) {
|
||||
int weight = key.intValue;
|
||||
if(weight > 5 || weight < 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NSArray *indices = [pointsWeight objectForKey:key];
|
||||
for(NSNumber *index in indices) {
|
||||
int i = index.intValue;
|
||||
if(i < _origPointCount) {
|
||||
_origMapPoints[i].weight = weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[_reducedPointsCache removeAllObjects];
|
||||
|
||||
_needRecalculateMapPoints = YES;
|
||||
[self recalculateMapPoints];
|
||||
}
|
||||
|
||||
- (NSInteger)getOrigPointIndexOfCar {
|
||||
return _carIndexInOrigArray;
|
||||
}
|
||||
|
||||
- (NSInteger)getReducedPointIndexOfCar {
|
||||
if(!_enablePointsReduce) {
|
||||
return [self getOrigPointIndexOfCar];
|
||||
}
|
||||
|
||||
return _reducedPointIndexOfCar;
|
||||
}
|
||||
|
||||
- (CGFloat)getRunningDirection {
|
||||
return _runningDirection;
|
||||
}
|
||||
|
||||
- (MAMapPoint)getMapPointOfIndex:(NSInteger)origIndex {
|
||||
if(origIndex >= _origPointCount) {
|
||||
return MAMapPointMake(0, 0);
|
||||
}
|
||||
return MAMapPointMake(_origMapPoints[origIndex].x, _origMapPoints[origIndex].y);
|
||||
}
|
||||
|
||||
- (MAMapPoint)getCarPosition {
|
||||
return _carMapPoint;
|
||||
}
|
||||
|
||||
#pragma mark - overlay
|
||||
- (MAMapRect)boundingMapRect {
|
||||
if(_needRecalculateMapPoints) {
|
||||
return MAMapRectWorld;
|
||||
}
|
||||
return _multiPolyline.boundingMapRect;
|
||||
}
|
||||
|
||||
- (CLLocationCoordinate2D)coordinate {
|
||||
MAMapRect boundimgMapRect = [self boundingMapRect];
|
||||
return MACoordinateForMapPoint(MAMapPointMake(MAMapRectGetMidX(boundimgMapRect), MAMapRectGetMidY(boundimgMapRect)));
|
||||
}
|
||||
|
||||
#pragma mark - addition
|
||||
- (MAMultiPolyline *)getMultiPolyline {
|
||||
return _multiPolyline;
|
||||
}
|
||||
|
||||
- (MAPolyline *)getPatchPolyline {
|
||||
return _patchLine;
|
||||
}
|
||||
|
||||
- (void)drawStepWithTime:(NSTimeInterval)timeDelta zoomLevel:(CGFloat)zoomLevel {
|
||||
[self setZoomLevel:zoomLevel];
|
||||
|
||||
BOOL hasRecalculated = [self recalculateMapPoints];
|
||||
//计算小车位置索引
|
||||
if(!_isPaused || !_readyForDrawing || hasRecalculated) {
|
||||
if(_isPaused) {
|
||||
timeDelta = 0;
|
||||
}
|
||||
|
||||
//计算最后一个flag=1的点的索引
|
||||
NSInteger theLastIndex = _origPointCount - 1;
|
||||
while(theLastIndex > 0 && _origMapPoints[theLastIndex].flag != 1) {
|
||||
theLastIndex--;
|
||||
}
|
||||
|
||||
NSInteger curIndex = _carIndexInOrigArray;
|
||||
if(curIndex >= (_origPointCount - 1)) {
|
||||
_carMapPoint = MAMapPointMake(_origMapPoints[theLastIndex].x, _origMapPoints[theLastIndex].y);
|
||||
[_patchLine setPolylineWithPoints:NULL count:0];
|
||||
_multiPolyline.drawStyleIndexes = @[@(_multiPolyline.pointCount - 1)];
|
||||
|
||||
_runningDirection = MAGetDirectionFromPoints(_multiPolyline.points[_multiPolyline.pointCount - 2], _multiPolyline.points[_multiPolyline.pointCount - 1]) * M_PI / 180;
|
||||
self.isPaused = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
double deltaDistance = _speed * timeDelta;
|
||||
_accumulatedDistance += deltaDistance;
|
||||
while(curIndex < _origPointCount) {
|
||||
double distance = _origMapPoints[curIndex].distance;
|
||||
if(_accumulatedDistance > distance) {
|
||||
curIndex++;
|
||||
_accumulatedDistance -= distance;
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_carIndexInOrigArray = curIndex;
|
||||
if(curIndex >= (_origPointCount - 1)) {
|
||||
_carMapPoint = MAMapPointMake(_origMapPoints[theLastIndex].x, _origMapPoints[theLastIndex].y);
|
||||
[_patchLine setPolylineWithPoints:NULL count:0];
|
||||
_multiPolyline.drawStyleIndexes = @[@(_multiPolyline.pointCount - 1)];
|
||||
|
||||
_runningDirection = MAGetDirectionFromPoints(_multiPolyline.points[_multiPolyline.pointCount - 2], _multiPolyline.points[_multiPolyline.pointCount - 1]) * M_PI / 180;
|
||||
self.isPaused = YES;
|
||||
return;
|
||||
}
|
||||
|
||||
//计算当前小车所在polyline的子线段的端点索引
|
||||
NSInteger prevIndex = curIndex;
|
||||
NSInteger nextIndex = curIndex + 1;
|
||||
while(prevIndex > 0 && _origMapPoints[prevIndex].flag != 1) {
|
||||
prevIndex--;
|
||||
}
|
||||
while(nextIndex <= theLastIndex && _origMapPoints[nextIndex].flag != 1) {
|
||||
nextIndex++;
|
||||
}
|
||||
|
||||
//计算小车位置
|
||||
double passedDistance = 0;
|
||||
for(NSInteger i = prevIndex; i < curIndex; ++i) {
|
||||
passedDistance += _origMapPoints[i].distance;
|
||||
}
|
||||
double totalDistance = passedDistance;
|
||||
for(NSInteger i = curIndex; i < nextIndex; ++i) {
|
||||
totalDistance += _origMapPoints[i].distance;
|
||||
}
|
||||
float ratio = (passedDistance + _accumulatedDistance) / totalDistance;
|
||||
|
||||
MAMapPoint p1 = MAMapPointMake(_origMapPoints[prevIndex].x, _origMapPoints[prevIndex].y);
|
||||
MAMapPoint p2 = MAMapPointMake(_origMapPoints[nextIndex].x, _origMapPoints[nextIndex].y);
|
||||
_carMapPoint.x = p1.x + ratio * (p2.x - p1.x);
|
||||
_carMapPoint.y = p1.y + ratio * (p2.y - p1.y);
|
||||
|
||||
//计算小车方向
|
||||
_runningDirection = MAGetDirectionFromPoints(MAMapPointMake(p1.x, p1.y), MAMapPointMake(p2.x, p2.y)) * M_PI / 180;
|
||||
|
||||
//更新小车在polyline里的索引
|
||||
NSInteger ret = 0;
|
||||
for(int i = 0; i < prevIndex; ++i) {
|
||||
if(_origMapPoints[i].flag == 1) {
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
_reducedPointIndexOfCar = ret;
|
||||
|
||||
//更新polyline的drawIndex
|
||||
if(_carIndexInOrigArray == 0) {
|
||||
_multiPolyline.drawStyleIndexes = nil;
|
||||
//更新patchline
|
||||
[_patchLine setPolylineWithPoints:NULL count:0];
|
||||
} else {
|
||||
_multiPolyline.drawStyleIndexes = @[@(_reducedPointIndexOfCar + 1)];
|
||||
|
||||
//更新patchline
|
||||
_patchLinePoints[0] = _carMapPoint;
|
||||
_patchLinePoints[1] = p2;
|
||||
[_patchLine setPolylineWithPoints:_patchLinePoints count:2];
|
||||
}
|
||||
}
|
||||
|
||||
if(!_readyForDrawing) {
|
||||
_readyForDrawing = YES;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - private
|
||||
- (void)setZoomLevel:(CGFloat)zoomLevel {
|
||||
int prevZoomLevel = floor(_zoomLevel);
|
||||
int currentoomLevel = floor(zoomLevel);
|
||||
if(prevZoomLevel != currentoomLevel) {
|
||||
_needRecalculateMapPoints = YES;
|
||||
}
|
||||
|
||||
_zoomLevel = zoomLevel;
|
||||
}
|
||||
|
||||
- (void)reducer_RDP:(MATraceReplayPoint *)inPoints
|
||||
fromIndex:(NSInteger)fromIndex
|
||||
toIndex:(NSInteger)toIndex
|
||||
threshHold:(float)threshHold {
|
||||
NSInteger count = toIndex - fromIndex + 1;
|
||||
if(count <= 2) {
|
||||
for(NSInteger i = 0; i < count; ++i) {
|
||||
inPoints[i].flag = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double max = 0;
|
||||
NSInteger index = 0;
|
||||
MAMapPoint firstPoint = MAMapPointMake(inPoints[fromIndex].x, inPoints[fromIndex].y);
|
||||
MAMapPoint lastPoint = MAMapPointMake(inPoints[toIndex].x, inPoints[toIndex].y);
|
||||
for(NSInteger i = fromIndex; i <= toIndex; ++i) {
|
||||
MAMapPoint curP = MAMapPointMake(inPoints[i].x, inPoints[i].y);
|
||||
double d = MAGetDistanceFromPointToLine(curP, firstPoint, lastPoint);
|
||||
if(d > max) {
|
||||
index = i;
|
||||
max = d;
|
||||
}
|
||||
}
|
||||
|
||||
if(max < threshHold) {
|
||||
inPoints[fromIndex].flag = 1;
|
||||
inPoints[toIndex].flag = 1;
|
||||
} else {
|
||||
[self reducer_RDP:inPoints fromIndex:fromIndex toIndex:index threshHold:threshHold];
|
||||
[self reducer_RDP:inPoints fromIndex:index toIndex:toIndex threshHold:threshHold];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)recalculateMapPoints {
|
||||
if(!_needRecalculateMapPoints) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
///重新做抽稀
|
||||
if(_enablePointsReduce) {
|
||||
int zoomLevel = floor(_zoomLevel);
|
||||
NSNumber *key = @(zoomLevel);
|
||||
NSArray *indexArray = [_reducedPointsCache objectForKey:key];
|
||||
|
||||
for(NSInteger i = 0; i < _origPointCount; ++i) {
|
||||
_origMapPoints[i].flag = 0;
|
||||
}
|
||||
|
||||
if(!indexArray) {
|
||||
CGFloat metersPerPixel = exp2(19 - zoomLevel);
|
||||
metersPerPixel = fmax(1, metersPerPixel);
|
||||
[self reducer_RDP:_origMapPoints fromIndex:0 toIndex:_origPointCount - 1 threshHold:metersPerPixel];
|
||||
|
||||
NSMutableArray<NSNumber*> *tempArr = [NSMutableArray array];
|
||||
for(NSInteger i = 0; i < _origPointCount; ++i) {
|
||||
if(_origMapPoints[i].flag == 1 || _origMapPoints[i].weight == 5) {
|
||||
[tempArr addObject:@(i)];
|
||||
}
|
||||
}
|
||||
|
||||
indexArray = tempArr;
|
||||
|
||||
[_reducedPointsCache setObject:indexArray forKey:key];
|
||||
}
|
||||
|
||||
if (indexArray.count > 0) {
|
||||
for(NSNumber *indexObj in indexArray) {
|
||||
int index = indexObj.intValue;
|
||||
_origMapPoints[index].flag = 1;
|
||||
}
|
||||
|
||||
NSInteger count = indexArray.count;
|
||||
MAMapPoint *p = (MAMapPoint *)malloc(sizeof(MAMapPoint) * count);
|
||||
if(p) {
|
||||
for(int i = 0; i < count; ++i) {
|
||||
NSNumber *indexObj = [indexArray objectAtIndex:i];
|
||||
int index = indexObj.intValue;
|
||||
p[i].x = _origMapPoints[index].x;
|
||||
p[i].y = _origMapPoints[index].y;
|
||||
}
|
||||
[_multiPolyline setPolylineWithPoints:p count:count drawStyleIndexes:nil];
|
||||
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
MAMapPoint *p = (MAMapPoint *)malloc(sizeof(MAMapPoint) * _origPointCount);
|
||||
if(p) {
|
||||
for(int i = 0; i < _origPointCount; ++i) {
|
||||
p[i].x = _origMapPoints[i].x;
|
||||
p[i].y = _origMapPoints[i].y;
|
||||
}
|
||||
[_multiPolyline setPolylineWithPoints:p count:_origPointCount drawStyleIndexes:nil];
|
||||
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
_needRecalculateMapPoints = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)prepareAsync:(void(^)())callback {
|
||||
if([NSThread isMainThread]) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
[weakSelf prepareAsync:callback];
|
||||
});
|
||||
} else {
|
||||
for(NSInteger i = 0; i < _origPointCount; ++i) {
|
||||
_origMapPoints[i].flag = 0;
|
||||
}
|
||||
|
||||
for(int zoomLevel = 3; zoomLevel <= 20; ++zoomLevel) {
|
||||
CGFloat metersPerPixel = exp2(19 - zoomLevel);
|
||||
metersPerPixel = fmax(1, metersPerPixel);
|
||||
[self reducer_RDP:_origMapPoints fromIndex:0 toIndex:_origPointCount - 1 threshHold:metersPerPixel];
|
||||
|
||||
NSMutableArray<NSNumber*> *tempArr = [NSMutableArray array];
|
||||
for(NSInteger i = 0; i < _origPointCount; ++i) {
|
||||
if(_origMapPoints[i].flag == 1 || _origMapPoints[i].weight == 5) {
|
||||
[tempArr addObject:@(i)];
|
||||
}
|
||||
}
|
||||
|
||||
[_reducedPointsCache setObject:tempArr forKey:@(zoomLevel)];
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if(callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@end
|
||||
Generated
+22
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// MATraceReplayOverlayRender.h
|
||||
// MAMapKit
|
||||
//
|
||||
// Created by shaobin on 2017/4/20.
|
||||
// Copyright © 2017年 Amap. All rights reserved.
|
||||
//
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AMapNaviKit/MAMapKit.h>
|
||||
|
||||
///轨迹回放overlay渲染器(since 5.1.0)
|
||||
@interface MATraceReplayOverlayRenderer : MAOverlayPathRenderer
|
||||
|
||||
///轨迹回放图标,会沿轨迹平滑移动
|
||||
@property (nonatomic, strong) UIImage *carImage;
|
||||
|
||||
///分段绘制的颜色,需要分段颜色绘制时,数组大小必须是2,第一个颜色是走过轨迹的颜色,第二个颜色是未走过的
|
||||
@property (nonatomic, strong) NSArray *strokeColors;
|
||||
|
||||
- (void)reset;
|
||||
|
||||
@end
|
||||
Generated
+327
@@ -0,0 +1,327 @@
|
||||
//
|
||||
// MATraceReplayOverlayRender.m
|
||||
// MAMapKit
|
||||
//
|
||||
// Created by shaobin on 2017/4/20.
|
||||
// Copyright © 2017年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MATraceReplayOverlayRender.h"
|
||||
#import "MATraceReplayOverlay.h"
|
||||
#import "MATraceReplayOverlay+Addition.h"
|
||||
#import <GLKit/GLKit.h>
|
||||
#import <OpenGLES/ES2/gl.h>
|
||||
#import <DDCategoryKit_Private/UIImage+DDCategory.h>
|
||||
|
||||
typedef struct _MADrawPoint {
|
||||
float x;
|
||||
float y;
|
||||
} MADrawPoint;
|
||||
|
||||
@interface MATraceReplayOverlayRenderer () {
|
||||
MAMultiColoredPolylineRenderer *_proxyRender;
|
||||
NSTimeInterval _prevTime;
|
||||
|
||||
MAPolylineRenderer *_patchLineRender;
|
||||
|
||||
CGPoint _imageMapPoints[4];
|
||||
GLuint _textureName;
|
||||
GLuint _programe;
|
||||
GLuint _uniform_viewMatrix_location;
|
||||
GLuint _uniform_projMatrix_location;
|
||||
GLuint _attribute_position_location;
|
||||
GLuint _attribute_texCoord_location;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MATraceReplayOverlayRenderer
|
||||
|
||||
- (id)initWithOverlay:(id<MAOverlay>)overlay {
|
||||
if(![overlay isKindOfClass:[MATraceReplayOverlay class]]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self = [super initWithOverlay:overlay];
|
||||
if(self) {
|
||||
MATraceReplayOverlay *traceOverlay = (MATraceReplayOverlay*)overlay;
|
||||
_proxyRender = [[MAMultiColoredPolylineRenderer alloc] initWithMultiPolyline:[traceOverlay getMultiPolyline]];
|
||||
_proxyRender.gradient = NO;
|
||||
_proxyRender.strokeColors = @[[UIColor grayColor], [UIColor greenColor]];
|
||||
_proxyRender.strokeColor = _proxyRender.strokeColors.lastObject;
|
||||
|
||||
_patchLineRender = [[MAPolylineRenderer alloc] initWithPolyline:[traceOverlay getPatchPolyline]];
|
||||
_patchLineRender.strokeColor = _proxyRender.strokeColors.lastObject;
|
||||
|
||||
_carImage = [UIImage dd_imageNamed:@"DDMAMap/my_location" bundleName:@"DDMAMapKit_Private" aClass:[self class]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if(_textureName) {
|
||||
glDeleteTextures(1, &_textureName);
|
||||
_textureName = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)glRender
|
||||
{
|
||||
MATraceReplayOverlay *traceOverlay = (MATraceReplayOverlay*)self.overlay;
|
||||
|
||||
CGFloat zoomLevel = [self getMapZoomLevel];
|
||||
if(_prevTime == 0) {
|
||||
_prevTime = CFAbsoluteTimeGetCurrent();
|
||||
[traceOverlay drawStepWithTime:0 zoomLevel:zoomLevel];
|
||||
} else {
|
||||
NSTimeInterval curTime = CFAbsoluteTimeGetCurrent();
|
||||
[traceOverlay drawStepWithTime:curTime - _prevTime zoomLevel:zoomLevel];
|
||||
_prevTime = curTime;
|
||||
}
|
||||
|
||||
if(self.carImage && [traceOverlay getMultiPolyline].pointCount > 0) {
|
||||
[_proxyRender glRender];
|
||||
[_patchLineRender glRender];
|
||||
|
||||
[self renderCarImage];
|
||||
} else {
|
||||
[_proxyRender glRender];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setRendererDelegate:(id<MAOverlayRenderDelegate>)rendererDelegate {
|
||||
[super setRendererDelegate:rendererDelegate];
|
||||
_proxyRender.rendererDelegate = rendererDelegate;
|
||||
_patchLineRender.rendererDelegate = rendererDelegate;
|
||||
}
|
||||
|
||||
- (void)setLineWidth:(CGFloat)lineWidth {
|
||||
[super setLineWidth:lineWidth];
|
||||
_proxyRender.lineWidth = lineWidth;
|
||||
_patchLineRender.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
- (void)setStrokeColors:(NSArray *)strokeColors {
|
||||
if(strokeColors.count != 2) {
|
||||
return;
|
||||
}
|
||||
_proxyRender.strokeColors = strokeColors;
|
||||
|
||||
if(strokeColors.count > 0) {
|
||||
_proxyRender.strokeColor = strokeColors.lastObject;
|
||||
_patchLineRender.strokeColor = strokeColors.lastObject;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)strokeColors {
|
||||
return _proxyRender.strokeColors;
|
||||
}
|
||||
|
||||
- (void)setStrokeColor:(UIColor *)strokeColor {
|
||||
[super setStrokeColor:strokeColor];
|
||||
[_proxyRender setStrokeColor:strokeColor];
|
||||
[_patchLineRender setStrokeColor:strokeColor];
|
||||
}
|
||||
|
||||
- (UIColor *)strokeColor {
|
||||
return _proxyRender.strokeColor;
|
||||
}
|
||||
|
||||
- (void)reset {
|
||||
_prevTime = 0;
|
||||
}
|
||||
|
||||
- (void)renderCarImage {
|
||||
if(_textureName == 0) {
|
||||
NSError *error = nil;
|
||||
GLKTextureInfo *texInfo = [GLKTextureLoader textureWithCGImage:self.carImage.CGImage options:nil error:&error];
|
||||
_textureName = texInfo.name;
|
||||
}
|
||||
|
||||
if(_programe == 0) {
|
||||
_programe = [self loadGLESPrograme];
|
||||
}
|
||||
|
||||
if(_textureName == 0 || _programe == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
MATraceReplayOverlay *traceOverlay = (MATraceReplayOverlay*)self.overlay;
|
||||
MAMapPoint carPoint = [traceOverlay getCarPosition];
|
||||
CLLocationDirection rotate = [traceOverlay getRunningDirection];
|
||||
|
||||
double zoomLevel = [self getMapZoomLevel];
|
||||
double zoomScale = pow(2, zoomLevel);
|
||||
|
||||
CGSize imageSize = self.carImage.size;
|
||||
|
||||
double halfWidth = imageSize.width * (1 << 20) / zoomScale/2;
|
||||
double halfHeight = imageSize.height * (1 << 20) / zoomScale/2;
|
||||
|
||||
_imageMapPoints[0].x = -halfWidth;
|
||||
_imageMapPoints[0].y = halfHeight;
|
||||
_imageMapPoints[1].x = halfWidth;
|
||||
_imageMapPoints[1].y = halfHeight;
|
||||
_imageMapPoints[2].x = halfWidth;
|
||||
_imageMapPoints[2].y = -halfHeight;
|
||||
_imageMapPoints[3].x = -halfWidth;
|
||||
_imageMapPoints[3].y = -halfHeight;
|
||||
|
||||
|
||||
MADrawPoint points[4] = { 0 };
|
||||
for(int i = 0; i < 4; ++i) {
|
||||
CGPoint tempPoint = _imageMapPoints[i];
|
||||
if(traceOverlay.enableAutoCarDirection) {
|
||||
tempPoint = CGPointApplyAffineTransform(_imageMapPoints[i], CGAffineTransformMakeRotation(rotate));
|
||||
}
|
||||
|
||||
tempPoint.x += carPoint.x;
|
||||
tempPoint.y += carPoint.y;
|
||||
CGPoint p = [self glPointForMapPoint:MAMapPointMake(tempPoint.x, tempPoint.y)];
|
||||
points[i].x = p.x;
|
||||
points[i].y = p.y;
|
||||
}
|
||||
|
||||
float *viewMatrix = [self getViewMatrix];
|
||||
float *projectionMatrix = [self getProjectionMatrix];
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);//纹理和顶点皆已做过预乘alpha值处理
|
||||
|
||||
|
||||
glUseProgram(_programe);
|
||||
glBindTexture(GL_TEXTURE_2D, _textureName);
|
||||
|
||||
//glUseProgram(shaderToUse.programName);
|
||||
glEnableVertexAttribArray(_attribute_position_location);
|
||||
glEnableVertexAttribArray(_attribute_texCoord_location);
|
||||
|
||||
glUniformMatrix4fv(_uniform_viewMatrix_location, 1, false, viewMatrix);
|
||||
glUniformMatrix4fv(_uniform_projMatrix_location, 1, false, projectionMatrix);
|
||||
|
||||
MADrawPoint textureCoords[4] = {
|
||||
0.0, 1.0,
|
||||
1.0, 1.0,
|
||||
1.0, 0.0,
|
||||
0.0, 0.0
|
||||
};
|
||||
glVertexAttribPointer(_attribute_position_location, 2, GL_FLOAT, false, sizeof(MADrawPoint), &(points[0]));
|
||||
glVertexAttribPointer(_attribute_texCoord_location, 2, GL_FLOAT, false, sizeof(MADrawPoint), &(textureCoords[0]));
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(_attribute_position_location);
|
||||
glDisableVertexAttribArray(_attribute_texCoord_location);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_TRUE);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
- (GLuint)loadGLESPrograme {
|
||||
NSString *vertexShaderSrc = @"precision highp float;\n\
|
||||
attribute vec2 attrVertex;\n\
|
||||
attribute vec2 attrTextureCoord;\n\
|
||||
uniform mat4 inViewMatrix;\n\
|
||||
uniform mat4 inProjMatrix;\n\
|
||||
varying vec2 textureCoord;\n\
|
||||
void main(){\n\
|
||||
gl_Position = inProjMatrix * inViewMatrix * (vec4(attrVertex, 1.0, 1.0));\n\
|
||||
textureCoord = attrTextureCoord;\n\
|
||||
}";
|
||||
|
||||
NSString *fragShaderSrc = @"precision highp float;\n\
|
||||
varying vec2 textureCoord;\n\
|
||||
uniform sampler2D inTextureUnit;\n\
|
||||
void main(){\n\
|
||||
gl_FragColor = texture2D(inTextureUnit, textureCoord);\n\
|
||||
}";
|
||||
|
||||
GLuint prgName = 0;
|
||||
prgName = glCreateProgram();
|
||||
|
||||
if(prgName <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
GLint logLength = 0, status = 0;
|
||||
//////////////////////////////////////
|
||||
// Specify and compile VertexShader //
|
||||
//////////////////////////////////////
|
||||
const GLchar* vertexShaderSrcStr = (const GLchar*)[vertexShaderSrc UTF8String];
|
||||
|
||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vertexShader, 1, (const GLchar **)&(vertexShaderSrcStr), NULL);
|
||||
glCompileShader(vertexShader);
|
||||
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
|
||||
if (logLength > 0) {
|
||||
GLchar *log = (GLchar*) malloc(logLength);
|
||||
glGetShaderInfoLog(vertexShader, logLength, &logLength, log);
|
||||
NSLog(@"Vtx Shader compile log:%s\n", log);
|
||||
free(log);
|
||||
}
|
||||
|
||||
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
|
||||
if (status == 0) {
|
||||
NSLog(@"Failed to compile vtx shader:\n%s\n", vertexShaderSrcStr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
glAttachShader(prgName, vertexShader);
|
||||
glDeleteShader(vertexShader);
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Specify and compile Fragment Shader //
|
||||
/////////////////////////////////////////
|
||||
const GLchar* fragmentShaderSrcStr = (const GLchar*)[fragShaderSrc UTF8String];
|
||||
|
||||
GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(fragShader, 1, (const GLchar **)&(fragmentShaderSrcStr), NULL);
|
||||
glCompileShader(fragShader);
|
||||
glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0) {
|
||||
GLchar *log = (GLchar*)malloc(logLength);
|
||||
glGetShaderInfoLog(fragShader, logLength, &logLength, log);
|
||||
NSLog(@"Frag Shader compile log:\n%s\n", log);
|
||||
free(log);
|
||||
}
|
||||
|
||||
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &status);
|
||||
if (status == 0) {
|
||||
NSLog(@"Failed to compile frag shader:\n%s\n", fragmentShaderSrcStr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
glAttachShader(prgName, fragShader);
|
||||
glDeleteShader(fragShader);
|
||||
|
||||
//////////////////////
|
||||
// Link the program //
|
||||
//////////////////////
|
||||
glLinkProgram(prgName);
|
||||
glGetProgramiv(prgName, GL_INFO_LOG_LENGTH, &logLength);
|
||||
if (logLength > 0) {
|
||||
GLchar *log = (GLchar*)malloc(logLength);
|
||||
glGetProgramInfoLog(prgName, logLength, &logLength, log);
|
||||
NSLog(@"Program link log:\n%s\n", log);
|
||||
free(log);
|
||||
}
|
||||
|
||||
glGetProgramiv(prgName, GL_LINK_STATUS, &status);
|
||||
if (status == 0) {
|
||||
NSLog(@"Failed to link program");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_uniform_viewMatrix_location = glGetUniformLocation(prgName, "inViewMatrix");
|
||||
_uniform_projMatrix_location = glGetUniformLocation(prgName, "inProjMatrix");
|
||||
|
||||
_attribute_position_location = glGetAttribLocation(prgName, "attrVertex");
|
||||
_attribute_texCoord_location = glGetAttribLocation(prgName, "attrTextureCoord");
|
||||
|
||||
return prgName;
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user