Поделиться через


Наложение мозаичных изображений на карту

Внимание

Bing Maps для выхода на пенсию службы Enterprise

Службы MapControl UWP и карты из пространства имен Windows.Services.Maps используют карты Bing. Карты Bing для предприятия устарели и будут прекращены, в то время как mapControl и службы больше не будут получать данные.

Дополнительные сведения см. в документации по Центру разработчиков карт Bing и картам Bing.

Примечание.

Для служб MapControl и служб карт требуется ключ проверки подлинности карт с именем MapServiceToken. Дополнительные сведения о получении и настройке ключа проверки подлинности карт см. в разделе "Запрос ключа проверки подлинности карт".

Выполняйте наложение сторонних или настраиваемых мозаичных изображений на карту с помощью источников таких изображений. Используйте источники мозаичных изображений для наложения специальных сведений, таких как данные о погоде, населении или сейсмической активности, а также для полной замены карты по умолчанию.

Обзор изображения с плитками

Службы карт, такие как Карты Bing, вырезают карты на квадратные плитки для быстрого извлечения и отображения. Эти плитки размером 256 пикселей на 256 пикселей и предварительно отрисовываются на нескольких уровнях детализации. Многие сторонние службы также предоставляют данные на основе карты, которые вырезаются на плитки. Используйте источники плиток, чтобы получить сторонние плитки или создать собственные пользовательские плитки, а также наложить их на карту, отображаемую в MapControl.

При использовании источников плиток вам не нужно писать код для запроса или размещения отдельных плиток. MapControl запрашивает плитки по мере их необходимости. Каждый запрос задает координаты X и Y и уровень масштабирования для отдельной плитки. Просто укажите формат URI или имени файла для получения плиток в свойстве UriFormatString . То есть вы вставляете заменяемые параметры в базовый URI или имя файла, чтобы указать, где передавать координаты X и Y и уровень масштабирования для каждой плитки.

Ниже приведен пример свойства UriFormatString для httpMapTileDataSource, который показывает заменяемые параметры для координат X и Y и уровня масштабирования.

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

(Координаты X и Y представляют расположение отдельной плитки на карте мира на указанном уровне детализации. Система нумерирования плиток начинается с {0, 0} в левом верхнем углу карты. Например, плитка {1, 2} находится во втором столбце третьей строки сетки плиток.)

Дополнительные сведения о системе плиток, используемой службами сопоставления, см. в статье Bing Maps Tile System.

Наложение плиток из источника плитки

Наложить наложенные изображения из источника плитки на карте с помощью MapTileDataSource.

  1. Создайте экземпляр одного из трех классов источников данных плиток, наследуемых от MapTileDataSource.

    Настройте UriFormatString для запроса плиток, вставив заменяемые параметры в базовый URI или имя файла.

    В следующем примере создается экземпляр httpMapTileDataSource. В этом примере указывается значение UriFormatString в конструкторе httpMapTileDataSource.

        HttpMapTileDataSource dataSource = new HttpMapTileDataSource(
          "http://www.<web service name>.com/z={zoomlevel}&x={x}&y={y}");
    
  2. Создайте экземпляр и настройте MapTileSource. Укажите MapTileDataSource, настроенный на предыдущем шаге в качестве источника данных MapTileSource.

    В следующем примере указан источник данных в конструкторе MapTileSource.

        MapTileSource tileSource = new MapTileSource(dataSource);
    

    Можно ограничить условия отображения плиток с помощью свойств MapTileSource.

    • Отображение плиток только в пределах определенной географической области путем предоставления значения для свойства Bounds .
    • Отображение плиток только на определенных уровнях детализации путем указания значения свойства ZoomLevelRange .

    При необходимости настройте другие свойства MapTileSource, влияющие на загрузку или отображение плиток, например Layer, AllowOverstretch, IsRetryEnabled и IsTransparencyEnabled.

  3. Добавьте MapTileSource в коллекцию TileSources mapControl.

         MapControl1.TileSources.Add(tileSource);
    

Наложение плиток из веб-службы

