다음을 통해 공유


지도에 바둑판식 이미지 오버레이

Important

엔터프라이즈 서비스 사용 중지를 위한 Bing Maps

Windows.Services.Maps 네임스페이스의 UWP MapControl 및 지도 서비스는 Bing Maps를 사용합니다. 엔터프라이즈용 Bing Maps는 더 이상 사용되지 않으며 사용 중지되며, 이 시점에서 MapControl 및 서비스는 더 이상 데이터를 수신하지 않습니다.

자세한 내용은 Bing Maps 개발자 센터Bing Maps 설명서를 참조하세요.

참고 항목

MapControl 및 지도 서비스를 사용하려면 MapServiceToken이라는 지도 인증 키가 필요합니다. 맵 인증 키 가져오기 및 설정에 대한 자세한 내용은 맵 인증 키 요청을 참조하세요.

타일 소스를 사용하여 지도에 타사 또는 사용자 지정 바둑판식 이미지를 오버레이합니다. 타일 소스를 사용하여 특수 정보(예제: 날씨 데이터, 인구 데이터, 지진 데이터 등)를 오버레이하거나 기본 지도를 전체적으로 바꿉니다.

바둑판식 이미지 개요

Bing Maps와 같은 지도 서비스는 빠른 검색 및 표시를 위해 맵을 사각형 타일로 잘라냅니다. 이 타일들은 크기가 256픽셀 x 256픽셀이며 다양한 수준의 정밀도로 미리 렌더링됩니다. 또한 상당수의 타사 서비스가 타일로 분할된 지도 기반 데이터를 제공합니다. 타일 소스를 사용하여 타사 타일을 검색하거나 사용자 지정 타일을 생성한 후 MapControl에 표시된 지도에 오버레이하세요.

타일 원본을 사용하는 경우 개별 타일을 요청하거나 배치하는 코드를 작성할 필요가 없습니다. MapControl은 필요에 따라 타일을 요청합니다. 각 요청에서는 개별 타일의 X/Y 좌표와 확대/축소 수준을 지정합니다. UriFormatString 속성에서는 타일 검색에 사용할 Uri 또는 파일 이름의 형식을 지정하기만 하면 됩니다. 다시 말해서, 각 타일의 X/Y 좌표와 확대/축소 수준을 전달할 위치가 표시되도록 기본 Uri 또는 파일 이름에 대체 가능한 매개변수를 넣어야 합니다.

다음은 X/Y 좌표 및 확대/축소 수준의 대체 가능한 매개변수를 보여 주는 HttpMapTileDataSource에 대한 UriFormatString 속성의 예입니다.

http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}

(X/Y 좌표는 지정된 수준의 정밀도로 세계 지도 내에서 개별 타일의 위치를 나타냅니다. 타일 번호 매기기 시스템은 지도의 왼쪽 상단에 있는 {0, 0}부터 시작됩니다. 그 예로 {1, 2}의 타일은 타일 그리드의 세 번째 행 두 번째 열에 있습니다.)

지도 서비스에서 사용되는 타일 시스템에 대한 자세한 내용은 Bing 지도 타일 시스템을 참조하세요.

타일 소스로부터 타일 오버레이하기

MapTileDataSource를 사용해서 지도의 타일 소스로부터 바둑판식 이미지를 오버레이하세요.

  1. MapTileDataSource로부터 상속되는 세 가지 타일 데이터 소스 클래스 중 하나를 인스턴스화하세요.

    기본 Uri 또는 파일 이름에 대체 가능한 매개변수를 넣어서 타일을 요청하는 데 사용할 UriFormatString을 구성하세요.

    다음 예제에서는 HttpMapTileDataSource를 인스턴스화합니다. 이 예제에서는 HttpMapTileDataSource 생성자에서 UriFormatString 값을 지정합니다.

        HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
          "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
    
  2. MapTileSource를 인스턴스화하고 구성하세요. 이전 단계에서 구성한 MapTileDataSourceMapTileSourceDataSource로 지정하세요.

    다음 예제에서는 MapTileSource 생성자의 DataSource를 지정합니다.

        MapTileSource tileSource = new MapTileSource(dataSource);
    

    MapTileSource의 속성을 사용하면 타일이 표시되는 조건을 제한할 수 있습니다.

    • 경계 속성의 값을 입력해서 특정 지리적 영역 내에서만 타일을 표시하세요.
    • ZoomLevelRange 속성의 값을 입력해서 특정 수준의 정밀도로만 타일을 표시하세요.

    타일의 로딩 또는 표시에 영향을 주는 MapTileSource의 다른 속성(예: 계층, AllowOverstretch, IsRetryEnabled, IsTransparencyEnabled)을 선택적으로 구성하세요.

  3. MapControlTileSources 컬렉션에 MapTileSource를 추가하세요.

         MapControl1.TileSources.Add(tileSource);
    

