iOS 运动轨迹

998 阅读4分钟

地图效果图

WechatIMG14.jpeg

卡片上画出来的效果 WechatIMG13.jpeg

需求说明:最新项目要做到像华为运动app的,运动记录显示轨迹效果。 思路:第一个点为所有点的中心点,算出连个点之间的距离。转换经纬度,得到两个点之间的x,y坐标,然后就可以连线。目前还没达到太好的效果,本文只是个抛砖引玉的作用。欢迎交流学习:QQ/微信308806988.

1、计算两个经纬度之间距离


#define PI 3.14159265358979323

-(**double**) CalculationDistanceOther_Lon1:(**double**)lon1 Other_Lat1:(**double**)lat1 self_Lon2:(**double**)lon2 self_Lat2:(**double**)lat2{

    **double** er = 6371229; // 6378700.0f;

    //ave. radius = 6371.315 (someone said more accurate is 6366.707)

    //equatorial radius = 6378.388

    //nautical mile = 1.15078

    **double** radlat1 = PI*lat1/180.0f;

    **double** radlat2 = PI*lat2/180.0f;

    //now long.

    **double** radlong1 = PI*lon1/180.0f;

    **double** radlong2 = PI*lon2/180.0f;

    **if**( radlat1 < 0 ) radlat1 = PI/2 + fabs(radlat1);// south

    **if**( radlat1 > 0 ) radlat1 = PI/2 - fabs(radlat1);// north

    **if**( radlong1 < 0 ) radlong1 = PI*2 - fabs(radlong1);//west

    **if**( radlat2 < 0 ) radlat2 = PI/2 + fabs(radlat2);// south

    **if**( radlat2 > 0 ) radlat2 = PI/2 - fabs(radlat2);// north

    **if**( radlong2 < 0 ) radlong2 = PI*2 - fabs(radlong2);// west

    //spherical coordinates x=r*cos(ag)sin(at), y=r*sin(ag)*sin(at), z=r*cos(at)

    //zero ag is up so reverse lat

    **double** x1 = er * cos(radlong1) * sin(radlat1);

    **double** y1 = er * sin(radlong1) * sin(radlat1);

    **double** z1 = er * cos(radlat1);

    **double** x2 = er * cos(radlong2) * sin(radlat2);

    **double** y2 = er * sin(radlong2) * sin(radlat2);

    **double** z2 = er * cos(radlat2);

    **double** d = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2));

    //side, side, side, law of cosines and arccos

    **double** theta = acos((er*er+er*er-d*d)/(2*er*er));

    **double** dist  = theta*er;

    **return** dist;
}

2、经纬度值转成view的x、y值

    NSMutableArray *pointAry = [NSMutableArray array];
    MapLaAndLoModel *fMode = _last_ary.firstObject;//经纬度数据
    
    NSArray *lon_lat_ary = [**self** transformLongitueAndLatitude:fMode];

    **double** first_lon = [lon_lat_ary.firstObject doubleValue];
    **double** first_lat = [lon_lat_ary.lastObject doubleValue];

    **double** max_lon = 0.00;
    **double** min_lon = 180.00;

    **double** max_lat = 0.00;
    **double** min_lat = 90.00;

    CGFloat oldLngLineDistance = 0;
    CGFloat oldLatLineDistance = 0;

    **for** (NSInteger i = 1; i < _last_ary.count; i++) {
    
        MapLaAndLoModel *lalonModel = [_last_ary objectAtIndex:i];

        NSArray *lon_lat_ary_1 = [**self** transformLongitueAndLatitude:lalonModel];

        **double** lon = [lon_lat_ary_1.firstObject doubleValue];
        **double** lat = [lon_lat_ary_1.lastObject doubleValue];

        //longitude取第一个点的经度,同一个经度计算纬度,两点之间距离,则就是y值
        **double** new_lat = [**self** CalculationDistanceOther_Lon1:first_lon Other_Lat1:first_lat self_Lon2:first_lon self_Lat2:lat];

        //latitude取第一个点的纬度,同一个纬度计算经度,两点之间距离,则就是x值
        **double** new_lon = [**self** CalculationDistanceOther_Lon1:first_lon Other_Lat1:first_lat self_Lon2:lon self_Lat2:first_lat];

        **if**(lon > max_lon){
            max_lon = lon;
        }

        **if**(min_lon > lon){
            min_lon = lon;
        }        

        **if**(lat > max_lat){
            max_lat = lat;
        }
        **if**(lat < min_lat){
            min_lat = lat;
        }

        //第一次经度如果小于后面的经度, 证明是往西走. 反之往东走
        **if** (first_lon > lon) {
            new_lon = oldLngLineDistance - new_lon;//往西走, x取负值
        }
        
        //第一次纬度如果小于后面的纬度, 证明是往北走. 反之往南走
        **if** (first_lat < lat) {
            new_lat = oldLatLineDistance - new_lat;//往北走, y取负值
        }

        PointModel *mode = [PointModel new];
        mode.x = new_lon;
        mode.y = new_lat;
        [pointAry addObject:mode];
        
    }

