Partager via


Niveaux de zoom et grille mosaïque

Azure Maps utilise le système de coordonnées de projection de Mercator sphérique (EPSG :3857). Une projection est le modèle mathématique utilisé pour transformer le globe sphérique en une carte plate. La projection sphérique de Mercator étire la carte au niveau des pôles pour créer une carte carrée. Cette projection déforme considérablement l’échelle et la surface de la carte, mais présente deux propriétés importantes qui l’emportent sur cette distorsion :

  • Il s’agit d’une projection conforme, ce qui signifie qu’elle préserve la forme d’objets relativement petits. Il est particulièrement important de préserver la forme des petits objets lors de la présentation d’images aériennes. Par exemple, nous voulons éviter de déformer la forme des bâtiments. Les bâtiments carrés doivent apparaître carrés et non rectangulaires.
  • C’est une projection cylindrique. Le nord et le sud sont toujours en haut et en bas, et l’ouest et l’est sont toujours à gauche et à droite.

Pour optimiser les performances de récupération et d’affichage de la carte, la carte est divisée en tuiles carrées. Les SDK Azure Maps utilisent des tuiles d’une taille de 512 x 512 pixels pour les cartes routières et de 256 x 256 pixels pour l’imagerie satellite. Azure Maps fournit des tuiles raster et vectorielles pour 23 niveaux de zoom, numérotés de 0 à 22. Au niveau de zoom 0, le monde entier tient sur une seule tuile :

Tuile de la carte du monde

Le niveau de zoom 1 utilise quatre tuiles pour rendre le monde : un carré de 2 x 2

Disposition des tuiles de carte 2x2

Chaque niveau de zoom supplémentaire divise les tuiles du précédent, créant une grille de 2zoom x 2zoom. Le niveau de zoom 22 est une grille 222 x 222, ou 4 194 304 x 4 194 304 tuiles (17 592 186 044 416 tuiles au total).

Les contrôles de carte interactive Azure Maps pour le web prennent en charge 25 niveaux de zoom, numérotés de 0 à 24. Bien que les données routières ne soient disponibles qu’aux niveaux de zoom lorsque les tuiles sont disponibles.

Le tableau suivant fournit la liste complète des valeurs pour les niveaux de zoom où la taille de la tuile est de 256 pixels carrés :

Niveau de zoom Mètres/pixel Compteurs/côté tuile
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 78271.5
10 152.87 39135.8
11 76.44 19567.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
17 1.1943 305.748
18 0.5972 152.874
19 0.2986 76.437
20 0.14929 38.2185
Vingt-et-un 0.074646 19.10926
22 0.037323 9.55463
23 0.0186615 4.777315
Vingt-quatre 0.00933075 2.3886575

Coordonnées en pixels

Après avoir choisi la projection et l’échelle à utiliser à chaque niveau de zoom, nous pouvons convertir les coordonnées géographiques en coordonnées de pixels. La largeur et la hauteur totales d’une image cartographique du monde pour un niveau de zoom particulier sont calculées comme suit :

var mapWidth = tileSize * Math.pow(2, zoom);

var mapHeight = mapWidth;

Étant donné que la largeur et la hauteur de la carte sont différentes à chaque niveau de zoom, les coordonnées des pixels le sont également. Le pixel situé dans le coin supérieur gauche de la carte a toujours des coordonnées de pixel (0, 0). Le pixel situé dans le coin inférieur droit de la carte a des coordonnées de pixel (largeur-1, hauteur-1), ou se référant aux équations de la section précédente, (tileSize * 2zoom–1, tileSize * 2zoom–1). Par exemple, lorsque vous utilisez des tuiles carrées de 512 au niveau 2, les coordonnées des pixels sont comprises entre (0, 0) et (2047, 2047), comme suit :

Carte montrant les dimensions des pixels

Étant donné la latitude et la longitude en degrés, et le niveau de détail, les coordonnées XY du pixel sont calculées comme suit :

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

Les valeurs de latitude et de longitude sont supposées être basées sur le système de référence WGS 84. Même si Azure Maps utilise une projection sphérique, il est important de convertir toutes les coordonnées géographiques en une référence commune. WGS 84 est la référence sélectionnée. La valeur de longitude est supposée être comprise entre -180 degrés et +180 degrés, et la valeur de latitude doit être écrêtée pour être comprise entre -85,05112878 et 85,05112878. Le respect de ces valeurs permet d’éviter une singularité au niveau des pôles et de garantir que la carte projetée est de forme carrée.

Coordonnées de la tuile

Pour optimiser les performances de récupération et d’affichage de la carte, la carte rendue est découpée en tuiles. Le nombre de pixels et le nombre de tuiles diffèrent à chaque niveau de zoom :