웹 서비스로부터 타일 오버레이하기

HttpMapTileDataSource를 사용해서 웹 서비스에서 검색된 바둑판식 이미지를 오버레이하세요.

  1. HttpMapTileDataSource를 인스턴스화하세요.

  2. 웹 서비스에서 예상되는 Uri의 형식을 UriFormatString 속성의 값으로 지정하세요. 이 값을 생성하려면 기본 URI에 대체 가능한 매개변수를 넣으세요. 그 예로 다음 코드 샘플에서 UriFormatString 값은 다음과 같습니다.

    http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}
    

    이 웹 서비스는 대체 가능한 매개변수 {x}, {y}, {zoomlevel}이 포함된 URI를 지원해야 합니다. 대부분의 웹 서비스(예: Nokia, Bing, Google)가 이 형식으로 된 Uri를 지원합니다. 웹 서비스에 UriFormatString 속성에서 사용할 수 없는 추가 인수가 필요한 경우에는 사용자 지정 Uri를 생성해야 합니다. UriRequested 이벤트를 처리해서 사용자 지정 Uri를 생성하고 반환하세요. 자세한 내용은 이 토픽의 뒷부분에 있는 사용자 지정 URI 제공하기 섹션을 참조하세요.

  3. 그런 다음 바둑판식 이미지 개요에 있는, 앞에서 설명한 나머지 단계를 따르세요.

다음 예제에서는 가상 웹 서비스의 타일을 북아메리카 지도에 오버레이합니다. UriFormatString 값은 HttpMapTileDataSource 생성자에 지정됩니다. 이 예제에서 타일은 선택적 경계 속성에 지정된 지리적 경계 내에만 표시됩니다.

private void AddHttpMapTileSource()
{
    // Create the bounding box in which the tiles are displayed.
    // This example represents North America.
    BasicGeoposition northWestCorner =
        new BasicGeoposition() { Latitude = 48.38544, Longitude = -124.667360 };
    BasicGeoposition southEastCorner =
        new BasicGeoposition() { Latitude = 25.26954, Longitude = -80.30182 };
    GeoboundingBox boundingBox = new GeoboundingBox(northWestCorner, southEastCorner);

    // Create an HTTP data source.
    // This example retrieves tiles from a fictitious web service.
    HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
        "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");

    // Optionally, add custom HTTP headers if the web service requires them.
    dataSource.AdditionalRequestHeaders.Add("header name", "header value");

    // Create a tile source and add it to the Map control.
    MapTileSource tileSource = new MapTileSource(dataSource);
    tileSource.Bounds = boundingBox;
    MapControl1.TileSources.Add(tileSource);
}
...
#include <winrt/Windows.Devices.Geolocation.h>
#include <winrt/Windows.UI.Xaml.Controls.Maps.h>
...
void MainPage::AddHttpMapTileSource()
{
    Windows::Devices::Geolocation::BasicGeoposition northWest{ 48.38544, -124.667360 };
    Windows::Devices::Geolocation::BasicGeoposition southEast{ 25.26954, -80.30182 };
    Windows::Devices::Geolocation::GeoboundingBox boundingBox{ northWest, southEast };

    Windows::UI::Xaml::Controls::Maps::HttpMapTileDataSource dataSource{
        L"http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}" };

    dataSource.AdditionalRequestHeaders().Insert(L"header name", L"header value");

    Windows::UI::Xaml::Controls::Maps::MapTileSource tileSource{ dataSource };
    tileSource.Bounds(boundingBox);

    MapControl1().TileSources().Append(tileSource);
}
...
void MainPage::AddHttpMapTileSource()
{
    BasicGeoposition northWest = { 48.38544, -124.667360 };
    BasicGeoposition southEast = { 25.26954, -80.30182 };
    GeoboundingBox^ boundingBox = ref new GeoboundingBox(northWest, southEast);

    auto dataSource = ref new Windows::UI::Xaml::Controls::Maps::HttpMapTileDataSource(
        "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");

    dataSource->AdditionalRequestHeaders->Insert("header name", "header value");

    auto tileSource = ref new Windows::UI::Xaml::Controls::Maps::MapTileSource(dataSource);
    tileSource->Bounds = boundingBox;

    this->MapControl1->TileSources->Append(tileSource);
}

