iOS 開発者ガイド for SDK

カスタムのラスタータイル

SDK for iOS を使用すると、カスタムのラスタタイル API NMAMapTileLayerを使用してマップを拡張できます。

カスタムのラスタタイルは、地図に追加できるタイル画像です。この画像を使用すると、地理的に広い範囲の追加情報で地図を拡張できます。 カスタムのラスタタイルを表示するようにアプリケーションが設定されている場合、ユーザーは、指定されたズーム レベルまたは一定範囲のズームレベルで指定された地理的領域を表示するたびに、それらのタイルを表示できます。

タイルイメージは、次の 2 つの方法で提供できます。
  1. カスタムのラスタタイルイメージをリモートサーバーに保存 NMAMapTileLayerDataSource mapTileLayer:urlForTileAtX:y:zoomLevel: し、プロトコルメソッドを使用して URL を返します。
  2. NMAMapTileLayerDataSource mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest: プロトコルメソッドを使用して、生のビットマップデータを提供します。
注 : ラスタタイルを有効にする前に、押し出し建物フィーチャーが無効になっていることを確認してください。両方のフィーチャーの外観がうまく合わせられません。

GitHub でラスタタイルの例をマップします

この機能を示す例について は、 https://github.com/heremaps/ (Obj-C) および https://github.com/heremaps/ (Swift) を参照してください。

地図を分割し、タイル座標を使用します

NMAMapTileLayer ワールドマップを、 x 、 y 、およびズーム レベル座標で指定されたタイルに分割するスキームを使用します。 NMAMapTileLayerDataSource この座標系は、タイルを要求するときにプロトコルによって使用されます。

各ズーム レベルでは、ワールドマップが (2 zoomlevel ) 2タイルにレンダリングされることが想定 されています。
  • レベル 0 の場合 : 1 x 1 = 1 タイル
  • レベル 1 の場合 : 2 x 2 = 4 タイル
  • レベル 2 の場合 : 4 x 4 = 16 タイル
  • レベル 3 の場合 : 8 x 8 = 64 タイル
  • レベル 4 の場合 : 16 x 16 = 256 タイル
  • ズーム レベル 20 まで続行します

たとえば、ズーム レベル 2 では、ワールドマップは次のように分割されます。

図 1. ズーム レベル 2 の世界地図

x および y パラメータは、指定されたズーム レベルに要求されているタイルを示します。

地理的領域内でサポートしているすべてのズームレベルをカバーするのに十分なタイルイメージを提供する必要があります。 NMAMapTileLayerboundingBox プロパティを使用して、カスタムタイルレンダリングを特定の NMAGeoBoundingBox に制限できます。 および showAtZoomLevel: 関連するメソッドを使用して、ズーム レベルを制限できます。

Web サーバーからタイルを提供しています

Web サーバーからマップ ビューにカスタムタイルを提供する手順は、次のとおりです。
  1. サーバー上の適切な数のタイルをズームレベルに従ってホスト NMAGeoBoundingBox し、サポートしている必要があります。 タイルは PNG または JPG 形式で、 256 x 256 ピクセルのサイズにする必要があります ( これは既定のサイズですが、変更できます ) 。
  2. サーバー上の指定したタイルを参照する URL を返すように、派生元 NMAMapTileLayerDataSource のオブジェクトを作成して mapTileLayer:urlForTileAtX:y:zoomLevel:method インプリメントします。
  3. NMAMapTileLayer オブジェクトを作成し、そのプロパティをタイルデータソースサーバーに対応するように設定します。 少なくとも、サーバーでホストされているタイルを反映するように boundingBox および zoomLevel のプロパティを設定してください。 dataSource プロパティを設定します。
  4. オプション fadingEnabledで、などのプロパティを設定して、マップ ビュー内のタイルの外観をカスタマイズします。
  5. addMapTileLayer: メソッドを呼び出して、 NMAMapTileLayer オブジェクトを NMAMapView に追加します。

