Sobrepor imagens lado a lado em um mapa

Importante

Desativação do serviço Bing Maps para empresas

O UWP MapControl e os serviços de mapa do namespace Windows.Services.Maps dependem do Bing Maps. O Bing Maps for Enterprise foi preterido e será desativado, momento em que o MapControl e os serviços não receberão mais dados.

Para obter mais informações, consulte a documentação da Central de Desenvolvedores do Bing Maps e do Bing Maps.

Observação

O MapControl e os serviços de mapa exigem uma chave de autenticação de mapas chamada MapServiceToken. Para saber mais sobre como obter e definir uma chave de autenticação de mapas, consulte Solicitar uma chave de autenticação de mapas.

Sobreponha imagens em blocos de terceiros ou personalizados em um mapa usando fontes de blocos. Use fontes de blocos para sobrepor informações especializadas, como dados de previsão do tempo, dados de população ou dados sísmicos; ou use fontes de blocos para substituir por completo o mapa padrão.

Visão geral da imagem lado a lado

Serviços de mapas como o Bing Maps cortam mapas em blocos quadrados para recuperação e exibição rápidas. Esses blocos têm 256 pixels por 256 pixels de tamanho e são pré-renderizados em vários níveis de detalhe. Muitos serviços de terceiros também fornecem dados baseados em mapas que são cortados em blocos. Use fontes de bloco para recuperar blocos de terceiros ou para criar seus próprios blocos personalizados e sobrepô-los no mapa exibido no MapControl.

Ao usar fontes de bloco, você não precisa escrever código para solicitar ou posicionar blocos individuais. O MapControl solicita blocos conforme necessário. Cada solicitação especifica as coordenadas X e Y e o nível de zoom para o bloco individual. Basta especificar o formato do Uri ou nome de arquivo a ser usado para recuperar os blocos na propriedade UriFormatString . Ou seja, você insere parâmetros substituíveis no URI base ou no nome do arquivo para indicar onde passar as coordenadas X e Y e o nível de zoom para cada bloco.

Aqui está um exemplo da propriedade UriFormatString para um HttpMapTileDataSource que mostra os parâmetros substituíveis para as coordenadas X e Y e o nível de zoom.

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

(As coordenadas X e Y representam a localização do bloco individual no mapa do mundo no nível de detalhe especificado. O sistema de numeração de blocos começa em {0, 0} no canto superior esquerdo do mapa. Por exemplo, o bloco em {1, 2} está na segunda coluna da terceira linha da grade de blocos.)

Para obter mais informações sobre o sistema de blocos usado pelos serviços de mapeamento, consulte Sistema de Blocos do Bing Maps.

Sobrepor blocos de uma origem de bloco

Sobreponha imagens lado a lado de uma fonte de bloco em um mapa usando o MapTileDataSource.

  1. Instancie uma das três classes de fonte de dados de bloco que herdam de MapTileDataSource.

    Configure o UriFormatString a ser usado para solicitar os blocos inserindo parâmetros substituíveis no URI base ou no nome do arquivo.

    O exemplo a seguir instancia um HttpMapTileDataSource. Este exemplo especifica o valor do UriFormatString no construtor do HttpMapTileDataSource.

        HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
          "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
    
  2. Instancie e configure um MapTileSource. Especifique o MapTileDataSource que você configurou na etapa anterior como o DataSource do MapTileSource.

    O exemplo a seguir especifica o DataSource no construtor do MapTileSource.

        MapTileSource tileSource = new MapTileSource(dataSource);
    

    Você pode restringir as condições nas quais os blocos são exibidos usando as propriedades do MapTileSource.

    • Exiba blocos somente dentro de uma área geográfica específica, fornecendo um valor para a propriedade Bounds .
    • Exiba blocos somente em determinados níveis de detalhe, fornecendo um valor para a propriedade ZoomLevelRange.

    Opcionalmente, configure outras propriedades do MapTileSource que afetam o carregamento ou a exibição dos blocos, como Layer, AllowOverstretch, IsRetryEnabled e IsTransparencyEnabled.

  3. Adicione o MapTileSource à coleção TileSources do MapControl.

         MapControl1.TileSources.Add(tileSource);
    

Sobrepor blocos de um serviço Web

Sobreponha imagens lado a lado recuperadas de um serviço Web usando o HttpMapTileDataSource.

  1. Instancie um HttpMapTileDataSource.

  2. Especifique o formato do Uri que o serviço Web espera como o valor da propriedade UriFormatString. Para criar esse valor, insira parâmetros substituíveis no Uri base. Por exemplo, no exemplo de código a seguir, o valor de UriFormatString é:

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

    O serviço Web precisa dar suporte a um Uri que contém os parâmetros substituíveis {x}, {y} e {zoomlevel}. A maioria dos serviços da web (por exemplo, Nokia, Bing e Google) suporta Uris neste formato. Se o serviço Web exigir argumentos adicionais que não estão disponíveis com a propriedade UriFormatString , você precisará criar um Uri personalizado. Crie e retorne um Uri personalizado manipulando o evento UriRequested. Para obter mais informações, consulte a seção Fornecer um URI personalizado mais adiante neste tópico.

  3. Em seguida, siga as etapas restantes descritas anteriormente na visão geral da imagem lado a lado.

