Men的博客

欢迎光临!

0%

地图计算

https://lbsyun.baidu.com/jsdemo.htm#TranslateggTobd

计算经纬度之间的距离

/*!
@brief 计算经纬度之间的距离
@param a a点
@param b b点
@return 距离,单位:米
*/
CLLocationDistance MAMetersBetweenMapPoints(CLLocationCoordinate2D a, CLLocationCoordinate2D b)
{
CLLocation *curLocation = [[CLLocation alloc] initWithLatitude:a.latitude longitude:a.longitude];
CLLocation *otherLocation = [[CLLocation alloc] initWithLatitude:b.latitude longitude:b.longitude];
return [curLocation distanceFromLocation:otherLocation];
}

static const double a = 6378245.0;
static const double ee = 0.00669342162296594323;
static const double pi = M_PI;
static const double xPi = M_PI * 3000.0 / 180.0;

GPS转高德

  • (CLLocationCoordinate2D)transformFromWGSToGCJ:(CLLocationCoordinate2D)wgsLoc {
    CLLocationCoordinate2D adjustLoc;
    if([self isLocationOutOfChina:wgsLoc]) {
      adjustLoc = wgsLoc;
    
    }
    else {
      double adjustLat = [self transformLatWithX:wgsLoc.longitude - 105.0 withY:wgsLoc.latitude - 35.0];
      double adjustLon = [self transformLonWithX:wgsLoc.longitude - 105.0 withY:wgsLoc.latitude - 35.0];
      long double radLat = wgsLoc.latitude / 180.0 * pi;
      long double magic = sin(radLat);
      magic = 1 - ee * magic * magic;
      long double sqrtMagic = sqrt(magic);
      adjustLat = (adjustLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
      adjustLon = (adjustLon * 180.0) / (a / sqrtMagic * cos(radLat) * pi);
      adjustLoc.latitude = wgsLoc.latitude + adjustLat;
      adjustLoc.longitude = wgsLoc.longitude + adjustLon;
    
    }
    return adjustLoc;
    }

    GPS转百度

  • (CLLocationCoordinate2D)transformFromWGSToBaidu:(CLLocationCoordinate2D)p {
    CLLocationCoordinate2D coo =[NSValue transformFromWGSToGCJ:p];
    return [NSValue transformFromGCJToBaidu:coo];
    }

    百度转GPS

  • (CLLocationCoordinate2D)transformFromBaiduToWGS:(CLLocationCoordinate2D)p {
    CLLocationCoordinate2D start_coor = [NSValue transformFromBaiduToGCJ:p];
    return [NSValue transformFromGCJToWGS:start_coor];
    }

    百度转高德

  • (CLLocationCoordinate2D)transformFromBaiduToGCJ:(CLLocationCoordinate2D)p {
    double x = p.longitude - 0.0065, y = p.latitude - 0.006;
    double z = sqrt(x * x + y * y) - 0.00002 * sin(y * xPi);
    double theta = atan2(y, x) - 0.000003 * cos(x * xPi);
    CLLocationCoordinate2D geoPoint;
    geoPoint.latitude = z * sin(theta);
    geoPoint.longitude = z * cos(theta);
    return geoPoint;
    }

    高德转百度

  • (CLLocationCoordinate2D)transformFromGCJToBaidu:(CLLocationCoordinate2D)p {
    long double z = sqrt(p.longitude * p.longitude + p.latitude * p.latitude) + 0.00002 * sqrt(p.latitude * pi);
    long double theta = atan2(p.latitude, p.longitude) + 0.000003 * cos(p.longitude * pi);
    CLLocationCoordinate2D geoPoint;
    geoPoint.latitude = (z * sin(theta) + 0.006);
    geoPoint.longitude = (z * cos(theta) + 0.0065);
    return geoPoint;
    }

    高德转GPS

  • (CLLocationCoordinate2D)transformFromGCJToWGS:(CLLocationCoordinate2D)p {
    double threshold = 0.00001; // The boundary
    double minLat = p.latitude - 0.5;
    double maxLat = p.latitude + 0.5;
    double minLng = p.longitude - 0.5;
    double maxLng = p.longitude + 0.5; double delta = 1;
    int maxIteration = 30;
    // Binary search
    while(true) {
      CLLocationCoordinate2D leftBottom  = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = minLat,.longitude = minLng}];
      CLLocationCoordinate2D rightBottom = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = minLat,.longitude = maxLng}];
      CLLocationCoordinate2D leftUp      = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = maxLat,.longitude = minLng}];
      CLLocationCoordinate2D midPoint    = [[self class] transformFromWGSToGCJ:(CLLocationCoordinate2D){.latitude = ((minLat + maxLat) / 2),.longitude = ((minLng + maxLng) / 2)}];
      delta = fabs(midPoint.latitude - p.latitude) + fabs(midPoint.longitude - p.longitude);
      
      if(maxIteration-- <= 0 || delta <= threshold) {
          return (CLLocationCoordinate2D){.latitude = ((minLat + maxLat) / 2),.longitude = ((minLng + maxLng) / 2)};
      }
      
      if(isContains(p, leftBottom, midPoint)) {
          maxLat = (minLat + maxLat) / 2;
          maxLng = (minLng + maxLng) / 2;
      } else if(isContains(p, rightBottom, midPoint)) {
          maxLat = (minLat + maxLat) / 2;
          minLng = (minLng + maxLng) / 2;
      } else if(isContains(p, leftUp, midPoint)) {
          minLat = (minLat + maxLat) / 2;
          maxLng = (minLng + maxLng) / 2;
      } else {
          minLat = (minLat + maxLat) / 2;
          minLng = (minLng + maxLng) / 2;
      }
    
    }

}

  • (double)transformLatWithX:(double)x withY:(double)y {
    double lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(fabs(x));
    lat += (20.0 * sin(6.0 * x * pi) + 20.0 *sin(2.0 * x * pi)) * 2.0 / 3.0;
    lat += (20.0 * sin(y * pi) + 40.0 * sin(y / 3.0 * pi)) * 2.0 / 3.0;
    lat += (160.0 * sin(y / 12.0 * pi) + 320 * sin(y * pi / 30.0)) * 2.0 / 3.0;
    return lat;
    }
  • (double)transformLonWithX:(double)x withY:(double)y {
    double lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(fabs(x));
    lon += (20.0 * sin(6.0 * x * pi) + 20.0 * sin(2.0 * x * pi)) * 2.0 / 3.0;
    lon += (20.0 * sin(x * pi) + 40.0 * sin(x / 3.0 * pi)) * 2.0 / 3.0;
    lon += (150.0 * sin(x / 12.0 * pi) + 300.0 * sin(x / 30.0 * pi)) * 2.0 / 3.0;
    return lon;
    }

    判断某个点point是否在p1和p2之间

    static bool isContains(CLLocationCoordinate2D point, CLLocationCoordinate2D p1, CLLocationCoordinate2D p2) {
    return (point.latitude >= MIN(p1.latitude, p2.latitude) && point.latitude <= MAX(p1.latitude, p2.latitude)) && (point.longitude >= MIN(p1.longitude,p2.longitude) && point.longitude <= MAX(p1.longitude, p2.longitude));
    }