로컬 스토리지로부터 타일 오버레이하기

LocalMapTileDataSource를 사용해서 로컬 스토리지에 파일로 저장된 바둑판식 이미지를 오버레이하세요. 일반적으로는 이 파일을 앱으로 패키징하고 배포해야 합니다.

  1. LocalMapTileDataSource를 인스턴스화하세요.

  2. 파일 이름의 형식을 UriFormatString 속성의 값으로 지정하세요. 이 값을 생성하려면 기본 파일 이름에 대체 가능한 매개변수를 넣으세요. 그 예로 다음 코드 샘플에서 UriFormatString 값은 다음과 같습니다.

        Tile_{zoomlevel}_{x}_{y}.png
    

    파일 이름의 형식에 UriFormatString 속성에서 사용할 수 없는 추가 인수가 필요한 경우에는 사용자 지정 Uri를 생성해야 합니다. UriRequested 이벤트를 처리해서 사용자 지정 Uri를 생성하고 반환하세요. 자세한 내용은 이 토픽의 뒷부분에 있는 사용자 지정 URI 제공하기 섹션을 참조하세요.

  3. 그런 다음 바둑판식 이미지 개요에 있는, 앞에서 설명한 나머지 단계를 따르세요.

다음 프로토콜 및 위치를 사용하면 로컬 스토리지로부터 타일을 로드할 수 있습니다.

URI 추가 정보
ms-appx:/// 앱의 설치 폴더의 루트를 가리킵니다.
이 위치는 Package.InstalledLocation 속성에서 참조하는 위치입니다.
ms-appdata:///local 앱의 로컬 스토리지의 루트를 가리킵니다.
이 위치는 ApplicationData.LocalFolder 속성에서 참조하는 위치입니다.
ms-appdata:///temp 앱의 temp 폴더를 가리킵니다.
이 위치는 ApplicationData.TemporaryFolder 속성에서 참조하는 위치입니다.

다음 예제에서는 ms-appx:/// 프로토콜을 사용해서 앱의 설치 폴더에 파일로 저장된 타일을 로드합니다. UriFormatString의 값은 LocalMapTileDataSource 생성자에 지정됩니다. 이 예제에서 타일은 지도의 확대/축소 수준이 선택적 ZoomLevelRange 속성에 지정된 범위 내에 있는 경우에만 표시됩니다.

void AddLocalMapTileSource()
{
    // Specify the range of zoom levels
    // at which the overlaid tiles are displayed.
    MapZoomLevelRange range;
    range.Min = 11;
    range.Max = 20;

    // Create a local data source.
    LocalMapTileDataSource dataSource = new LocalMapTileDataSource(
        "ms-appx:///TileSourceAssets/Tile_{zoomlevel}_{x}_{y}.png");

    // Create a tile source and add it to the Map control.
    MapTileSource tileSource = new MapTileSource(dataSource);
    tileSource.ZoomLevelRange = range;
    MapControl1.TileSources.Add(tileSource);
}

사용자 지정 URI 제공하기

HttpMapTileDataSourceUriFormatString 속성 또는 LocalMapTileDataSourceUriFormatString 속성과 함께 제공되는 대체 가능한 매개변수가 타일을 검색하기에 충분하지 않은 경우에는 사용자 지정 Uri를 생성해야 합니다. UriRequested 이벤트에 대한 사용자 지정 처리기를 제공해서 사용자 지정 Uri를 생성하고 반환하세요. UriRequested 이벤트는 각 개별 타일에 대해 발생합니다.

  1. UriRequested 이벤트에 대한 사용자 지정 처리기에서 필요한 사용자 지정 인수를 MapTileUriRequestedEventArgsX 속성, Y 속성 및 ZoomLevel 속성과 결합하여 사용자 지정 Uri를 생성하세요.
  2. MapTileUriRequestUri 속성(MapTileUriRequestedEventArgs요청 속성에 포함됨)에 사용자 지정 URI를 반환하세요.