次のコード スニペットは、ロンドンのクイーンエリザベスオリンピックパークをレンダリングするクラスを示しています。 パークは、NMAMapViewに追加されたタイルレイヤーとして表示 され、ラスタタイルは HERE サーバーから提供されます。 このクラスを使用するには、を呼び出し [OlympicParkTileLayer addOlympicParkTileLayerToMapView:myMapView]ます。


@interface OlympicParkTileLayer : NMAMapTileLayer <NMAMapTileLayerDataSource>
@end

@implementation OlympicParkTileLayer

+(void)addOlympicParkTileLayerToMapView:(NMAMapView*)mapView
{
  OlympicParkTileLayer *tileLayer = [OlympicParkTileLayer new];
  [mapView addMapTileLayer:tileLayer];
  [mapView setGeoCenter:tileLayer.boundingBox.center
      zoomLevel:14.0
      orientation:NMAMapViewPreserveValue
      tilt:NMAMapViewPreserveValue
      withAnimation:NMAMapAnimationNone ];
}

-(id)init
{
  if (self = [super init]) {
    // Set the data source
    self.dataSource = self;

    // Set the bitmap format properties (must be compatible with pngs hosted on the
    // server)
    self.pixelFormat = NMAPixelFormatRGBA;
    self.transparent = NO;

    // Limit the tiles to the bounding box supported by the server
    NMAGeoBoundingBox *olympicParkBoundingBox =
    [NMAGeoBoundingBox geoBoundingBoxWithTopLeft:
      [NMAGeoCoordinates geoCoordinatesWithLatitude:51.557000 longitude:-0.042772]
      bottomRight:
      [NMAGeoCoordinates geoCoordinatesWithLatitude:51.525941 longitude: 0.028296]];
    self.boundingBox = olympicParkBoundingBox;

    // Customize the tile layer
    self.fadingEnabled = YES;
    // covers everything else on the map
    self.mapLayerType = NMAMapLayerTypeForeground;

    // Enable caching
    self.cacheTimeToLive = 60 * 60 * 24;  // 24 hours
    self.cacheSizeLimit = 1024 * 1024 * 64; // 64MB
    [self setCacheEnabled:YES withIdentifier:@"OlympicParkTileLayer"];
  }
  return self;
}

-(NSString *)mapTileLayer:(NMAMapTileLayer *)mapTileLayer
      urlForTileAtX:(NSUInteger)x
            y:(NSUInteger)y
        zoomLevel:(NSUInteger)zoomLevel
{
  // Return a URL for the specified tile
  // This tile source is hosted by HERE Global B.V. and may be removed at any time
  return [NSString stringWithFormat:
    @"http://api.maps.example.org/maptiles/olympic_park/normal.day/%d/%d/%d.png",
    zoomLevel,
    y,
    x ];
}

@end

タイルをビットマップとして指定します

アプリでバンドルされた静的タイル、動的に生成されたタイル、またはタイルイメージに使用しているサーバーで認証が必要な場合は、タイルをビットマップとして提供することを選択できます。 3 つ目のケースでは NMAMapTileLayer 、単純な HTTP GET 要求を使用してタイルイメージを取得するだけであるため、認証を処理してタイルをダウンロードするコードを提供するかどうかはユーザーの責任になります。 タイルがダウンロードされたら NMAMapTileLayer 、クラスのローカルビットマップとして使用できます。

カスタムタイルをローカルビットマップとしてマップ ビューに提供する手順は、次のとおりです。
  1. NMAMapTileLayerDataSource メソッドから派生し、 mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest: メソッドを実装するオブジェクトを作成します。 NMAMapTileRequest パラメーターを保持して使用し、要求されたビットマップデータを提供します。
  2. NMAMapTileLayer オブジェクトを作成し、そのプロパティをタイルデータソースに対応するように設定します。 dataSource プロパティを設定します。
  3. オプション fadingEnabledで、などのプロパティを設定して、マップ ビュー内のタイルの外観をカスタマイズします。
  4. addMapTileLayer: メソッドを呼び出して、 NMAMapTileLayer オブジェクトを NMAMapView に追加します。

