【问题标题】:Drawing Great Circle overlay lines on an MKMapView在 MKMapView 上绘制大圆覆盖线
【发布时间】:2011-08-31 13:30:45
【问题描述】:

我正在尝试在 MKMapView 上的两个纬度/经度点之间绘制一条大圆线。这是一条看起来是圆形的线(地球上的一条“直线”),并且是最好的可视化here。事实上,这个非常奇怪的 WordPress 网站似乎开始准确地描述如何做到这一点,但在最初的几个步骤之后它就突然结束了。

阅读我看到的 Apple 文档

在 iOS 4.0 及更高版本中,您还可以使用投影地图坐标而不是区域来指定一些值。当您将地球的曲面投影到平面上时,您会得到一个二维版本的地图,其中经线看起来是平行的。此地图上的位置和距离使用 MKMapPoint、MKMapSize 和 MKMapRect 数据类型指定。您可以使用这些数据类型来指定地图的可见区域以及何时指定叠加层的位置。

我不确定如何将它应用到 Great Circle 叠加层。有人可以帮忙吗?

【问题讨论】:

  • 作为后续,我还没有找到解决方案,并且已经离开了 MKMapView。我为 Bing Maps AJAX 界面 (v7) 采用了一些 JavaScript,并打算在 WebView 中显示地图。

标签: ios mkmapview great-circle


【解决方案1】:

我已经使用 MKPolyline 为在两个机场之间飞行的飞机绘制了一个很棒的圆形路线。

+ (void)createGreatCircleMKPolylineFromPoint:(CLLocationCoordinate2D)point1 
                                     toPoint:(CLLocationCoordinate2D)point2
                                  forMapView:(MKMapView*)mapView
{
double lat1 = point1.latitude;
double lon1 = point1.longitude;
double lat2 = point2.latitude;
double lon2 = point2.longitude;
lat1 = lat1 * (PI/180);
lon1 = lon1 * (PI/180);
lat2 = lat2 * (PI/180);
lon2 = lon2 * (PI/180);
double d = 2 * asin( sqrt(pow(( sin( (lat1-lat2)/2) ), 2) + cos(lat1) * cos(lat2) * pow(( sin( (lon1-lon2)/2) ), 2)));
int numsegs = 100;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numsegs);
double f = 0.0;
for(int i=1; i<=numsegs; i++)
{
    f += 1.0 / (float)numsegs;
    double A=sin((1-f)*d)/sin(d);
    double B=sin(f*d)/sin(d);
    double x = A*cos(lat1) * cos(lon1) +  B * cos(lat2) * cos(lon2);
    double y = A*cos(lat1) * sin(lon1) +  B * cos(lat2) * sin(lon2);
    double z = A*sin(lat1)           +  B*sin(lat2);
    double latr=atan2(z, sqrt(pow(x, 2) + pow(y, 2) ));
    double lonr=atan2(y, x);
    double lat = latr * (180/PI);
    double lon = lonr * (180/PI);
    //        NSLog(@"lat: %f lon: %f", lat, lon);
    CLLocationCoordinate2D loc = CLLocationCoordinate2DMake(lat, lon);
    coords[i - 1] = loc;
}

//check for circling west to east. If the plane is crossing 180, we need
//to draw two lines or else the polyline connects the dots and draws a straight
//line all the way across the map.
CLLocationCoordinate2D prevCoord;
BOOL twoLines = NO;
int numsegs2 = 0;
CLLocationCoordinate2D *coords2;

for(int i=0; i<numsegs; i++)
{
    CLLocationCoordinate2D coord = coords[i];
    if(prevCoord.longitude < -170 && prevCoord.longitude > -180  && prevCoord.longitude < 0 
       && coord.longitude > 170 && coord.longitude < 180 && coord.longitude > 0)
    {
        twoLines = YES;
        coords2 = malloc(sizeof(CLLocationCoordinate2D) * (numsegs - i));
        numsegs2 = numsegs - i;
        for(int j=0; j<numsegs2; j++)
        {
            coords2[j] = coords[i + j];
        }
        break;
    }
    prevCoord = coord;
}

//remove any previously added overlays
[mapView removeOverlays:mapView.overlays];

if(twoLines)
{
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:numsegs - numsegs2];
    free(coords);
    [mapView addOverlay:polyline];

    MKPolyline *polyline2 = [MKPolyline polylineWithCoordinates:coords2 count:numsegs2];
    free(coords2);
    [mapView addOverlay:polyline2];
}
else
{
    MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coords count:numsegs];
    free(coords);
    [mapView addOverlay:polyline];
}

}

您现在已经创建了叠加层,现在您只需要在 mapView:viewForOverlay 中提供一个 MKOverlayView。

- (MKOverlayView*)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
    MKPolyline *polyline = (MKPolyline*)overlay;
    MKPolylineView *view = [[[MKPolylineView alloc] initWithPolyline:polyline] autorelease];
    //choose your line params here
    view.lineWidth = 2;
    view.fillColor = [UIColor blueColor];
    return view;
}

希望这会有所帮助。

Screenshot http://s1-03.twitpicproxy.com/photos/large/489178500.png

【讨论】:

    【解决方案2】:

    虽然已经很晚了,但值得一提的是MKGeodesicPolyline,这是自 iOS 7.0 以来的新功能,它“沿着地球表面追踪最短路径”。

    有了这个,创建和添加测地线折线类型的MKPolylineOverlay 变得简单。

    points = [CLLocationCoordinate2DMake(27.123, 85.765),
                      CLLocationCoordinate2DMake(41.444, 106.987)]
    geodesic = MKGeodesicPolyline(coordinates: points, count: 2)
    mapView.add(geodesic)
    

    记得包含渲染器并给 mapView 一个委托:

    //MARK: - MKMapView Delegate Method
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if overlay is MKGeodesicPolyline {
            let polylineRenderer = MKPolylineRenderer(overlay: overlay)
            polylineRenderer.strokeColor = UIColor.white
            polylineRenderer.lineWidth = 2.5
            return polylineRenderer
        }
    }
    

    【讨论】:

      【解决方案3】:

      这可以通过创建 MKOverlayPathView 类的子类来完成。您需要重写 (void)createPath 方法,基本上您可以使用 UIBezierPath 来创建弧线,或者直接创建弧线作为路径,这是可能的,但我还没有这样做。

      在方法上定义路径后,需要使用新创建的路径设置类的路径属性。这样,路径的渲染将自动完成。

      希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        numsegs 参数应根据地图缩放级别和两点的距离进行更改。两点的纬度/经度坐标可以转换为像素坐标。因此,numsegs 参数可以被视为像素差异的函数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-10-19
          • 2015-09-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-13
          相关资源
          最近更新 更多