This commit is contained in:
DDIsFriend
2023-08-18 17:28:57 +08:00
commit f0e8a1709d
4282 changed files with 192396 additions and 0 deletions
@@ -0,0 +1,15 @@
//
// DriveRouteCustomAnnotation.h
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/2/3.
#import <AMapNaviKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface DriveRouteCustomAnnotation : MAPointAnnotation
@property (nonatomic, copy)NSAttributedString *customAttributedText;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,11 @@
//
// DriveRouteCustomAnnotation.m
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/2/3.
#import "DriveRouteCustomAnnotation.h"
@implementation DriveRouteCustomAnnotation
@end
@@ -0,0 +1,25 @@
//
// MAPointAnnotation+DDCategory.h
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/1/31.
#import <AMapNaviKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface MAPointAnnotation (DDCategory)
// 自定义图片
@property (nonatomic, strong, nullable)UIImage *dd_image;
// 自定义气泡的view
@property (nonatomic, strong, nullable)UIView *customCalloutView;
// 类型字符
@property (nonatomic, strong)Class annotationClass;
// tag
@property (nonatomic, assign)long tag;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,42 @@
//
// MAPointAnnotation+DDCategory.m
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/1/31.
#import "MAPointAnnotation+DDCategory.h"
#import <objc/runtime.h>
@implementation MAPointAnnotation (DDCategory)
- (void)setDd_image:(UIImage *)dd_image{
objc_setAssociatedObject(self, @selector(dd_image), dd_image, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (nullable UIImage *)dd_image{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setCustomCalloutView:(UIView *)customCalloutView{
objc_setAssociatedObject(self, @selector(customCalloutView), customCalloutView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (nullable UIView *)customCalloutView{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setAnnotationClass:(Class)annotationClass{
objc_setAssociatedObject(self, @selector(annotationClass), annotationClass, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (Class)annotationClass{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setTag:(int)tag{
objc_setAssociatedObject(self, @selector(tag), @(tag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)tag{
return [objc_getAssociatedObject(self, _cmd) intValue];
}
@end
@@ -0,0 +1,15 @@
//
// DriveRouteCustomAnnotationView.h
// DDCategoryKit_Private
// Created by DDIsFriend on 2023/2/3.
#import <AMapNaviKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface DriveRouteCustomAnnotationView : MAAnnotationView
@property (nonatomic, strong)UILabel *customTextLabel;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,37 @@
//
// DriveRouteCustomAnnotationView.m
// DDCategoryKit_Private
// Created by DDIsFriend on 2023/2/3.
#import "DriveRouteCustomAnnotationView.h"
@interface DriveRouteCustomAnnotationView ()
@end
@implementation DriveRouteCustomAnnotationView
- (id)initWithAnnotation:(id <MAAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self) {
[self addSubview:self.customTextLabel];
self.customTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.customTextLabel.heightAnchor constraintEqualToConstant:30],
[self.customTextLabel.bottomAnchor constraintEqualToAnchor:self.topAnchor constant:0],
[self.customTextLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
]];
}
return self;
}
// MARK: <Lazy>
- (UILabel *)customTextLabel{
if (_customTextLabel == nil) {
_customTextLabel = [[UILabel alloc] init];
}
return _customTextLabel;
}
@end
@@ -0,0 +1,154 @@
//
// DDMAMapView.h
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/1/30.
#import <UIKit/UIKit.h>
#import <AMapNaviKit/MAMapKit.h>
#import <DDMAMapKit_Private/MATraceReplayOverlay.h>
#import <DDMAMapKit_Private/MATraceReplayOverlayRender.h>
NS_ASSUME_NONNULL_BEGIN
@protocol DDMAMapViewDelegate;
@class DDAnnotationView;
@class DDAnnotation;
@interface DDMAMapView : UIView
@property (nonatomic, strong, nonnull)MAMapView *maMapView;
@property (nonatomic, weak)id<DDMAMapViewDelegate> delegate;
// 请在使用该类前先设置appkey
+ (void)startWithAppKey:(nullable NSString *)appKey;
// 在创建该类实例前调用
+ (void)agreePrivacy;
- (MAOverlayRenderer *)dd_rendererForOverlay:(id <MAOverlay>)overlay;
@end
@interface DDMAMapView (Location)
/// @brief 用户当前位置的属性
@property (nonatomic, readonly)MAUserLocation *maUserLocation;
/// @brief 调用此方法来自定义当前位置小蓝点
- (void)updateLocationViewWithParam:(MAUserLocationRepresentation *)representation;
@end
@interface DDMAMapView (Trace)
@property (nonatomic, strong)MATraceReplayOverlay *traceReplayOverlay;
@property (nonatomic, strong)MATraceReplayOverlayRenderer *traceReplayOverlayRenderer;
@end
@protocol DDMAMapViewDelegate <NSObject>
@optional
/**
* @brief 地图开始加载
* @param mapView 地图View
*/
- (void)dd_mapViewWillStartLoadingMap:(MAMapView *)mapView;
/**
* @brief 地图加载成功
* @param mapView 地图View
*/
- (void)dd_mapViewDidFinishLoadingMap:(MAMapView *)mapView;
/**
* @brief 地图加载失败
* @param mapView 地图View
* @param error 错误信息
*/
- (void)dd_mapViewDidFailLoadingMap:(MAMapView *)mapView withError:(NSError *)error;
/**
* @brief 地形图加载失败
* @param mapView 地图View
* @param error 错误信息
*/
- (void)dd_mapView:(MAMapView *)mapView didFailLoadTerrainWithError:(NSError *)error;
/**
* @brief 在地图View将要启动定位时,会调用此函数
* @param mapView 地图View
*/
- (void)dd_mapViewWillStartLocatingUser:(MAMapView *)mapView;
/**
* @brief 在地图View停止定位后,会调用此函数
* @param mapView 地图View
*/
- (void)dd_mapViewDidStopLocatingUser:(MAMapView *)mapView;
/**
* @brief 位置或者设备方向更新后,会调用此函数
* @param mapView 地图View
* @param userLocation 用户定位信息(包括位置与设备方向等数据)
* @param updatingLocation 标示是否是location数据更新, YES:location数据更新 NO:heading数据更新
*/
- (void)dd_mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation;
/**
* @brief 当plist配置NSLocationAlwaysUsageDescription或者NSLocationAlwaysAndWhenInUseUsageDescription,并且[CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined,会调用代理的此方法。
此方法实现调用后台权限API即可( 该回调必须实现 [locationManager requestAlwaysAuthorization] ; since 6.8.0
* @param locationManager 地图的CLLocationManager。
*/
- (void)dd_mapViewRequireLocationAuth:(CLLocationManager *)locationManager;
/**
* @brief 定位失败后,会调用此函数
* @param mapView 地图View
* @param error 错误号,参考CLError.h中定义的错误号
*/
- (void)dd_mapView:(MAMapView *)mapView didFailToLocateUserWithError:(NSError *)error;
/**
* @brief 根据anntation生成对应的View。
注意:
1、5.1.0后由于定位蓝点增加了平滑移动功能,如果在开启定位的情况先添加annotation,需要在此回调方法中判断annotation是否为MAUserLocation,从而返回正确的View。
if ([annotation isKindOfClass:[MAUserLocation class]]) {
return nil;
}
2、请不要在此回调中对annotation进行select和deselect操作,此时annotationView还未添加到mapview。
* @param mapView 地图View
* @param annotation 指定的标注
* @return 生成的标注View
*/
- (MAAnnotationView *)dd_mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation;
/**
* @brief 根据overlay生成对应的Renderer
* @param mapView 地图View
* @param overlay 指定的overlay
* @return 生成的覆盖物Renderer
*/
- (MAOverlayRenderer *)dd_mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay;
/**
* @brief 标注view被点击时,触发该回调。(since 5.7.0
* @param mapView 地图的view
* @param view annotationView
*/
- (void)dd_mapView:(MAMapView *)mapView didAnnotationViewTapped:(MAAnnotationView *)view;
/**
* @brief 当mapView新添加overlay renderers时,调用此接口
* @param mapView 地图View
* @param overlayRenderers 新添加的overlay renderers
*/
- (void)dd_mapView:(MAMapView *)mapView didAddOverlayRenderers:(NSArray *)overlayRenderers;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,245 @@
//
// DDMAMapView.m
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/1/30.
#import "DDMAMapView.h"
#import <objc/runtime.h>
#import <DDCategoryKit_Private/UIImage+DDCategory.h>
#import <DDMAMapKit_Private/MAPointAnnotation+DDCategory.h>
#import <DDMAMapKit_Private/MABaseOverlay+DDCategory.h>
#import <DDMAMapKit_Private/DriveRouteCustomAnnotationView.h>
#import <DDMAMapKit_Private/DriveRouteCustomAnnotation.h>
@interface DDMAMapView () <MAMapViewDelegate>
@end
@implementation DDMAMapView
// MARK: <Class Initialize>
+ (void)startWithAppKey:(nullable NSString *)appKey{
[[AMapServices sharedServices] setEnableHTTPS:YES];
[AMapServices sharedServices].apiKey = appKey;
}
+ (void)agreePrivacy{
[MAMapView updatePrivacyShow:AMapPrivacyShowStatusDidShow privacyInfo:AMapPrivacyInfoStatusDidContain];
[MAMapView updatePrivacyAgree:AMapPrivacyAgreeStatusDidAgree];
}
// MARK: <Init Function>
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (!self) return nil;
[self configMapView];
return self;
}
- (void)configMapView{
// MAMapView.metalEnabled = YES;
self.maMapView = [[MAMapView alloc] init];
self.maMapView.delegate = self;
[self addSubview:self.maMapView];
self.maMapView.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[self.maMapView.leftAnchor constraintEqualToAnchor:self.leftAnchor],
[self.maMapView.topAnchor constraintEqualToAnchor:self.topAnchor],
[self.maMapView.rightAnchor constraintEqualToAnchor:self.rightAnchor],
[self.maMapView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
]];
self.maMapView.showsIndoorMap = NO;
self.maMapView.zoomLevel = 16;
self.maMapView.mapType = MAMapTypeStandard;
self.maMapView.showsCompass = NO;
self.maMapView.showsScale = NO;
}
- (MAOverlayRenderer *)dd_rendererForOverlay:(id <MAOverlay>)overlay{
return [self.maMapView rendererForOverlay:overlay];
}
// MARK: <MAMapViewDelegate>
- (void)mapViewWillStartLoadingMap:(MAMapView *)mapView{
if ([self.delegate respondsToSelector:@selector(dd_mapViewWillStartLoadingMap:)]) {
[self.delegate dd_mapViewWillStartLoadingMap:mapView];
}
}
- (void)mapViewDidFinishLoadingMap:(MAMapView *)mapView{
if ([self.delegate respondsToSelector:@selector(dd_mapViewDidFinishLoadingMap:)]) {
[self.delegate dd_mapViewDidFinishLoadingMap:mapView];
}
}
- (void)mapViewDidFailLoadingMap:(MAMapView *)mapView withError:(NSError *)error{
if ([self.delegate respondsToSelector:@selector(dd_mapViewDidFailLoadingMap:withError:)]) {
[self.delegate dd_mapViewDidFailLoadingMap:mapView withError:error];
}
}
- (void)mapView:(MAMapView *)mapView didFailLoadTerrainWithError:(NSError *)error{
if ([self.delegate respondsToSelector:@selector(dd_mapView:didFailLoadTerrainWithError:)]) {
[self.delegate dd_mapView:mapView didFailLoadTerrainWithError:error];
}
}
// MARK: <Locate>
- (void)mapViewWillStartLocatingUser:(MAMapView *)mapView{
if ([self.delegate respondsToSelector:@selector(dd_mapViewWillStartLocatingUser:)]) {
[self.delegate dd_mapViewWillStartLocatingUser:mapView];
}
}
- (void)mapViewDidStopLocatingUser:(MAMapView *)mapView{
if ([self.delegate respondsToSelector:@selector(dd_mapViewDidStopLocatingUser:)]) {
[self.delegate dd_mapViewDidStopLocatingUser:mapView];
}
}
- (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation{
if ([self.delegate respondsToSelector:@selector(dd_mapView:didUpdateUserLocation:updatingLocation:)]) {
[self.delegate dd_mapView:mapView didUpdateUserLocation:userLocation updatingLocation:updatingLocation];
}
}
- (void)mapViewRequireLocationAuth:(CLLocationManager *)locationManager {
if ([self.delegate respondsToSelector:@selector(dd_mapViewRequireLocationAuth:)]) {
[self.delegate dd_mapViewRequireLocationAuth:locationManager];
}
}
- (void)mapView:(MAMapView *)mapView didFailToLocateUserWithError:(NSError *)error{
if ([self.delegate respondsToSelector:@selector(dd_mapView:didFailToLocateUserWithError:)]) {
[self.delegate dd_mapView:mapView didFailToLocateUserWithError:error];
}
}
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation{
if ([self.delegate respondsToSelector:@selector(dd_mapView:viewForAnnotation:)]) {
return [self.delegate dd_mapView:mapView viewForAnnotation:annotation];
}
if ([annotation isMemberOfClass:[MAPointAnnotation class]]){
MAPointAnnotation *pointAnnotation = (MAPointAnnotation *)annotation;
static NSString *pointReuseIndentifier = @"pointReuseIndentifier";
MAAnnotationView *annotationView = (MAAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier];
if (annotationView == nil)
{
annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier];
}
annotationView.annotation = pointAnnotation;
annotationView.image = pointAnnotation.dd_image;
if (pointAnnotation.customCalloutView != nil) {
annotationView.customCalloutView = [[MACustomCalloutView alloc] initWithCustomView:pointAnnotation.customCalloutView];
annotationView.canShowCallout = YES;
annotationView.selected = YES;
}
return annotationView;
}
if ([annotation isMemberOfClass:[MAAnimatedAnnotation class]]) {
MAAnimatedAnnotation *animatedAnnotation = (MAAnimatedAnnotation *)annotation;
static NSString *pointReuseIndentifier = @"AnimatedAnnotationPointReuseIndentifier";
MAAnnotationView *annotationView = (MAAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier];
if (annotationView == nil)
{
annotationView = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier];
}
annotationView.annotation = animatedAnnotation;
annotationView.image = animatedAnnotation.dd_image;
return annotationView;
}
if ([annotation isMemberOfClass:[DriveRouteCustomAnnotation class]]){
DriveRouteCustomAnnotation *pointAnnotation = (DriveRouteCustomAnnotation *)annotation;
static NSString *pointReuseIndentifier = @"DriveRouteCustomAnnotationPointReuseIndentifier";
DriveRouteCustomAnnotationView *annotationView = (DriveRouteCustomAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:pointReuseIndentifier];
if (annotationView == nil)
{
annotationView = [[DriveRouteCustomAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:pointReuseIndentifier];
}
annotationView.annotation = pointAnnotation;
annotationView.image = pointAnnotation.dd_image;
annotationView.customTextLabel.attributedText = pointAnnotation.customAttributedText;
return annotationView;
}
return nil;
}
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay{
if ([self.delegate respondsToSelector:@selector(dd_mapView:rendererForOverlay:)]) {
return [self.delegate dd_mapView:mapView rendererForOverlay:overlay];
}
if ([overlay isMemberOfClass:[MAPolyline class]]){
MAPolyline *polyline = (MAPolyline *)overlay;
MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:polyline];
polylineRenderer.lineWidth = polyline.dd_lineWidth;
polylineRenderer.strokeColor = polyline.dd_strokeColor;
polylineRenderer.lineJoinType = polyline.dd_lineJoinType;
polylineRenderer.lineCapType = polyline.dd_lineCapType;
return polylineRenderer;
}
if ([overlay isMemberOfClass:[MATraceReplayOverlay class]]) {
MATraceReplayOverlay *traceReplayOverlay = (MATraceReplayOverlay *)overlay;
MATraceReplayOverlayRenderer *traceReplayOverlayRenderer = [[MATraceReplayOverlayRenderer alloc] initWithOverlay:traceReplayOverlay];
traceReplayOverlayRenderer.lineWidth = traceReplayOverlay.dd_lineWidth;
traceReplayOverlayRenderer.strokeColors = traceReplayOverlay.dd_strokeColors;
traceReplayOverlayRenderer.lineJoinType = traceReplayOverlay.dd_lineJoinType;
traceReplayOverlayRenderer.lineCapType = traceReplayOverlay.dd_lineCapType;
self.traceReplayOverlay = traceReplayOverlay;
self.traceReplayOverlayRenderer = traceReplayOverlayRenderer;
return traceReplayOverlayRenderer;
}
return nil;
}
- (void)mapView:(MAMapView *)mapView didAnnotationViewTapped:(MAAnnotationView *)view{
if ([self.delegate respondsToSelector:@selector(dd_mapView:didAnnotationViewTapped:)]) {
[self.delegate dd_mapView:mapView didAnnotationViewTapped:view];
}
}
- (void)mapView:(MAMapView *)mapView didAddOverlayRenderers:(NSArray *)overlayRenderers{
if ([self.delegate respondsToSelector:@selector(dd_mapView:didAddOverlayRenderers:)]) {
[self.delegate dd_mapView:mapView didAddOverlayRenderers:overlayRenderers];
}
}
@end
@implementation DDMAMapView (Location)
- (MAUserLocation *)maUserLocation{
return self.maMapView.userLocation;
}
- (void)updateLocationViewWithParam:(MAUserLocationRepresentation *)representation{
[self.maMapView updateUserLocationRepresentation:representation];
}
@end
@implementation DDMAMapView (Trace)
- (void)setTraceReplayOverlay:(MATraceReplayOverlay *)traceReplayOverlay{
objc_setAssociatedObject(self, @selector(traceReplayOverlay), traceReplayOverlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (MATraceReplayOverlay *)traceReplayOverlay{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setTraceReplayOverlayRenderer:(MATraceReplayOverlayRenderer *)traceReplayOverlayRenderer{
objc_setAssociatedObject(self, @selector(traceReplayOverlayRenderer), traceReplayOverlayRenderer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (MATraceReplayOverlayRenderer *)traceReplayOverlayRenderer{
return objc_getAssociatedObject(self, _cmd);
}
@end
@@ -0,0 +1,26 @@
//
// MABaseOverlay+DDCategory.h
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/2/1.
#import <AMapNaviKit/MAMapKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface MABaseOverlay (DDCategory)
@property (nonatomic, assign)CGFloat dd_lineWidth;
@property (nonatomic, strong)UIColor *dd_strokeColor;
@property (nonatomic, strong)NSArray *dd_strokeColors;
@property (nonatomic, assign)MALineJoinType dd_lineJoinType;
@property (nonatomic, assign)MALineCapType dd_lineCapType;
@property (nonatomic, assign)int tag;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,58 @@
//
// MABaseOverlay+DDCategory.m
// DDMAMapKit_Private
// Created by DDIsFriend on 2023/2/1.
#import "MABaseOverlay+DDCategory.h"
#import <objc/runtime.h>
@implementation MABaseOverlay (DDCategory)
- (void)setDd_lineWidth:(CGFloat)dd_lineWidth{
objc_setAssociatedObject(self, @selector(dd_lineWidth), @(dd_lineWidth), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (CGFloat)dd_lineWidth{
return [objc_getAssociatedObject(self, _cmd) floatValue];
}
- (void)setDd_strokeColor:(UIColor *)dd_strokeColor{
objc_setAssociatedObject(self, @selector(dd_strokeColor), dd_strokeColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIColor *)dd_strokeColor{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDd_strokeColors:(NSArray *)dd_strokeColors{
objc_setAssociatedObject(self, @selector(dd_strokeColors), dd_strokeColors, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSArray *)dd_strokeColors{
return objc_getAssociatedObject(self, _cmd);
}
- (void)setDd_lineJoinType:(MALineJoinType)dd_lineJoinType{
objc_setAssociatedObject(self, @selector(dd_lineJoinType), @(dd_lineJoinType), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (MALineJoinType)dd_lineJoinType{
return (MALineJoinType)[objc_getAssociatedObject(self, _cmd) intValue];
}
- (void)setDd_lineCapType:(MALineCapType)dd_lineCapType{
objc_setAssociatedObject(self, @selector(dd_lineCapType), @(dd_lineCapType), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (MALineCapType)dd_lineCapType{
return (MALineCapType)[objc_getAssociatedObject(self, _cmd) intValue];
}
- (void)setTag:(int)tag{
objc_setAssociatedObject(self, @selector(tag), @(tag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (int)tag{
return [objc_getAssociatedObject(self, _cmd) intValue];
}
@end
@@ -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
@@ -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>
///轨迹回放overlaysince 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
@@ -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
@@ -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
@@ -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