3、计算缩放比例

//计算同一最大、最小经度两点之间到距离
    **double** max_lon_distance = [**self** CalculationDistanceOther_Lon1:min_lon Other_Lat1:first_lat self_Lon2:max_lon self_Lat2:first_lat];

    //计算同一最大、最小纬度两点之间到距离
    **double** max_lat_distance = [**self** CalculationDistanceOther_Lon1:max_lon Other_Lat1:min_lat self_Lon2:max_lon self_Lat2:max_lat];

    CGFloat b_height = 35;
    CGFloat line_height = **self**.height - b_height - 15;

    //画布
    UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(0,0,**self**.width, line_height)];
    bgView.backgroundColor = UIColor.clearColor;

    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.strokeColor = UIColor.greenColor.CGColor;
    layer.fillColor = UIColor.clearColor.CGColor;
    layer.lineWidth = 2;

    UIBezierPath *path = [UIBezierPath bezierPath];
    CGPoint firstPoint = CGPointZero;
    CGPoint endPoint = CGPointZero;

    CGFloat scale_y = bgView.height / max_lat_distance;
    CGFloat scale_x = bgView.width / max_lon_distance;

    CGFloat zoomScale = scale_y;

    **if**(scale_y < 1 && scale_x < 1){
        **if**(scale_y > scale_x){
            zoomScale = scale_x;
        }
    }**else** **if** (scale_y < 1){
        zoomScale = scale_y;
    }**else** **if** (scale_x < 1){
        zoomScale = scale_x;
    }

    zoomScale *= 0.781;

4、调整位置,居中显示

    NSMutableArray *point_array = [NSMutableArray arrayWithCapacity:pointAry.count];
    CGFloat offset_x = 0;
    CGFloat offset_y = 0;

    CGFloat max_line_x = 0;
    CGFloat min_line_x = bgView.width;

    CGFloat max_line_y = 0;
    CGFloat min_line_y = bgView.height;

    **for** (NSInteger j = 0; j < pointAry.count; j++) {
    
        PointModel *xyModel = [pointAry objectAtIndex:j];
        CGFloat y = xyModel.y * zoomScale;
        CGFloat x = xyModel.x * zoomScale;

        **if**(max_line_x < x){
            max_line_x = x;
        }
        **if**(min_line_x > x){
            min_line_x = x;
        }

        **if**(max_line_y < y){
            max_line_y = y;
        }

        **if**(min_line_y > y){
            min_line_y = y;
        }

        CGPoint point = CGPointMake(x, y);
        [point_array addObject:[NSValue valueWithCGPoint:point]];
    }

    **if**(max_line_x < 0 || min_line_x < 0){//在中心点左边
        CGFloat all_x_distance = fabs(max_line_x) + fabs(min_line_x);
        offset_x = (bgView.width - all_x_distance) * 0.5 + fabs(min_line_x);
    }**else**{//在中心点右边
        CGFloat all_x_distance = fabs(max_line_x) - fabs(min_line_x);
        offset_x = -(max_line_x - all_x_distance * 0.5 - bgView.width * 0.5);
    }
    
    **if**(max_line_y < 0 || min_line_y < 0){
        CGFloat all_y_distance = fabs(max_line_y) + fabs(min_line_y);
        offset_y = (bgView.height - all_y_distance) * 0.5 + fabs(min_line_y);
    }**else**{
        CGFloat all_y_distance = fabs(max_line_y) - fabs(min_line_y);
        offset_y = -(max_line_y - all_y_distance * 0.5 - bgView.height * 0.5);
    }

5、在画布view上显示

    **for** (NSInteger i = 0; i < point_array.count; i++) {
        CGPoint point = [[point_array objectAtIndex:i] CGPointValue];
        CGPoint n_point = CGPointMake(point.x + offset_x, point.y + offset_y);
        **if** (i == 0) {
            [path moveToPoint:n_point];
            firstPoint = n_point;
        }**else**{
            [path addLineToPoint:n_point];
        }
        **if**(i == point_array.count - 1){
            endPoint = n_point;
        }
    }

    layer.path = path.CGPath;
    [bgView.layer addSublayer:layer];

    //结束圆环
    UIColor *r_cl = [UIColor.redColor colorWithAlphaComponent:0.8];
    CAShapeLayer *cirlLayer = [**self** addCirlViewColor:r_cl point:endPoint];
    [bgView.layer addSublayer:cirlLayer];
    
    //开始圆环
    CAShapeLayer *cirlLayer2 = [**self** addCirlViewColor:RGB(117, 84, 60) point:firstPoint];
    [bgView.layer addSublayer:cirlLayer2];
    [**self** addSubview:bgView];

结束语:该做法尚有不足之处,请不吝指教。