粗略判断是不是在中国

  • (BOOL)isLocationOutOfChina:(CLLocationCoordinate2D)location {
    if (location.longitude < 72.004 || location.longitude > 137.8347 || location.latitude < 0.8293 || location.latitude > 55.8271)
      return YES;
    
    return NO;
    }

    弧线计算

    double x1 = pArc.startCoordinate.longitude;
    double y1 = pArc.startCoordinate.latitude;
    double x2 = pArc.passedCoordinate.longitude;
    double y2 = pArc.passedCoordinate.latitude;
    double x3 = pArc.endCoordinate.longitude;
    double y3 = pArc.endCoordinate.latitude;
    double a = 2 * (x2 - x1);
    double b = 2 * (y2 - y1);
    double c = x2 * x2 + y2 * y2 - x1 * x1 - y1 * y1;
    double d = 2 * (x3 - x2);
    double e = 2 * (y3 - y2);
    double f = x3 * x3 + y3 * y3 - x2 * x2 - y2 * y2;
    double x = (b * f - e * c) / (b * d - e * a);
    double y = (d * c - a * f) / (b * d - e * a);
    double r = sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1));
    double angle1 = acos((x1 - x) / r);
    if (y1 - y < 0)
    angle1 = -angle1;
    double angle2 = acos((x2 - x) / r);
    if (y2 - y < 0)
    angle2 = -angle2;
    double angle3 = acos((x3 - x) / r);
    if (y3 - y < 0)
    angle3 = -angle3;
    double deltaAngle1 = angle1 - angle2;

