MKMapPoint with MKMapPointMake from MKMapRect

ぃ、小莉子 提交于 2020-01-23 03:37:25

问题


I have the following code:

 MKMapRect mRect = self.mapView.visibleMapRect;
 MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), MKMapRectGetMaxY(mRect)/2);
 MKMapPoint northMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect)/2, 0);
 MKMapPoint southMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect)/2, MKMapRectGetMaxY(mRect));
 MKMapPoint westMapPoint = MKMapPointMake(0, MKMapRectGetMaxY(mRect)/2);

I am converting these to CLLocationCoordinate2D with MKCoordinateForMapPoint. For example:

    CLLocationCoordinate2D northCoords = MKCoordinateForMapPoint(northMapPoint);

Along with northCoords, I have centerCoords which is the coordinates of the point in the center in the map. With these two set of coordinates, I create an array CLLocationCoordinate2D coordinates[2] to which I add these two sets...

Following, I use the following code to draw a line between the two coordinates:

    MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coordinates count:2];
    [_mapView addOverlay:polyLine];


- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay 
{
    MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
    polylineView.strokeColor = [UIColor redColor];
    polylineView.lineWidth = 5.0;
    return polylineView;
}

The Problem:

The polyline overlay starting point (center of the map) is correct always starting at the center. However the other end of the line (north/south/east/west) does not point correctly to where it should be. In the image below I am drawing all four lines respective to the 4 MKMapPoint above.


回答1:


The overall idea is correct but there are two problems:

  1. Code assumes that the visibleMapRect's bounds are from 0,0 which they are usually not. The visibleMapRect.origin property has the starting offset. This has to be taken into account when calculating the midpoint.

    With the current code, if the bounds are say from 80 to 100, MKMapRectGetMaxX(mRect)/2 returns 50 but the visible map rect is from 80 to 100 so the line ends somewhere before the minimum x (instead of setting the ending x to 90).

    So instead of MKMapRectGetMaxX(mRect)/2, it should be (MKMapRectGetMinX(mRect) + MKMapRectGetMaxX(mRect))/2 or even simpler MKMapRectGetMidX(mRect).

    Same applies to the y position.

  2. Code assumes that the user location will be at the center of the map. If this is guaranteed, then you can use the midpoint as above. However, this is an unnecessary restriction. You can easily adjust the code so it works even if the user location is not in the center:

    //first convert userLocation to map points...
    MKMapPoint userLocationMapPoint = 
        MKMapPointForCoordinate(mapView.userLocation.coordinate);
    
    MKMapPoint eastMapPoint = MKMapPointMake(MKMapRectGetMaxX(mRect), 
                                             userLocationMapPoint.y);
    
    MKMapPoint northMapPoint = MKMapPointMake(userLocationMapPoint.x, 
                                              MKMapRectGetMinY(mRect));
    
    MKMapPoint southMapPoint = MKMapPointMake(userLocationMapPoint.x, 
                                              MKMapRectGetMaxY(mRect));
    
    MKMapPoint westMapPoint = MKMapPointMake(MKMapRectGetMinX(mRect), 
                                             userLocationMapPoint.y);
    


The above should work for the 0 (N), 90 (E), 180 (S), and 270 (W) positions but this can be generalized for any angle using some trigonometry:

//radiusMapPoints will be the length of the line (max of width or height).
double radiusMapPoints = MAX(mRect.size.width, mRect.size.height);

//thetaRadians is the heading of the line in radians.
//Example below is for 45.0 degrees.
double thetaRadians = 45.0 * (M_PI/180.0);

//endMapPoint is end of line starting from user location.
MKMapPoint endMapPoint;
endMapPoint.x = userLocationMapPoint.x + (radiusMapPoints * sin(thetaRadians));
endMapPoint.y = userLocationMapPoint.y - (radiusMapPoints * cos(thetaRadians));

CLLocationCoordinate2D lineCoords[2];
lineCoords[0] = mapView.userLocation.coordinate;
lineCoords[1] = MKCoordinateForMapPoint(endMapPoint);

MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:lineCoords count:2];
//can also use polylineWithPoints and pass MKMapPoints instead
[mapView addOverlay:polyLine];


Also note that for iOS 7, you should implement the rendererForOverlay delegate method instead of viewForOverlay and return an MKPolylineRenderer instead of an MKPolylineView. Although iOS 7 currently still works if you only implement viewForOverlay it is technically deprecated. You can have both delegate methods so that the app works in any iOS version (iOS 6 will use viewForOverlay and iOS 7 will use rendererForOverlay it it's there).



来源:https://stackoverflow.com/questions/19968477/mkmappoint-with-mkmappointmake-from-mkmaprect

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!