다음 예제에서는 UriRequested 이벤트에 대한 사용자 지정 처리기를 생성해서 사용자 지정 Uri를 제공하는 방법을 보여줍니다. 비동기 작업을 수행해야 하는 경우 사용자 지정 Uri를 생성하기 위해 지연 패턴을 구현하는 방법도 보여줍니다.

using Windows.UI.Xaml.Controls.Maps;
using System.Threading.Tasks;
...
            var httpTileDataSource = new HttpMapTileDataSource();
            // Attach a handler for the UriRequested event.
            httpTileDataSource.UriRequested += HandleUriRequestAsync;
            MapTileSource httpTileSource = new MapTileSource(httpTileDataSource);
            MapControl1.TileSources.Add(httpTileSource);
...
        // Handle the UriRequested event.
        private async void HandleUriRequestAsync(HttpMapTileDataSource sender,
            MapTileUriRequestedEventArgs args)
        {
            // Get a deferral to do something asynchronously.
            // Omit this line if you don't have to do something asynchronously.
            var deferral = args.Request.GetDeferral();

            // Get the custom Uri.
            var uri = await GetCustomUriAsync(args.X, args.Y, args.ZoomLevel);

            // Specify the Uri in the Uri property of the MapTileUriRequest.
            args.Request.Uri = uri;

            // Notify the app that the custom Uri is ready.
            // Omit this line also if you don't have to do something asynchronously.
            deferral.Complete();
        }

        // Create the custom Uri.
        private async Task<Uri> GetCustomUriAsync(int x, int y, int zoomLevel)
        {
            // Do something asynchronously to create and return the custom Uri.        }
        }

사용자 지정 소스로부터 타일 오버레이하기

CustomMapTileDataSource를 사용해서 사용자 지정 타일을 오버레이하세요. 메모리에서 신속하게 프로그래밍 방식으로 타일을 생성하거나, 다른 소스로부터 기존 타일을 로드할 고유한 코드를 작성하세요.

사용자 지정 타일을 생성하거나 로드하려면 BitmapRequested 이벤트에 대한 사용자 지정 처리기를 제공하세요. BitmapRequested 이벤트는 각 개별 타일에 대해 발생합니다.

  1. BitmapRequested 이벤트에 대한 사용자 지정 처리기에서 필수 사용자 지정 인수를 MapTileBitmapRequestedEventArgsX 속성, Y 속성 및 ZoomLevel 속성과 결합시켜 사용자 지정 타일을 생성하거나 검색하세요.
  2. MapTileBitmapRequestPixelData 속성(MapTileBitmapRequestedEventArgsRequest(요청) 속성에 포함됨)에 사용자 지정 타일을 반환하세요. PixelData 속성은 IRandomAccessStreamReference 형식에 속합니다.

다음 예제에서는 BitmapRequested 이벤트에 대한 사용자 지정 처리기를 생성해서 사용자 지정 타일을 제공하는 방법을 보여줍니다. 이 예제에서는 부분적으로 불투명하면서 서로 동일한 빨간색 타일을 생성합니다. 이 예제에서는 MapTileBitmapRequestedEventArgsX 속성, Y 속성 및 ZoomLevel 속성을 무시합니다. 이 예제는 실제 예제가 아니지만, 신속하게 메모리 내 사용자 지정 타일을 생성하는 방법을 보여줍니다. 이 예제에서는 비동기 작업을 수행해야 하는 경우 사용자 지정 타일을 생성하기 위해 지연 패턴을 구현하는 방법도 보여줍니다.

using Windows.UI.Xaml.Controls.Maps;
using Windows.Storage.Streams;
using System.Threading.Tasks;
...
        CustomMapTileDataSource customDataSource = new CustomMapTileDataSource();
        // Attach a handler for the BitmapRequested event.
        customDataSource.BitmapRequested += customDataSource_BitmapRequestedAsync;
        customTileSource = new MapTileSource(customDataSource);
        MapControl1.TileSources.Add(customTileSource);