Наложить наложенные изображения, полученные из веб-службы, с помощью HttpMapTileDataSource.

  1. Создайте экземпляр httpMapTileDataSource.

  2. Укажите формат URI, который веб-служба ожидает в качестве значения свойства UriFormatString. Чтобы создать это значение, вставьте заменяемые параметры в базовый URI. Например, в следующем примере кода значение UriFormatString :

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

    Веб-служба должна поддерживать URI, содержащий заменяемые параметры {x}, {y}и {zoomlevel}. Большинство веб-служб (например, Nokia, Bing и Google) поддерживают Uris в этом формате. Если веб-служба требует дополнительных аргументов, которые недоступны для свойства UriFormatString , необходимо создать uri. Создайте и верните пользовательский URI, обрабатывая событие UriRequested . Дополнительные сведения см . в разделе "Предоставление пользовательского URI " далее в этом разделе.

  3. Затем выполните оставшиеся шаги, описанные ранее в обзоре изображения с плитками.

В следующем примере наложены плитки из вымышленной веб-службы на карте Северная Америка. Значение UriFormatString указывается в конструкторе httpMapTileDataSource. В этом примере плитки отображаются только в географических границах, указанных необязательным свойством 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);
}

Наложение плиток из локального хранилища

Наложить наложенные изображения, хранящиеся в виде файлов в локальном хранилище, с помощью LocalMapTileDataSource. Как правило, вы упаковывайте и распределяете эти файлы с приложением.

  1. Создайте экземпляр LocalMapTileDataSource.

  2. Укажите формат имен файлов в качестве значения свойства UriFormatString. Чтобы создать это значение, вставьте заменяемые параметры в базовое имя файла. Например, в следующем примере кода значение UriFormatString:

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

    Если формат имен файлов требует дополнительных аргументов, которые недоступны для свойства UriFormatString , необходимо создать uri. Создайте и верните пользовательский URI, обрабатывая событие UriRequested . Дополнительные сведения см . в разделе "Предоставление пользовательского 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

Если заменяемые параметры, доступные свойству UriFormatString httpMapTileDataSource или свойству UriFormatString localMapTileDataSource, недостаточно для извлечения плиток, необходимо создать URI. Создайте и верните uri, предоставив пользовательский обработчик для события UriRequested . Событие UriRequested создается для каждой отдельной плитки.

  1. В пользовательском обработчике события UriRequested объедините необходимые настраиваемые аргументы со свойствами X, Y и ZoomLevel объекта MapTileUriRequestedEventArgs для создания пользовательского URI.
  2. Возвращает пользовательский URI в свойстве Uri mapTileUriRequest, который содержится в свойстве Request объекта MapTileUriRequestedEventArgs.

В следующем примере показано, как предоставить uri, создав настраиваемый обработчик для события UriRequested . В нем также показано, как реализовать шаблон отсрочки, если необходимо сделать что-то асинхронно для создания пользовательского 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 необходимо объединить необходимые настраиваемые аргументы со свойствами X, Y и ZoomLevel mapTileBitmapRequestedEventArgs для создания или получения пользовательской плитки.
  2. Возвращает пользовательскую плитку в свойстве PixelData объекта MapTileBitmapRequest, который содержится в свойстве Request mapTileBitmapRequestedEventArgs. Свойство PixelData имеет тип IRandomAccessStreamReference.

В следующем примере показано, как предоставить пользовательские плитки, создав настраиваемый обработчик для события BitmapRequested . В этом примере создаются идентичные красные плитки, частично непрозрачные. В примере игнорируются свойства X, Y и ZoomLevel mapTileBitmapRequestedEventArgs. Хотя это не реальный пример, в примере показано, как можно создавать пользовательские плитки в памяти на лету. В примере также показано, как реализовать шаблон отсрочки, если необходимо сделать что-то асинхронно для создания пользовательских плиток.

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

Замена карты по умолчанию

Чтобы заменить карту по умолчанию полностью сторонними или настраиваемыми плитками, выполните следующие действия.