while (deltaAngle1 > M_PI)
deltaAngle1 -= M_PI * 2;
while (deltaAngle1 <= -M_PI)
deltaAngle1 += M_PI * 2;
int numPoints1 = (int) (128 * fabs(deltaAngle1) / M_PI);
double phase1 = deltaAngle1 / numPoints1;
double deltaAngle2 = angle2 - angle3;
while (deltaAngle2 > M_PI)
deltaAngle2 -= M_PI * 2;
while (deltaAngle2 <= -M_PI)
deltaAngle2 += M_PI * 2;
int numPoints2 = (int) (128 * fabs(deltaAngle2) / M_PI);
double phase2 = deltaAngle2 / numPoints2;
int pointCnt = numPoints1 + numPoints2 + 1;
CLLocationCoordinate2D coos[pointCnt];
pointCnt = 0;
coos[pointCnt] = CLLocationCoordinate2DMake(y1, x1);
pointCnt++;
for (int i = 1; i < numPoints1; i++) {
coos[pointCnt] = CLLocationCoordinate2DMake((y + r * sin(angle1 - phase1 * i)),(x + r * cos(angle1 - phase1 * i)));
pointCnt++;
}
coos[pointCnt] = CLLocationCoordinate2DMake(y2, x2);
pointCnt++;
for (int i = 1; i < numPoints2; i++) {
coos[pointCnt] = CLLocationCoordinate2DMake((y + r * sin(angle2 - phase2 * i)),(x + r * cos(angle2 - phase2 * i)));
pointCnt++;
}
coos[pointCnt] = CLLocationCoordinate2DMake(y3, x3);
pointCnt++;

图片截图

  • (UIImage *)takeSnapshotInRect:(CGRect)rect {
    UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, [UIScreen mainScreen].scale);
    [self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    if (CGRectEqualToRect(rect, self.bounds)) {
      return image;
    
    }
    CGFloat scale = image.scale;
    CGRect scaledRect = CGRectMake(rect.origin.x * scale, rect.origin.y * scale, rect.size.width * scale, rect.size.height * scale);
    CGImageRef rectImage = CGImageCreateWithImageInRect(image.CGImage,scaledRect);
    return [UIImage imageWithCGImage:rectImage];
    }

    地图手势

    // 单击
    UITapGestureRecognizer * singletapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onSingleTap:)];
    [singletapGesture setNumberOfTapsRequired:1];
    [singletapGesture setNumberOfTouchesRequired:1];
    [self addGestureRecognizer:singletapGesture];
    双击
    UITapGestureRecognizer * doubletapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onDoubleTap:)];
    [doubletapGesture setNumberOfTapsRequired: 2];
    [doubletapGesture setNumberOfTouchesRequired: 1];
    [self addGestureRecognizer:doubletapGesture];
    [singletapGesture requireGestureRecognizerToFail:doubletapGesture];
    长按
    UILongPressGestureRecognizer* longPressGr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
    [self addGestureRecognizer:longPressGr];
    缩放
    UITapGestureRecognizer *m_pZoomoutGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onZoomOut:)];
    [m_pZoomoutGesture setNumberOfTapsRequired:1];
    [m_pZoomoutGesture setNumberOfTouchesRequired:2];
    [self addGestureRecognizer:m_pZoomoutGesture];
    拖拽
    m_pSinglePanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onScroll:)];
    [m_pSinglePanGesture setMaximumNumberOfTouches:1];
    [self addGestureRecognizer:m_pSinglePanGesture];
    旋转
    UIPanGestureRecognizer * doublePanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(onOverlook:)];
    [doublePanGesture setMinimumNumberOfTouches:2];
    [self addGestureRecognizer:doublePanGesture];
    m_pPinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinch:)];
    m_pPinchGesture.delegate = self;
    [self addGestureRecognizer:m_pPinchGesture];
    缩放
    m_pRotateGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(onRotate:)];
    m_pRotateGesture.delegate = self;
    [self addGestureRecognizer:m_pRotateGesture];