var numberOfTilesWide = Math.pow(2, zoom);

var numberOfTilesHigh = numberOfTilesWide;

Chaque tuile reçoit des coordonnées XY allant de (0, 0) en haut à gauche à (2zoom-1, 2zoom-1) en bas à droite. Par exemple, au niveau de zoom 3, les coordonnées de la vignette sont comprises entre (0, 0) et (7, 7) comme suit :

Carte des coordonnées des tuiles

Étant donné une paire de coordonnées XY de pixels, vous pouvez facilement déterminer les coordonnées XY de la tuile contenant ce pixel :

var tileX = Math.floor(pixelX / tileSize);

var tileY = Math.floor(pixelY / tileSize);

Les tuiles sont appelées par niveau de zoom. Les coordonnées x et y correspondent à la position de la tuile sur la grille pour ce niveau de zoom.

Lorsque vous déterminez le niveau de zoom à utiliser, n’oubliez pas que chaque emplacement se trouve dans une position fixe sur sa tuile. Par conséquent, le nombre de tuiles nécessaires pour afficher une étendue de territoire donnée dépend de l’emplacement spécifique de la grille de zoom sur la carte du monde. Par exemple, s’il y a deux points distants de 900 mètres, il suffit de trois tuiles pour afficher un itinéraire entre eux au niveau de zoom 17. Cependant, si le point ouest est à droite de sa tuile, et le point oriental à gauche de sa tuile, il peut prendre quatre tuiles :

Échelle de démonstration Zoom

Une fois le niveau de zoom déterminé, les valeurs x et y peuvent être calculées. La tuile en haut à gauche de chaque grille de zoom est x=0, y=0 ; La tuile en bas à droite est à x=2zoom-1, y=2zoom-1.

Voici la grille de zoom pour le niveau de zoom 1 :

Grille de zoom pour le niveau de zoom 1

Indices quadriclés

Certaines plates-formes de cartographie utilisent une convention de quadkey nommage d’indexation qui combine les coordonnées ZY de la tuile en une chaîne unidimensionnelle appelée quadtree clés ou quadkeys en abrégé. Chacune quadkey identifie de manière unique une seule tuile à un niveau de détail particulier, et elle peut être utilisée comme clé dans les index d’arbre B de base de données courants. Les SDK Azure Maps prennent en charge la superposition de couches de tuiles qui utilisent quadkey la convention de nommage en plus d’autres conventions de nommage comme documenté dans le document Ajouter une couche de tuiles .

Remarque

La quadkeys convention de dénomination ne fonctionne que pour les niveaux de zoom d’un ou plus. Le SDK Azure Maps prend en charge le niveau de zoom 0, qui est une vignette de carte unique pour le monde entier.

Pour convertir les coordonnées de tuile en , quadkeyles bits des coordonnées Y et X sont entrelacés, et le résultat est interprété comme un nombre en base 4 (avec les zéros non significatifs maintenus) et converti en une chaîne. Par exemple, étant donné les coordonnées XY de la tuile (3, 5) au niveau 3, le quadkey est déterminé comme suit :

tileX = 3 = 011 (base 2)

tileY = 5 = 101 (base 2)

quadkey = 100111 (base 2) = 213 (base 4) = "213"

Qquadkeys ont plusieurs propriétés intéressantes. Tout d’abord, la longueur de a quadkey (le nombre de chiffres) est égale au niveau de zoom de la tuile correspondante. Deuxièmement, la quadkey de n’importe quelle tuile commence par la quadkey de sa tuile parente (la tuile contenant au niveau précédent). Comme le montre l’exemple suivant, la tuile 2 est le parent des tuiles 20 à 23 :

Pyramide de tuiles quadrilatères

Enfin, quadkeys fournissez une clé d’index unidimensionnelle qui préserve généralement la proximité des tuiles dans l’espace XY. En d’autres termes, deux tuiles qui ont des coordonnées XY proches ont quadkeys généralement des qui sont relativement proches l’une de l’autre. Ceci est important pour optimiser les performances de la base de données, car les tuiles voisines sont souvent demandées en groupes, et il est souhaitable de conserver ces tuiles sur les mêmes blocs de disque, afin de minimiser le nombre de lectures de disque.

Code source mathématique de tuile

L’exemple de code suivant illustre comment implémenter les fonctions décrites dans ce document. Ces fonctions peuvent être facilement traduites dans d’autres langages de programmation si nécessaire.

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

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

Remarque

Les contrôles de carte interactive dans le SDK Azure Maps disposent de fonctions d’assistance pour la conversion entre les positions géospatiales et les pixels de la fenêtre d’affichage.

Étapes suivantes

Accédez directement aux tuiles de carte à partir des services REST Azure Maps :

En savoir plus sur les concepts géospatiaux :