NMAMapView タイルレイヤーを使用して上で赤と緑のタイルをレンダリングするクラスの例を次に示します。 を呼び出すことで使用 [SimpleBitmapTileLayer addSimpleBitmapTileLayerToMapView]できます。


@interface SimpleBitmapTileLayer : NMAMapTileLayer <NMAMapTileLayerDataSource>
{
  char *_redBitmap;
  char *_greenBitmap;
}
@end

@implementation SimpleBitmapTileLayer

+(void)addSimpleBitmapTileLayerToMapView:(NMAMapView*)mapView
{
  [mapView addMapTileLayer:[SimpleBitmapTileLayer new]];
}

-(id)init
{
  if (self = [super init]) {

    // Set the data source
    self.dataSource = self;

    // Set the bitmap properties (must match what is returned in 
    // requestDataForTileAtX:)
    self.pixelFormat = NMAPixelFormatRGBA;
    self.transparent = NO;

    // The tiles will replace the map background
    self.mapLayerType = NMAMapLayerTypeArea;

    // We want the tiles to span the globe so don't limit with a bounding box or 
    // zoom level.

    // We don't want to cache these tiles to disk, as in this simple case
    // it's more efficient to keep bitmaps in memory.

    // Create a red bitmap
    _redBitmap = (char *)malloc(256*256*4);
    for (int i=0; i<256*256*4; i+=4) {
      _redBitmap[i] = 0xFF;
      _redBitmap[i+1] = 0x00;
      _redBitmap[i+2] = 0x00;
      _redBitmap[i+3] = 0xFF;
    }

    // Create a green bitmap
    _greenBitmap = (char *)malloc(256*256*4);
    for (int i=0; i<256*256*4; i+=4) {
      _greenBitmap[i] = 0x00;
      _greenBitmap[i+1] = 0xFF;
      _greenBitmap[i+2] = 0x00;
      _greenBitmap[i+3] = 0xFF;
    }
  }

  return self;
}

-(void)dealloc
{
  free(_redBitmap);
  free(_greenBitmap);
}

-(void)   mapTileLayer:(NMAMapTileLayer *)mapTileLayer
   requestDataForTileAtX:(NSUInteger)x
             y:(NSUInteger)y
         zoomLevel:(NSUInteger)zoomLevel
       tileRequest:(NMAMapTileRequest *)tileRequest
{
  // Dispatch to a global queue to demonstrate retaining the tile request and 
  // completing asynchronously. In this case it is not necessary but if obtaining 
  // the bitmap data was a lengthy operation we would not want to block the current 
  // (map rendering) thread.
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Use alternating red and green bitmaps to create checkerboard effect
    void *bitmap = ( (x%2==0 && y%2==1) || (x%2 ==1 && y%2==0) ) ? _redBitmap : 
      _greenBitmap;

    // Copy the bitmap into the bitmap buffer supplied by the tile request
    // Copy exactly tileRequest.bytesLength
    memcpy(tileRequest.bytesPtr, bitmap, tileRequest.bytesLength);

    // Complete the tile request AFTER the copy has completed
    tileRequest.status = NMAMapTileRequestStatusComplete;
  });
}

@end
NMAMapTileRequest このオブジェクトを使用する際に考慮すべき重要な点がいくつかあります。
  1. ビットマップデータは NMAMapTileLayer pixelFormat 、プロパティで指定された形式にする必要があります。 デフォルトはです NMAPixelFormatRGBA
  2. 要求を完了する前にビットマップバイトをコピーし、 bytesLength で指定されたバイト数のみをコピーして、メモリの破損を防ぎます。
  3. リクエストは NMAMapTileRequestStatusComplete 、必ずまたはのいずれかを使用して正確に 1 回完了 NMAMapTileRequestStatusFailedしてください。 未完了のリクエストは、完了するまでメモリを占有します。
  4. mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest: レンダリングのパフォーマンスに影響を与えるため、長期間ブロックしないでください。

オーバーレイのレンダリング順序を変更しています

プロパティを使用 mapLayerType して、ラスタタイルがレンダリングされるマップ レイヤーをカスタマイズできます。 たとえば、作成した NMAMapObjects と共にタイルを NMAMapLayerTypeForeground レイヤーに配置する場合、 zIndex を使用して、タイルの上または下にオブジェクトをレンダリングするかどうかを制御できます。

その他のタイルのカスタマイズ

NMAMapTileLayer では、次のようなタイルの外観をさらにカスタマイズするためのプロパティがサポートされています。
  • タイルサイズ
  • RGB や BGRA などのピクセル形式 ( メモリ使用量を削減するため )
  • タイルが描画されるときにフェードインするかどうかを指定します
  • 欠落しているタイルの代わりに、別のズーム レベルからのタイルをレンダリングするかどうかを指定します
  • タイルが透明度をサポートするかどうかを示します

タイルのキャッシュ

タイルをディスクにキャッシュして、 URL フェッチケースのパフォーマンスを改善し、データトラフィックを削減できます。

キャッシュを有効にする場合は、キャッシュ識別子を指定する必要があります。 この識別子は NMAMapTileLayer 、アプリケーション内で使用されている各識別子で一意である必要があります。 キャッシュはアプリセッション間で保持されるため、(定数を定義するなどして)セッション間で同じ識別子を使用することが重要です。

オプションで、キャッシュされた各タイルのキャッシュサイズと存続時間を制限できます。 を呼び出すと、いつでもキャッシュを消去 [NMAMapTileLayer clearCache]できます。 キャッシュが完全に消去されたことを確認するには、 [NMAMapTileLayer clearCache] を呼び出す前に、まずマップ ビューから NMAMapTileLayer を削除します。

次のコードでは、最大 128 MB のディスクキャッシュと、 7 日間のタイル有効期間を有効にします。

NMAMapTileLayer *tileLayer = [[NMAMapTileLayer alloc]init];
tileLayer.dataSource = self; // Assuming self is a valid data source
[tileLayer setCacheEnabled:YES withIdentifier:@"MyUniqueTileCacheIdenfifier"];
tileLayer.cacheTimeToLive = 60 * 60 * 24 * 7; // 7 days
tileLayer.cacheSizeLimit = 1024 * 1024 * 128; // 128 MB
[mapView addMapTileLayer:tileLayer]; // NOTE: add to map view after setting tile properties
      

パフォーマンスのヒント

  1. 重要 : NMAMapTileLayer タイルレイヤーをマップ ビューに追加する前に、プロパティを設定します。 ほとんどのプロパティでは、ビューに追加された後での設定は無視されます。
  2. 1 NMAMapTileLayer つのインスタンスを複数のマップに追加しないでください。
  3. タイルレイヤーで設定したプロパティが NMAMapTileLayerDataSource 、プロトコル経由で提供しているデータと一致することを確認してください。 たとえば、タイルデータが透明機能をサポートしていない場合は、透明機能を有効にしないでください。
  4. NMAMapTileLayerDataSource メソッドを長期間ブロックしないでください。 たとえば、その場でタイルを生成するのに時間がかかる場合は、処理を別の GCD キューに移動します。
  5. NMAMapTileRequest メモリ mapTileLayer:requestDataForTileAtX:y:zoomLevel:tileRequest: リークを避けるため、経由で受信したすべてのオブジェクトが完了していることを確認します。
  6. NMAMapTileRequest bytesPtr メモリのコピーを避けるために、プロパティに直接書き込みます。
  7. 特定のタイルの要求が頻繁に失敗する場合は、 NO RETURNING mapTileLayer:hasTileAtX:y:zoomLevel: の実装を検討してください。
  8. 提供されているディスクキャッシュメカニズムを使用します。