比例尺绘制

  • (void)drawRect:(CGRect)rect {

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetRGBStrokeColor(context, 0.0f, 0.0f, 0.0f, 1.0f); //画笔颜色
    CGContextSetLineWidth(context, 1.0); //线宽

    CGFloat scale = [UIScreen mainScreen].scale;
    int zoomLevel = self.zoomLevel;

    int iLength = (MASCALE_DISTANCES[zoomLevel] /([self.mapView metersPerPointForZoomLevel:zoomLevel] * scale));
    if (iLength >200) {

      iLength = 200;
    

    }
    int iStartX = rect.origin.x;
    int iStartY = rect.size.height - 12;
    int iEndY = rect.size.height - 9;
    NSString *name = MASCALE_DISTANCESNAME[zoomLevel];
    [name drawInRect:CGRectMake(iStartX + SCALE_NAME_STARTX, iStartY - 13, rect.size.width, rect.size.height) withFont:[UIFont systemFontOfSize:10.0]];

    CGPoint points[2];//坐标点
    points[0] = CGPointMake(iStartX, iEndY);//坐标1
    points[1] = CGPointMake(iStartX + iLength, iEndY);//坐标2
    CGContextAddLines(context, points, 2);//添加线
    CGContextDrawPath(context, kCGPathStroke);

    points[0] = CGPointMake(iStartX, iStartY); //坐标1
    points[1] = CGPointMake(iStartX, iEndY); //坐标2
    CGContextAddLines(context, points, 2); //添加线
    CGContextDrawPath(context, kCGPathStroke);

    points[0] = CGPointMake(iStartX + iLength, iStartY);//坐标1
    points[1] = CGPointMake(iStartX + iLength, iEndY);//坐标2
    CGContextAddLines(context, points, 2);//添加线
    CGContextDrawPath(context, kCGPathStroke);
    }

点到直线的距离

  • (CGFloat)lineDistance:(CGPoint)point linePoint1:(CGPoint)line1 linePoint2:(CGPoint)line2
    {
    CGFloat se = (line1.x-line2.x)(line1.x-line2.x)+(line1.y-line2.y)(line1.y-line2.y);//线段两点距离平方
    CGFloat p = ((point.x-line1.x)(line2.x-line1.x)+(point.y-line1.y)(line2.y-line1.y)); //向量点乘=|a||b|cosA
    CGFloat r = p / se; //r即点到线段的投影长度与线段长度比
    CGFloat outx = line1.x + r * (line2.x-line1.x);
    CGFloat outy = line1.y+r
    (line2.y-line1.y);
    CGFloat des =(point.x-outx)
    (point.x-outx)+(point.y-outy)*(point.y-outy);
    return sqrt(des);
    }

