公司为了节约成本开始换成了Mapbox 开源免费,最初用的Arcgis ,Arcgis买的时候70多个W,Arcgis手机端支持非常差劲,打电话没有人能给你提供服务,必须邮件,而且他们Ios开发不怎么负责,我们70w买的Arcgis你就这态度?问你个报警动态怎么能实现,原本是没有接口实现,你直接跟我说实现不了就行了,Ios开发给我发了段代码,给个定时器->去修改点的阿尔法,模拟闪光。。。。我地图上几百个点甚至上千个点,你让我这么做?
槽点:
1.文档:
(1).mapbox详细,非常详细,手把手教你了,swift OC都有很全。
(2).Arcgis 挺烂,swift转OC基本上挂羊头卖狗肉,因为项目OC的,swift转OC遇到了很多坑。
2020.12.16====
(3).Arcgis代码封装性比较好,举个例子,arcgis图层加载直接放url就行,mapbox需要先用get请求请求下数据,然后对数据进行处理,需要自己绘制线,相比arcgis,arcgis就方便很多直接使用图层url就可以不需要区分点和线图层。
(4).关于点击方法,mapbox自己加点击方法,arcgis 是自带的tap点击方法,arcgis获取点击图层属性稍微麻烦点,mapbox能直接点出来。
2020.12.22====
(5).mapbox对ios支持不是很好啊,对了下发现没有安卓功能多,先更新下其中一个功能,画区域去获取图层要素:
思路:屏幕中间有个框 放在self.view上,点击方法拿到point,用这个方法去读数据
//把你要获取的图层的IDF标识符写上,因为mapbox创建图层都需要标识符,我建议是把标识符写在pch文件里,因为我的项目的图层是通过geoserver发布的,而且在三个vc里频繁使用
NSSet *idfSet = [NSSet setWithArray:@[Line_1,Line_2,Line_3,Line_4,Line_5,Line_6,Line_7,Line_8,Line_9]];
// 获取图层
NSArray *featureArr = [self.mapBoxmapView visibleFeaturesInRect:self.view.frame inStyleLayersWithIdentifiers:idfSet];
//遍历图层获取所有要素
[featureArr enumerateObjectsUsingBlock:^(MGLPolygonFeature *obj, NSUInteger idx, BOOL * _Nonnull stop) {
//obj.attributes;
//这里建议字典转模型
XXXPipeNetWorkDataModel *model = [XXXPipeNetWorkDataModel yy_modelWithDictionary:obj.attributes];
}]
6.关于mapbox 的测量距离和测量面积里面没有实现方法,我说下实现思路,arcgis和mapbox一起用才行,主要用到arcgis的测量距离和面积的方法,用贝塞尔曲线画图层,然后专程arcgis对象,用arcgis方法来实现,我下面直接贴代码.
#pragma mark ---------- 贝塞尔曲线
//我先说下我的需求,这段代码直接复制不能用,需要改东西,只能提供关键代码和思路
//我是面积和距离通过一个标识符来分辨的indexpath 如果是1就是测面 2就是测距
//这个sport就是你添加了点击方法 拿到的那个sport
- (void)beginDrawBezierPathWithPoint:(CGPoint)sport{
//首先只要点击屏幕就记录点 这边有几个关键的地方需要注意下
//面积是3个点 距离是2个点
[self.savePointArr addObject:@(sport)];
// 创建一个路径对象
// 起点
if (self.savePointArr.count >= 2) {
//这块是距离 当只有数组里面大于等于2个点才开始链接
if (self.savePointArr.count == 2) {
//一共就俩点直接取也行 我习惯了遍历下
for (int i = 0; i < 2; i++) {
//取出点坐标
NSNumber *pointNum = self.savePointArr[i];
CGPoint selectedPoint = [pointNum CGPointValue];
if (i == 0) {
//这里是起点
[self.mainBezier moveToPoint:selectedPoint];
}else{
//连成一条线
[self.mainBezier addLineToPoint:selectedPoint];
}
}
//拿到数组里的点的结构体
CGPoint p1 = [self.savePointArr[0] CGPointValue];
CGPoint p2 = [self.savePointArr[1] CGPointValue];
//mapbox方法 将点转成Arcgis能用的CLLocationCoordinate2D
CLLocationCoordinate2D p1_2D = [self.mapBoxmapView convertPoint:p1 toCoordinateFromView:nil];
CLLocationCoordinate2D p2_2D = [self.mapBoxmapView convertPoint:p2 toCoordinateFromView:nil];
//转成Arcgis的点
AGSPoint *agsP1 = [AGSPoint pointWithCLLocationCoordinate2D:p1_2D];
AGSPoint *agsP2 = [AGSPoint pointWithCLLocationCoordinate2D:p2_2D];
//Arcgis专门计算距离的方法 你其实不用也可以 百度上能找到 但是我没用过应为我要
//做面积,后面可以直接拿来用
double mapArea = [AGSGeometryEngine distanceBetweenGeometry1:agsP1 geometry2:agsP2];
//距离需要累加 一个全局数组进行存储
[self.saveLengthArr addObject:@(mapArea)];
NSString *mapAreaStr = [NSString stringWithFormat:@"距离:%fm",mapArea];
//自己做交互操作
}else{
//这块就是大于三个点之后的操作要连接前一个点然后算距离
NSNumber *pointNum = self.savePointArr.lastObject;
CGPoint selectedPoint = [pointNum CGPointValue];
[self.mainBezier addLineToPoint:selectedPoint];
CGPoint p1 = [self.savePointArr[self.savePointArr.count - 1] CGPointValue];
CGPoint p2 = [self.savePointArr[self.savePointArr.count - 2] CGPointValue];
CLLocationCoordinate2D p1_2D = [self.mapBoxmapView convertPoint:p1 toCoordinateFromView:nil];
CLLocationCoordinate2D p2_2D = [self.mapBoxmapView convertPoint:p2 toCoordinateFromView:nil];
AGSPoint *agsP1 = [AGSPoint pointWithCLLocationCoordinate2D:p1_2D];
AGSPoint *agsP2 = [AGSPoint pointWithCLLocationCoordinate2D:p2_2D];
double mapArea = [AGSGeometryEngine distanceBetweenGeometry1:agsP1 geometry2:agsP2];
double allLength = mapArea;
for (NSNumber *lengthNum in self.saveLengthArr) {
allLength = [lengthNum doubleValue] + allLength;
}
//这块是我要画出面来算面积了
if (self.selectedRightItemIndexRow == 1) {
//三个点成为一个面
if (self.savePointArr.count == 3) {
//这个是记录贝塞尔曲线是否闭合的一个参数,如果闭合说明继续点击要将闭合的贝塞尔曲线重新打开,然后把线重新连接闭合
self.bezierPathIsClose = YES;
[self.mainBezier closePath];
}
}
//这里是周长大于2个点之后的显示
if (self.selectedRightItemIndexRow == 2) {
NSString *mapAreaStr = [NSString stringWithFormat:@"周长:%fm",allLength];
[self lineAndPiceBtnShow:mapAreaStr];
}
}
// >
// 设置路径画
//这块是画面+算面积 前面这个判断就是为了保证唯一性,只有画多边形的时候才进入
if (self.selectedRightItemIndexRow == 1 && self.bezierPathIsClose == YES && self.savePointArr.count > 3) {
//首先删除贝塞尔里面所有的点
[self.mainBezier removeAllPoints];
for (CAShapeLayer *shapeLayer in self.saveAllLayerArr) {
[shapeLayer removeFromSuperlayer];
}
// [self.view setNeedsDisplay];
// 这块就是直接重新画点进行闭合 生成新的面
for (int i = 0; i < self.savePointArr.count; i++) {
NSNumber *pointNum = self.savePointArr[i];
CGPoint selectedPoint = [pointNum CGPointValue];
if (i == 0) {
[self.mainBezier moveToPoint:selectedPoint];
}else{
[self.mainBezier addLineToPoint:selectedPoint];
}
}
[self.mainBezier closePath];
}
if (self.selectedRightItemIndexRow == 1 && self.savePointArr.count >= 3) {
//这块是算面积 用Arcgis
NSMutableArray <AGSPoint *>*newMarr = [NSMutableArray array];
for (NSNumber *numPoint in self.savePointArr) {
CGPoint p = [numPoint CGPointValue];
CLLocationCoordinate2D p1_2D = [self.mapBoxmapView convertPoint:p toCoordinateFromView:nil];
AGSPoint *agsP1 = [AGSPoint pointWithCLLocationCoordinate2D:p1_2D];
[newMarr addObject:agsP1];
}
AGSPolygon *polygon = [AGSPolygon polygonWithPoints:newMarr];
double mapArea = [AGSGeometryEngine geodeticAreaOfGeometry:polygon areaUnit:[AGSAreaUnit squareMeters] curveType:AGSGeodeticCurveTypeGeodesic];
NSString *mapAreaStr = [NSString stringWithFormat:@"面积:%fm",mapArea];
[self lineAndPiceBtnShow:mapAreaStr];
}
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.bounds = self.view.bounds;
lineLayer.position = self.view.layer.position;
lineLayer.lineWidth = 2.0;
lineLayer.strokeColor = [UIColor orangeColor].CGColor; // 边线颜色
// >
lineLayer.path = self.mainBezier.CGPath;
if (self.selectedRightItemIndexRow == 1) {
lineLayer.fillColor = [[UIColor orangeColor] colorWithAlphaComponent:0.6].CGColor;
}else{
lineLayer.fillColor = nil;
}// 默认是black
[self.view.layer addSublayer:lineLayer];
[self.saveAllLayerArr addObject:lineLayer];
}
}
(6).关于mapbox的表达式,我就搞懂一种.
// CAST 固定写法 building_name是我geojson里面的某个字段 nsstring是类型
//主要是用来显示名字的
NSExpression *ex1 = [NSExpression expressionWithFormat:@"CAST(Building_Name,'NSString')"];