Getting MKMapRect from MKTileOverlayPath

I've searched a lot for the answer and I can't imagine such a method doesn't exist !! I have MKTileOverlayPath (x, y and z) and also managed to get the lon / lat of the center of this rectangle. Now I need to get the spacing of each rectangle, is this possible?

+3


source to share


2 answers


Yes, although it's not entirely obvious with MapKit alone.

Tiles and blending paths are defined in a grid, where the number of dots on the (square) side of the map is equal 2^z * 256

, since the default tile size is 256px

square. z0

is a square tile 256px

, z1

is four tiles for the whole world of a square 512px

, etc. Tiled coordinates in this system are linear (all squares on a square map).

MKMapPoint

is derived from z20

such that MKMapSizeWorld

are the 268,435,456

display points on the side. If you do the math 2^20 * 256 = 268,435,456

. Map points are also linear (pixels / points on a square map).

Latitude and longitude are of course not linear as it is a predicted view, so you have functions like MKMetersPerMapPointAtLatitude()

.

If you have the following MKTileOverlayPath

:

  • z = 10

  • x = 12

  • y = 8

You know that the size of the point of the world 2^10 * 256 = 262,144

and that the world is the 2^10 = 1,024

tiles on the side.



The left edge of the tile 256 * 12 = 3,072

and the top edge 256 * 8 = 2,048

points down. They refer to z10

which is less than 268,435,456 / 262,144 = 1,024

times less than z20

.

This is MKMapPoint

of { x: (3,072 * 1,024 = 3,145,728), y: (2,048 * 1,024 = 2,097,152) }

.

The bottom right side is the same { x: 3,407,872, y: 2,359,296 }

(add tile size 256 * 1,024 = 262,144

to each).

You can use MKCoordinateForMapPoint()

for each to get CLLocationCoordinate2D

out, and subtract their differences to get MKCoordinateSpan

.

  • In the top left corner: { latitude: 84.8024737243345, longitude: -175.78125 }

  • Bottom right: { latitude: 84.7705283207591, longitude: -175.4296875 }

  • Span: { latitudeDelta: 0.0319454035754205, longitudeDelta: 0.3515625 }

Yes, these points are very close to the upper left area of ​​Alaska on the map, but this is logical, considering that x = 12

also y = 8

of the 1,024

tiles are numbered in the upper left corner.

@interface GridTileOverlay : MKTileOverlay

@end

@implementation GridTileOverlay
-(void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result {
    NSLog(@"Loading tile x/y/z: %ld/%ld/%ld",(long)path.x,(long)path.y,(long)path.z);

    int worldPointSize = pow(2,(int)path.z)*256; // 2^10 * 256 = 262,144
    int tilesOnASide = pow(2,(int)path.z);       // 2^10 = 1,024
    long leftEdge = path.x *256;                 // 256 * 12 = 3,072 points
    long topEdge = path.y *256;                  // 256 * 8  = 2,048
    int w = self.boundingMapRect.size.width;     // 2^20 * 256 = 268,435,456
    int zScale =  w / worldPointSize;            // 268,435,456 / 262,144 = 1,024
    int tileSize = 256 * zScale;                 // 256 * 1,024 = 262,144
    long x0 = leftEdge*zScale;                   // 3,072 * 1,024 = 3,145,728
    long y0 = topEdge*zScale;                    // 2,048 * 1,024 = 3,145,728
    long x1 = x0 + tileSize;
    long y1 = y0 + tileSize;

    MKMapPoint ul = MKMapPointMake(x0, y0);      // upper left
    MKMapPoint lr = MKMapPointMake(x1, y1);      // lower right
    MKMapRect mapRect = MKMapRectMake (fmin(ul.x, lr.x),
                              fmin(ul.y, lr.y),
                              fabs(ul.x - lr.x),
                              fabs(ul.y - lr.y));
}
@end  

      

+6


source


theme variations



  + (MKMapRect)mapRectForTilePath:(MKTileOverlayPath)path
{
    CGFloat xScale = (double)path.x / [self worldTileWidthForZoomLevel:path.z];
    CGFloat yScale = (double)path.y / [self worldTileWidthForZoomLevel:path.z];
    MKMapRect world = MKMapRectWorld;
    return MKMapRectMake(world.size.width * xScale,
                         world.size.height * yScale,
                         world.size.width / [self worldTileWidthForZoomLevel:path.z],
                         world.size.height / [self worldTileWidthForZoomLevel:path.z]);
}

/*
 Determine the number of tiles wide *or tall* the world is, at the given zoomLevel.
 (In the Spherical Mercator projection, the poles are cut off so that the resulting 2D map is "square".)
 */
+ (NSUInteger)worldTileWidthForZoomLevel:(NSUInteger)zoomLevel
{
    return (NSUInteger)(pow(2,zoomLevel));
}

      

+1


source







All Articles