检查某点是否包含在多边形的范围内(判断多边形是否被点击

  • (BOOL)PointInPoly:(CGPoint *)poly count:(int)count point:(CGPoint)pt {
    BOOL c = false;
    int i = -1, l = count;
    for (int j = l - 1; ++i < l; j = i){
      ((poly[i].y <= pt.y && pt.y < poly[j].y) || (poly[j].y <= pt.y && pt.y < poly[i].y)) && (pt.x < (poly[j].x - poly[i].x) * (pt.y - poly[i].y) / (poly[j].y - poly[i].y) + poly[i].x) && (c = !c);
    
    }
    return c;
    }

    判断折线是否被点击

    原理:点到线的距离是否大与线的宽度
    MAPolylineRenderer *line = (MAPolylineRenderer *)ovlay;
    CLLocationCoordinate2D *coo = line.polyline.points;
    long count = line.polyline.pointCount;
    for (int i = 0; i < count - 1; i++) {
      CLLocationCoordinate2D item = coo[i];
      CLLocationCoordinate2D item1 = coo[i + 1];
      CGPoint point1 = [m_pSkMap lonlat2Pixel:item];
      CGPoint point2 = [m_pSkMap lonlat2Pixel:item1];
      CGFloat dis = [self lineDistance:point linePoint1:point1 linePoint2:point2];
      if (dis < line.lineWidth * 3) { // 为了防止点不上,给进行了加大处理
          return line.polyline;
      }
    
    }

    判断是否在弧形上

    原理:同线的点击
    MAArcRenderer *arcRenderer = (MAArcRenderer *)ovlay;
    MAArc *arc = arcRenderer.arc;
    int count = arc.pointCount;
    CLLocationCoordinate2D *coo = arc.points;
    for (int i = 0; i < count - 1; i++) {
      CLLocationCoordinate2D item = coo[i];
      CLLocationCoordinate2D pointCoo = [m_pSkMap pixel2LonLat:point];
      CLLocationDistance dis = MAMetersBetweenMapPoints(item,pointCoo);
      CGFloat zoom = [m_pSkMap getZoom];
     if (dis < arcRenderer.lineWidth * 500 / zoom) { // 为了防止点不上,给进行了加大处理
         return arc;
     }
    
    }

    判断是否在圆内

    原理:点到圆心的距离小于半径
    MACircleRenderer *circle = (MACircleRenderer *)ovlay;
    CLLocationCoordinate2D coo = circle.circle.coordinate;
    CLLocationCoordinate2D sele = [m_pSkMap pixel2LonLat:point];
    double dis = MAMetersBetweenMapPoints(coo,sele);
    if (dis < circle.circle.radius) {
      return circle.circle;
    
    }

    判断矩形画图标是否被点击

    判断点击是否在矩形图标rect内
    MAMarkerRenderer *mark = (MAMarkerRenderer *)ovlay;
    CGPoint markPoint = [m_pSkMap lonlat2Pixel:mark.marker.coordinate];
    CGSize imageSize = mark.imageSize;
    CGFloat scale = 1;
    if (mark.image) { // 不规则图形处理
      scale = mark.imageSize.height / mark.imageSize.width;
      if (scale > 1) {
          imageSize.width = mark.imageSize.width / scale;
          imageSize.height = mark.imageSize.height / scale;
          markPoint.x = markPoint.x + imageSize.width / scale;
      }else{
          imageSize.width = mark.imageSize.width * scale;
          imageSize.height = mark.imageSize.height * scale;
      }
    
    }
    CGRect rect = CGRectMake(markPoint.x, markPoint.y, imageSize.width,imageSize.height);
    if (CGRectContainsPoint(rect,point)) {
      return mark.marker;
    
    }

覆盖物的拖拽:

1.通过长按手势触发拖拽
2.通过判断是否点击了多边形,判断是否在拖拽覆盖物
3.计算移动的坐标数量,获取覆盖物新的坐标位置
4.修改覆盖物坐标位置