...
        // Handle the BitmapRequested event.
        private async void customDataSource_BitmapRequestedAsync(
            CustomMapTileDataSource sender,
            MapTileBitmapRequestedEventArgs args)
        {
            var deferral = args.Request.GetDeferral();
            args.Request.PixelData = await CreateBitmapAsStreamAsync();
            deferral.Complete();
        }

        // Create the custom tiles.
        // This example creates red tiles that are partially opaque.
        private async Task<RandomAccessStreamReference> CreateBitmapAsStreamAsync()
        {
            int pixelHeight = 256;
            int pixelWidth = 256;
            int bpp = 4;

            byte[] bytes = new byte[pixelHeight * pixelWidth * bpp];

            for (int y = 0; y < pixelHeight; y++)
            {
                for (int x = 0; x < pixelWidth; x++)
                {
                    int pixelIndex = y * pixelWidth + x;
                    int byteIndex = pixelIndex * bpp;

                    // Set the current pixel bytes.
                    bytes[byteIndex] = 0xff;        // Red
                    bytes[byteIndex + 1] = 0x00;    // Green
                    bytes[byteIndex + 2] = 0x00;    // Blue
                    bytes[byteIndex + 3] = 0x80;    // Alpha (0xff = fully opaque)
                }
            }

            // Create RandomAccessStream from byte array.
            InMemoryRandomAccessStream randomAccessStream =
                new InMemoryRandomAccessStream();
            IOutputStream outputStream = randomAccessStream.GetOutputStreamAt(0);
            DataWriter writer = new DataWriter(outputStream);
            writer.WriteBytes(bytes);
            await writer.StoreAsync();
            await writer.FlushAsync();
            return RandomAccessStreamReference.CreateFromStream(randomAccessStream);
        }
...
#include <winrt/Windows.Storage.Streams.h>
...
Windows::Foundation::IAsyncOperation<Windows::Storage::Streams::InMemoryRandomAccessStream> MainPage::CustomRandomAccessStream()
{
    constexpr int pixelHeight{ 256 };
    constexpr int pixelWidth{ 256 };
    constexpr int bpp{ 4 };

    std::array<uint8_t, pixelHeight * pixelWidth * bpp> bytes;

    for (int y = 0; y < pixelHeight; y++)
    {
        for (int x = 0; x < pixelWidth; x++)
        {
            int pixelIndex{ y * pixelWidth + x };
            int byteIndex{ pixelIndex * bpp };

            // Set the current pixel bytes.
            bytes[byteIndex] = (byte)(std::rand() % 256);        // Red
            bytes[byteIndex + 1] = (byte)(std::rand() % 256);    // Green
            bytes[byteIndex + 2] = (byte)(std::rand() % 256);    // Blue
            bytes[byteIndex + 3] = (byte)((std::rand() % 56) + 200);    // Alpha (0xff = fully opaque)
        }
    }

    // Create RandomAccessStream from byte array.
    Windows::Storage::Streams::InMemoryRandomAccessStream randomAccessStream;
    Windows::Storage::Streams::IOutputStream outputStream{ randomAccessStream.GetOutputStreamAt(0) };
    Windows::Storage::Streams::DataWriter writer{ outputStream };
    writer.WriteBytes(bytes);

    co_await writer.StoreAsync();
    co_await writer.FlushAsync();

    co_return randomAccessStream;
}
...
InMemoryRandomAccessStream^ TileSources::CustomRandomAccessStream::get()
{
    int pixelHeight = 256;
    int pixelWidth = 256;
    int bpp = 4;

    Array<byte>^ bytes = ref new Array<byte>(pixelHeight * pixelWidth * bpp);

    for (int y = 0; y < pixelHeight; y++)
    {
        for (int x = 0; x < pixelWidth; x++)
        {
            int pixelIndex = y * pixelWidth + x;
            int byteIndex = pixelIndex * bpp;

            // Set the current pixel bytes.
            bytes[byteIndex] = (byte)(std::rand() % 256);        // Red
            bytes[byteIndex + 1] = (byte)(std::rand() % 256);    // Green
            bytes[byteIndex + 2] = (byte)(std::rand() % 256);    // Blue
            bytes[byteIndex + 3] = (byte)((std::rand() % 56) + 200);    // Alpha (0xff = fully opaque)
        }
    }

    // Create RandomAccessStream from byte array.
    InMemoryRandomAccessStream^ randomAccessStream = ref new InMemoryRandomAccessStream();
    IOutputStream^ outputStream = randomAccessStream->GetOutputStreamAt(0);
    DataWriter^ writer = ref new DataWriter(outputStream);
    writer->WriteBytes(bytes);

    create_task(writer->StoreAsync()).then([writer](unsigned int)
    {
        create_task(writer->FlushAsync());
    });

    return randomAccessStream;
}

기본 맵 바꾸기

기본 맵을 타사 타일 또는 사용자 지정 타일로 완전히 바꾸려면 다음 방법대로 하세요.