O exemplo a seguir sobrepõe blocos de um serviço Web fictício em um mapa da América do Norte. O valor do UriFormatString é especificado no construtor do HttpMapTileDataSource. Neste exemplo, os blocos são exibidos apenas dentro dos limites geográficos especificados pela propriedade opcional Bounds.

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);
}

Sobrepor blocos do armazenamento local

Sobreponha imagens lado a lado armazenadas como arquivos no armazenamento local usando o LocalMapTileDataSource. Normalmente, você empacota e distribui esses arquivos com seu aplicativo.

  1. Instancie um LocalMapTileDataSource.

  2. Especifique o formato dos nomes de arquivo como o valor da propriedade UriFormatString. Para criar esse valor, insira parâmetros substituíveis no nome do arquivo base. Por exemplo, no exemplo de código a seguir, o valor de UriFormatString é:

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

    Se o formato dos nomes de arquivo exigir argumentos adicionais que não estão disponíveis com a propriedade UriFormatString , você precisará criar um Uri personalizado. Crie e retorne um Uri personalizado manipulando o evento UriRequested. Para obter mais informações, consulte a seção Fornecer um URI personalizado mais adiante neste tópico.

  3. Em seguida, siga as etapas restantes descritas anteriormente na visão geral da imagem lado a lado.

Você pode usar os seguintes protocolos e locais para carregar blocos do armazenamento local:

Uri Mais informações
ms-appx:/// Aponta para a raiz da pasta de instalação do aplicativo.
Esse é o local referenciado pela propriedade Package.InstalledLocation .
ms-appdata:///local Aponta para a raiz do armazenamento local do aplicativo.
Esse é o local referenciado pela propriedade ApplicationData.LocalFolder .
ms-appdata:///temp Aponta para a pasta temporária do aplicativo.
Esse é o local referenciado pela propriedade ApplicationData.TemporaryFolder .

O exemplo a seguir carrega blocos armazenados como arquivos na pasta de instalação do aplicativo usando o ms-appx:/// protocolo. O valor do UriFormatString é especificado no construtor do LocalMapTileDataSource. Neste exemplo, os blocos só são exibidos quando o nível de zoom do mapa está dentro do intervalo especificado pela propriedade opcional 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);
}

Forneça um URI personalizado

Se os parâmetros substituíveis disponíveis com a propriedade UriFormatString do HttpMapTileDataSource ou a propriedade UriFormatString do LocalMapTileDataSource não forem suficientes para recuperar seus blocos, você precisará criar um Uri personalizado. Crie e retorne um Uri personalizado fornecendo um manipulador personalizado para o evento UriRequested . O evento UriRequested é gerado para cada bloco individual.

  1. No manipulador personalizado do evento UriRequested, combine os argumentos personalizados necessários com as propriedades X, Y e ZoomLevel do MapTileUriRequestedEventArgs para criar o Uri personalizado.
  2. Retorne o Uri personalizado na propriedade Uri do MapTileUriRequest, que está contido na propriedade Request do MapTileUriRequestedEventArgs.

O exemplo a seguir mostra como fornecer um Uri personalizado criando um manipulador personalizado para o evento UriRequested . Ele também mostra como implementar o padrão de adiamento se você precisar fazer algo de forma assíncrona para criar o URI personalizado.

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.        }
        }

Sobrepor blocos de uma fonte personalizada

Sobreponha blocos personalizados usando o CustomMapTileDataSource. Crie blocos programaticamente na memória em tempo real ou escreva seu próprio código para carregar blocos existentes de outra fonte.

Para criar ou carregar blocos personalizados, forneça um manipulador personalizado para o evento BitmapRequested. O evento BitmapRequested é gerado para cada bloco individual.

  1. No manipulador personalizado do evento BitmapRequested, combine os argumentos personalizados necessários com as propriedades X, Y e ZoomLevel do MapTileBitmapRequestedEventArgs para criar ou recuperar um bloco personalizado.
  2. Retorne o bloco personalizado na propriedade PixelData do MapTileBitmapRequest, que está contido na propriedade Request do MapTileBitmapRequestedEventArgs. A propriedade PixelData é do tipo IRandomAccessStreamReference.

O exemplo a seguir mostra como fornecer blocos personalizados criando um manipulador personalizado para o evento BitmapRequested . Este exemplo cria blocos vermelhos idênticos que são parcialmente opacos. O exemplo ignora as propriedades X, Y e ZoomLevel do MapTileBitmapRequestedEventArgs. Embora este não seja um exemplo do mundo real, o exemplo demonstra como você pode criar blocos personalizados na memória em tempo real. O exemplo também mostra como implementar o padrão de adiamento se você precisar fazer algo de forma assíncrona para criar os blocos personalizados.

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;
}

Substituir o mapa padrão

Para substituir o mapa padrão inteiramente por blocos personalizados ou de terceiros: