Azure Maps では、球面メルカトル投影座標系 (EPSG:3857) が使用されます。 投影は、球面地球をフラット マップに変換するために使用される数学モデルです。 球面メルカトル図法では、マップが極に引き伸ばされ、正方形のマップが作成されます。 この投影は、マップの縮尺と面積を大幅に歪めますが、この歪みを上回る 2 つの重要なプロパティがあります。
- これはコンフォーマル 投影であり、比較的小さなオブジェクトの形状を保持することを意味します。 航空写真を表示する場合は、小さなオブジェクトの形状を維持することが特に重要です。 たとえば、建物の形状が歪むのを防ぐ必要があります。 四角い建物は長方形ではなく、正方形に見えるべきです。
- 円柱状の投影です。 北と南は常に上下で、西と東は常に左と右です。
マップの取得と表示のパフォーマンスを最適化するために、マップは正方形のタイルに分割されます。 Azure Maps SDK の使用タイルのサイズは、道路地図では 512 x 512 ピクセル、衛星画像では 256 x 256 ピクセル未満です。 Azure Maps には、0 から 22 までの 23 のズーム レベルに対応するラスター タイルとベクター タイルが用意されています。 ズーム レベル 0 では、世界全体が 1 つのタイルに収まります。
ズーム レベル 1 では、4 つのタイルを使用してワールドをレンダリングします。2 x 2 四角形
ズーム レベルを追加するたびに、前のタイルが 4 分割され、2 ズーム x 2ズーム のグリッドが作成されます。 ズーム レベル 22 は、グリッド 222 x 222、または 4,194,304 x 4,194,304 タイル (合計で 17,592,186,044,416 タイル) です。
Web 用の Azure Maps 対話型マップ コントロールでは、0 から 24 の番号が付いた 25 のズーム レベルがサポートされます。 ただし、道路データをズーム レベルで使用できるのは、タイルが使用可能な場合のみです。
次の表は、タイル サイズが 256 ピクセルの正方形であるズーム レベルの値の完全な一覧を示しています。
ズーム レベル | メートル/ピクセル | メートル/タイル一辺 |
---|---|---|
0 | 156543 | 40075017 |
1 | 78271.5 | 20037508 |
2 | 39135.8 | 10018754 |
3 | 19567.88 | 5009377.1 |
4 | 9783.94 | 2504688.5 |
5 | 4891.97 | 1252344.3 |
6 | 2445.98 | 626172.1 |
7 | 1222.99 | 313086.1 |
8 | 611.5 | 156543 |
9 | 305.75 | 78,271.5 |
10 | 152.87 | 39135.8 |
11 | 76.44 | 19,567.9 |
12 | 38.219 | 9783.94 |
13 | 19.109 | 4891.97 |
14 | 9.555 | 2445.98 |
15 | 4.777 | 1222.99 |
16 | 2.3887 | 611.496 |
十七 | 1.1943 | 305.748 |
18 | 0.5972 | 152.874 |
19 | 0.2986 | 76.437 |
20 | 0.14929 | 38.2185 |
21 (二十一) | 0.074646 | 19.10926 |
22 | 0.037323 | 9.55463 |
23 | 0.0186615 | 4.777315 |
二十四 | 0.00933075 | 2.3886575 |
ピクセル座標
各ズーム レベルで使用する投影とスケールを選択したら、地理座標をピクセル座標に変換できます。 特定のズーム レベルに対するワールドのマップ イメージの全ピクセル幅と高さは、次のように計算されます。
var mapWidth = tileSize * Math.pow(2, zoom);
var mapHeight = mapWidth;
マップの幅と高さはズーム レベルごとに異なるため、ピクセル座標も異なります。 マップの左上隅にあるピクセルには、常にピクセル座標 (0,0) があります。 マップの右下隅のピクセルにはピクセル座標 (幅 1、高さ-1) があります。または前のセクション の数式 (tileSize * 2zoom-1、tileSize * 2zoom-1) を参照します。 たとえば、レベル 2 で 512 平方タイルを使用する場合、ピクセル座標の範囲は (0, 0) から (2047, 2047) です。次のようになります。
緯度と経度を度単位で指定し、詳細レベルを指定すると、ピクセル XY 座標は次のように計算されます。
var sinLatitude = Math.sin(latitude * Math.PI/180);
var pixelX = ((longitude + 180) / 360) * tileSize * Math.pow(2, zoom);
var pixelY = (0.5 – Math.log((1 + sinLatitude) / (1 – sinLatitude)) / (4 * Math.PI)) * tileSize * Math.pow(2, zoom);
緯度と経度の値は WGS 84 データム上にあると見なされます。 Azure Maps では球面投影を使用しますが、すべての地理座標を共通のデータムに変換することが重要です。 WGS 84 は、選択したデータムです。 経度の値は、-180 度から +180 度の範囲であると見なされ、緯度の値を -85.05112878 から 85.05112878 までの範囲にクリップする必要があります。 これらの値に従うと、極での特異点が回避され、投影されたマップが 2 乗形状であることが保証されます。
タイル座標
マップの取得と表示のパフォーマンスを最適化するために、レンダリングされたマップをタイルに切り取ります。 ピクセルの数とタイルの数は、ズーム レベルごとに異なります。
var numberOfTilesWide = Math.pow(2, zoom);
var numberOfTilesHigh = numberOfTilesWide;
各タイルには、左上の (0, 0) から右下の (2ズーム - 1、2ズーム - 1) までの XY 座標が指定されます。 たとえば、ズーム レベル 3 では、タイル座標の範囲は (0, 0) ~ (7, 7) です。
ピクセル XY 座標のペアを指定すると、そのピクセルを含むタイルのタイル XY 座標を簡単に決定できます。
var tileX = Math.floor(pixelX / tileSize);
var tileY = Math.floor(pixelY / tileSize);
タイルはズーム レベルによって呼び出されます。 x 座標と y 座標は、そのズーム レベルのグリッド上のタイルの位置に対応します。
使用するズーム レベルを決定するときは、各場所がタイル上の固定位置にある点に注意してください。 その結果、地域の特定の広がりを表示するために必要なタイルの数は、世界地図上のズーム グリッドの特定の配置に依存します。 たとえば、900 メートル離れた 2 つのポイントがある場合、ズーム レベル 17 でそれらの間のルートを表示するのに 3 つのタイルしか必要と されないことがあります 。 ただし、西のポイントがタイルの右側にあり、タイルの左側の東のポイントにある場合は、次の 4 つのタイルが必要になることがあります。
ズーム レベルが決定されると、x と y の値を計算できます。 各ズーム グリッドの左上のタイルは x=0、y=0 です。右下のタイルは x=2zoom-1、y=2zoom-1 です。
ズーム レベル 1 のズーム グリッドを次に示します。
Quadkey インデックス
一部のマッピング プラットフォームでは、タイルの ZY 座標を、quadtree
キーまたはquadkeys
と呼ばれる 1 次元文字列に結合するquadkey
インデックス付け名前付け規則を使用します。 各 quadkey
は、特定の詳細レベルで 1 つのタイルを一意に識別し、一般的なデータベース B ツリー インデックスのキーとして使用できます。 Azure Maps SDK では、「タイル レイヤーの追加」ドキュメントに記載されている他の名前付け規則に加えて、 quadkey
名前付け規則を使用する タイル レイヤー のオーバーレイがサポートされています。
注
quadkeys
の名前付け規則は、1 つ以上のズーム レベルでのみ機能します。 Azure Maps SDK のサポート ズーム レベル 0 は、世界中の 1 つのマップ タイルです。
タイル座標を quadkey
に変換するには、Y 座標と X 座標のビットがインターリーブされ、結果は base-4 数値 (先頭に 0 が保持されます) として解釈され、文字列に変換されます。 たとえば、レベル 3 のタイル XY 座標 (3, 5) を指定すると、 quadkey
は次のように決定されます。
tileX = 3 = 011 (base 2)
tileY = 5 = 101 (base 2)
quadkey = 100111 (base 2) = 213 (base 4) = "213"
Qquadkeys
には、いくつかの興味深いプロパティがあります。 まず、 quadkey
の長さ (桁数) は、対応するタイルのズーム レベルと等しくなります。 次に、タイルの quadkey
は、親タイルの quadkey
(前のレベルのタイルを含む) で始まります。 次の例に示すように、タイル 2 はタイル 20 から 23 の親です。
最後に、 quadkeys
は、通常、XY 空間内のタイルの近接性を保持する 1 次元インデックス キーを提供します。 つまり、近くの XY 座標を持つ 2 つのタイルには、通常、比較的近い quadkeys
があります。 これはデータベースのパフォーマンスを最適化するために重要です。これは、隣接するタイルがグループで要求されることが多く、ディスク読み取りの数を最小限に抑えるために、それらのタイルを同じディスク ブロックに保持することが望ましいためです。
タイル演算のソース コード
次のサンプル コードは、このドキュメントで説明する関数を実装する方法を示しています。 これらの関数は、必要に応じて他のプログラミング言語に簡単に変換できます。
using System;
using System.Text;
namespace AzureMaps
{
/// <summary>
/// Tile System math for the Spherical Mercator projection coordinate system (EPSG:3857)
/// </summary>
public static class TileMath
{
//Earth radius in meters.
private const double EarthRadius = 6378137;
private const double MinLatitude = -85.05112878;
private const double MaxLatitude = 85.05112878;
private const double MinLongitude = -180;
private const double MaxLongitude = 180;
/// <summary>
/// Clips a number to the specified minimum and maximum values.
/// </summary>
/// <param name="n">The number to clip.</param>
/// <param name="minValue">Minimum allowable value.</param>
/// <param name="maxValue">Maximum allowable value.</param>
/// <returns>The clipped value.</returns>
private static double Clip(double n, double minValue, double maxValue)
{
return Math.Min(Math.Max(n, minValue), maxValue);
}
/// <summary>
/// Calculates width and height of the map in pixels at a specific zoom level from -180 degrees to 180 degrees.
/// </summary>
/// <param name="zoom">Zoom Level to calculate width at</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>Width and height of the map in pixels</returns>
public static double MapSize(double zoom, int tileSize)
{
return Math.Ceiling(tileSize * Math.Pow(2, zoom));
}
/// <summary>
/// Calculates the Ground resolution at a specific degree of latitude in meters per pixel.
/// </summary>
/// <param name="latitude">Degree of latitude to calculate resolution at</param>
/// <param name="zoom">Zoom level to calculate resolution at</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>Ground resolution in meters per pixels</returns>
public static double GroundResolution(double latitude, double zoom, int tileSize)
{
latitude = Clip(latitude, MinLatitude, MaxLatitude);
return Math.Cos(latitude * Math.PI / 180) * 2 * Math.PI * EarthRadius / MapSize(zoom, tileSize);
}
/// <summary>
/// Determines the map scale at a specified latitude, level of detail, and screen resolution.
/// </summary>
/// <param name="latitude">Latitude (in degrees) at which to measure the map scale.</param>
/// <param name="zoom">Level of detail, from 1 (lowest detail) to 23 (highest detail).</param>
/// <param name="screenDpi">Resolution of the screen, in dots per inch.</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>The map scale, expressed as the denominator N of the ratio 1 : N.</returns>
public static double MapScale(double latitude, double zoom, int screenDpi, int tileSize)
{
return GroundResolution(latitude, zoom, tileSize) * screenDpi / 0.0254;
}
/// <summary>
/// Global Converts a Pixel coordinate into a geospatial coordinate at a specified zoom level.
/// Global Pixel coordinates are relative to the top left corner of the map (90, -180)
/// </summary>
/// <param name="pixel">Pixel coordinates in the format of [x, y].</param>
/// <param name="zoom">Zoom level</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>A position value in the format [longitude, latitude].</returns>
public static double[] GlobalPixelToPosition(double[] pixel, double zoom, int tileSize)
{
var mapSize = MapSize(zoom, tileSize);
var x = (Clip(pixel[0], 0, mapSize - 1) / mapSize) - 0.5;
var y = 0.5 - (Clip(pixel[1], 0, mapSize - 1) / mapSize);
return new double[] {
360 * x, //Longitude
90 - 360 * Math.Atan(Math.Exp(-y * 2 * Math.PI)) / Math.PI //Latitude
};
}
/// <summary>
/// Converts a point from latitude/longitude WGS-84 coordinates (in degrees) into pixel XY coordinates at a specified level of detail.
/// </summary>
/// <param name="position">Position coordinate in the format [longitude, latitude]</param>
/// <param name="zoom">Zoom level.</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>A global pixel coordinate.</returns>
public static double[] PositionToGlobalPixel(double[] position, int zoom, int tileSize)
{
var latitude = Clip(position[1], MinLatitude, MaxLatitude);
var longitude = Clip(position[0], MinLongitude, MaxLongitude);
var x = (longitude + 180) / 360;
var sinLatitude = Math.Sin(latitude * Math.PI / 180);
var y = 0.5 - Math.Log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
var mapSize = MapSize(zoom, tileSize);
return new double[] {
Clip(x * mapSize + 0.5, 0, mapSize - 1),
Clip(y * mapSize + 0.5, 0, mapSize - 1)
};
}
/// <summary>
/// Converts pixel XY coordinates into tile XY coordinates of the tile containing the specified pixel.
/// </summary>
/// <param name="pixel">Pixel coordinates in the format of [x, y].</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <param name="tileX">Output parameter receiving the tile X coordinate.</param>
/// <param name="tileY">Output parameter receiving the tile Y coordinate.</param>
public static void GlobalPixelToTileXY(double[] pixel, int tileSize, out int tileX, out int tileY)
{
tileX = (int)(pixel[0] / tileSize);
tileY = (int)(pixel[1] / tileSize);
}
/// <summary>
/// Performs a scale transform on a global pixel value from one zoom level to another.
/// </summary>
/// <param name="pixel">Pixel coordinates in the format of [x, y].</param>
/// <param name="oldZoom">The zoom level in which the input global pixel value is from.</param>
/// <returns>A scale pixel coordinate.</returns>
public static double[] ScaleGlobalPixel(double[] pixel, double oldZoom, double newZoom)
{
var scale = Math.Pow(2, oldZoom - newZoom);
return new double[] { pixel[0] * scale, pixel[1] * scale };
}
/// <summary>
/// Performs a scale transform on a set of global pixel values from one zoom level to another.
/// </summary>
/// <param name="pixels">A set of global pixel value from the old zoom level. Points are in the format [x,y].</param>
/// <param name="oldZoom">The zoom level in which the input global pixel values is from.</param>
/// <param name="newZoom">The new zoom level in which the output global pixel values should be aligned with.</param>
/// <returns>A set of global pixel values that has been scaled for the new zoom level.</returns>
public static double[][] ScaleGlobalPixels(double[][] pixels, double oldZoom, double newZoom)
{
var scale = Math.Pow(2, oldZoom - newZoom);
var output = new System.Collections.Generic.List<double[]>();
foreach (var p in pixels)
{
output.Add(new double[] { p[0] * scale, p[1] * scale });
}
return output.ToArray();
}
/// <summary>
/// Converts tile XY coordinates into a global pixel XY coordinates of the upper-left pixel of the specified tile.
/// </summary>
/// <param name="tileX">Tile X coordinate.</param>
/// <param name="tileY">Tile Y coordinate.</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <param name="pixelX">Output parameter receiving the X coordinate of the point, in pixels.</param>
/// <param name="pixelY">Output parameter receiving the Y coordinate of the point, in pixels.</param>
public static double[] TileXYToGlobalPixel(int tileX, int tileY, int tileSize)
{
return new double[] { tileX * tileSize, tileY * tileSize };
}
/// <summary>
/// Converts tile XY coordinates into a quadkey at a specified level of detail.
/// </summary>
/// <param name="tileX">Tile X coordinate.</param>
/// <param name="tileY">Tile Y coordinate.</param>
/// <param name="zoom">Zoom level</param>
/// <returns>A string containing the quadkey.</returns>
public static string TileXYToQuadKey(int tileX, int tileY, int zoom)
{
var quadKey = new StringBuilder();
for (int i = zoom; i > 0; i--)
{
char digit = '0';
int mask = 1 << (i - 1);
if ((tileX & mask) != 0)
{
digit++;
}
if ((tileY & mask) != 0)
{
digit++;
digit++;
}
quadKey.Append(digit);
}
return quadKey.ToString();
}
/// <summary>
/// Converts a quadkey into tile XY coordinates.
/// </summary>
/// <param name="quadKey">Quadkey of the tile.</param>
/// <param name="tileX">Output parameter receiving the tile X coordinate.</param>
/// <param name="tileY">Output parameter receiving the tile Y coordinate.</param>
/// <param name="zoom">Output parameter receiving the zoom level.</param>
public static void QuadKeyToTileXY(string quadKey, out int tileX, out int tileY, out int zoom)
{
tileX = tileY = 0;
zoom = quadKey.Length;
for (int i = zoom; i > 0; i--)
{
int mask = 1 << (i - 1);
switch (quadKey[zoom - i])
{
case '0':
break;
case '1':
tileX |= mask;
break;
case '2':
tileY |= mask;
break;
case '3':
tileX |= mask;
tileY |= mask;
break;
default:
throw new ArgumentException("Invalid QuadKey digit sequence.");
}
}
}
/// <summary>
/// Calculates the XY tile coordinates that a coordinate falls into for a specific zoom level.
/// </summary>
/// <param name="position">Position coordinate in the format [longitude, latitude]</param>
/// <param name="zoom">Zoom level</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <param name="tileX">Output parameter receiving the tile X position.</param>
/// <param name="tileY">Output parameter receiving the tile Y position.</param>
public static void PositionToTileXY(double[] position, int zoom, int tileSize, out int tileX, out int tileY)
{
var latitude = Clip(position[1], MinLatitude, MaxLatitude);
var longitude = Clip(position[0], MinLongitude, MaxLongitude);
var x = (longitude + 180) / 360;
var sinLatitude = Math.Sin(latitude * Math.PI / 180);
var y = 0.5 - Math.Log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI);
//tileSize needed in calculations as in rare cases the multiplying/rounding/dividing can make the difference of a pixel which can result in a completely different tile.
var mapSize = MapSize(zoom, tileSize);
tileX = (int)Math.Floor(Clip(x * mapSize + 0.5, 0, mapSize - 1) / tileSize);
tileY = (int)Math.Floor(Clip(y * mapSize + 0.5, 0, mapSize - 1) / tileSize);
}
/// <summary>
/// Calculates the tile quadkey strings that are within a specified viewport.
/// </summary>
/// <param name="position">Position coordinate in the format [longitude, latitude]</param>
/// <param name="zoom">Zoom level</param>
/// <param name="width">The width of the map viewport in pixels.</param>
/// <param name="height">The height of the map viewport in pixels.</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>A list of quadkey strings that are within the specified viewport.</returns>
public static string[] GetQuadkeysInView(double[] position, int zoom, int width, int height, int tileSize)
{
var p = PositionToGlobalPixel(position, zoom, tileSize);
var top = p[1] - height * 0.5;
var left = p[0] - width * 0.5;
var bottom = p[1] + height * 0.5;
var right = p[0] + width * 0.5;
var tl = GlobalPixelToPosition(new double[] { left, top }, zoom, tileSize);
var br = GlobalPixelToPosition(new double[] { right, bottom }, zoom, tileSize);
//Boudning box in the format: [west, south, east, north];
var bounds = new double[] { tl[0], br[1], br[0], tl[1] };
return GetQuadkeysInBoundingBox(bounds, zoom, tileSize);
}
/// <summary>
/// Calculates the tile quadkey strings that are within a bounding box at a specific zoom level.
/// </summary>
/// <param name="bounds">A bounding box defined as an array of numbers in the format of [west, south, east, north].</param>
/// <param name="zoom">Zoom level to calculate tiles for.</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>A list of quadkey strings.</returns>
public static string[] GetQuadkeysInBoundingBox(double[] bounds, int zoom, int tileSize)
{
var keys = new System.Collections.Generic.List<string>();
if (bounds != null && bounds.Length >= 4)
{
PositionToTileXY(new double[] { bounds[3], bounds[0] }, zoom, tileSize, out int tlX, out int tlY);
PositionToTileXY(new double[] { bounds[1], bounds[2] }, zoom, tileSize, out int brX, out int brY);
for (int x = tlX; x <= brX; x++)
{
for (int y = tlY; y <= brY; y++)
{
keys.Add(TileXYToQuadKey(x, y, zoom));
}
}
}
return keys.ToArray();
}
/// <summary>
/// Calculates the bounding box of a tile.
/// </summary>
/// <param name="tileX">Tile X coordinate</param>
/// <param name="tileY">Tile Y coordinate</param>
/// <param name="zoom">Zoom level</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid.</param>
/// <returns>A bounding box of the tile defined as an array of numbers in the format of [west, south, east, north].</returns>
public static double[] TileXYToBoundingBox(int tileX, int tileY, double zoom, int tileSize)
{
//Top left corner pixel coordinates
var x1 = (double)(tileX * tileSize);
var y1 = (double)(tileY * tileSize);
//Bottom right corner pixel coordinates
var x2 = (double)(x1 + tileSize);
var y2 = (double)(y1 + tileSize);
var nw = GlobalPixelToPosition(new double[] { x1, y1 }, zoom, tileSize);
var se = GlobalPixelToPosition(new double[] { x2, y2 }, zoom, tileSize);
return new double[] { nw[0], se[1], se[0], nw[1] };
}
/// <summary>
/// Calculates the best map view (center, zoom) for a bounding box on a map.
/// </summary>
/// <param name="bounds">A bounding box defined as an array of numbers in the format of [west, south, east, north].</param>
/// <param name="mapWidth">Map width in pixels.</param>
/// <param name="mapHeight">Map height in pixels.</param>
/// <param name="latitude">Output parameter receiving the center latitude coordinate.</param>
/// <param name="longitude">Output parameter receiving the center longitude coordinate.</param>
/// <param name="zoom">Output parameter receiving the zoom level</param>
/// <param name="padding">Width in pixels to use to create a buffer around the map. This is to keep markers from being cut off on the edge. Default: 0</param>
/// <param name="tileSize">The size of the tiles in the tile pyramid. Default: 512</param>
/// <param name="maxZoom">Optional maximum zoom level to return. Useful when the bounding box represents a very small area. Default: 24</param>
/// <param name="allowFloatZoom">Specifies if the returned zoom level should be a float or rounded down to an whole integer zoom level. Default: true</param>
public static void BestMapView(BoundingBox bounds, double mapWidth, double mapHeight, out double centerLat, out double centerLon, out double zoom, int padding = 0, int tileSize = 512, double maxZoom = 24, bool allowFloatZoom = true)
{
centerLat = 0;
centerLon = 0;
zoom = 0;
if (bounds != null && mapWidth > 0 && mapHeight > 0)
{
//Ensure padding is valid.
padding = Math.Abs(padding);
//Ensure max zoom is within valid range.
maxZoom = Clip(maxZoom, 0, 24);
//Do pixel calculations at zoom level 24 as that will provide a high level of visual accuracy.
int pixelZoom = 24;
//Calculate mercator pixel coordinate at zoom level 24.
var wnPixel = PositionToGlobalPixel(new double[] { bounds[0], bounds[3] }, pixelZoom, tileSize);
var esPixel = PositionToGlobalPixel(new double[] { bounds[2], bounds[1] }, pixelZoom, tileSize);
//Calculate the pixel distance between pixels for each axis.
double dx = esPixel[0] - wnPixel[0];
double dy = esPixel[1] - wnPixel[1];
//Calculate the average pixel positions to get the visual center.
double xAvg = (esPixel[0] + wnPixel[0]) / 2;
double yAvg = (esPixel[1] + wnPixel[1]) / 2;
//Determine if the bounding box crosses the antimeridian. (West pixel will be greater than East pixel).
if (wnPixel[0] > esPixel[0])
{
double mapSize = MapSize(24, tileSize);
//We are interested in the opposite area of the map. Calculate the opposite area and visual center.
dx = mapSize - Math.Abs(dx);
//Offset the visual center by half the global map width at zoom 24 on the x axis.
xAvg += mapSize / 2;
}
//Convert visual center pixel from zoom 24 to lngLat.
center = GlobalPixelToPosition(new Pixel(xAvg, yAvg), pixelZoom, tileSize);
//Calculate scale of screen pixels per unit on the Web Mercator plane.
double scaleX = (mapWidth - padding * 2) / Math.Abs(dx) * Math.Pow(2, pixelZoom);
double scaleY = (mapHeight - padding * 2) / Math.Abs(dy) * Math.Pow(2, pixelZoom);
//Calculate zoom levels based on the x/y scales. Choose the most zoomed out value.
zoom = Math.Max(0, Math.Min(maxZoom, Math.Log2(Math.Abs(Math.Min(scaleX, scaleY)))));
//Round down zoom level if float values are not desired.
if (!allowFloatZoom)
{
zoom = Math.Floor(zoom);
}
}
return new CameraOptions
{
Center = center,
Zoom = zoom
};
}
}
}
注
Azure Maps SDK の対話型マップ コントロールには、地理空間の位置とビューポートピクセルの間で変換するためのヘルパー関数があります。
次のステップ
Azure Maps REST サービスからマップ タイルに直接アクセスします。
地理空間の概念の詳細については、以下をご覧ください。