Megosztás a következőn keresztül:


Nagyítási szintek és csemperács

Az Azure Térképek a Spherical Mercator vetítési koordinátarendszert (EPSG:3857) használja. A vetítés a gömbgömb sík térképpé alakításához használt matematikai modell. A gömb alakú Mercator-vetítés a pólusokon feszíti ki a térképet, hogy négyzetes térképet hozzon létre. Ez az előrejelzés jelentősen torzítja a térkép skáláját és területét, de két fontos tulajdonsága van, amelyek felülmúlják ezt a torzítást:

  • Ez egy megfelelő kivetítés, ami azt jelenti, hogy megőrzi a viszonylag kis objektumok alakját. A kis objektumok alakjának megőrzése különösen fontos a légi felvételek megjelenítésekor. Például el szeretnénk kerülni az épületek alakjának torzítását. A négyzetes épületeknek négyzetnek kell megjelennie, nem téglalap alakúnak.
  • Ez egy hengeres kivetülés. Észak és dél mindig felfelé és lefelé, nyugaton és keleten pedig mindig balra és jobbra.

A térkép lekérésének és megjelenítésének teljesítményének optimalizálása érdekében a térkép négyzetes csempékre van osztva. Az Azure Térképek SDK 512 x 512 képpont méretű csempéket használ az úttérképekhez, a műholdas képekhez pedig kisebb 256 x 256 képpontot. Az Azure Térképek raszter- és vektorcsempéket biztosít 23 nagyítási szinthez, számozott 0 és 22 között. A 0. nagyítási szinten az egész világ egyetlen csempére illeszkedik:

Világtérkép csempe

Az 1. nagyítási szint négy csempét használ a világ megjelenítéséhez: egy 2 x 2 négyzet

2x2 térkép csempe elrendezése

Minden további nagyítási szint quad-elosztja az előző csempéit, és létrehoz egy rácsot 2nagyítás x 2nagyítással. A 22. nagyítási szint egy rács 2 22 x 222 vagy 4 194 304 x 4 194 304 csempe (összesen 17 592 186 044 416 csempe).

Az Azure Térképek webes és Androidos interaktív térképvezérlők 25 nagyítási szintet támogatnak, 0 és 24 között. Bár az útadatok csak a nagyítási szinteken érhetők el, amikor a csempék elérhetők.

Az alábbi táblázat a nagyítási szintek értékeinek teljes listáját tartalmazza, ahol a csempe mérete 256 képpont négyzet:

Nagyítási szint Mérő/képpont Mérő/csempe oldal
0 156543 40075017
0 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
21 0.074646 19.10926
22 0.037323 9.55463
23 0.0186615 4.777315
24 0.00933075 2.3886575

Képpontkoordináták

Miután kiválasztottuk az egyes nagyítási szinteken használni kívánt vetítést és méretezést, a földrajzi koordinátákat képpontkoordinátákká alakíthatjuk. Egy adott nagyítási szint térképképének teljes képpontszélessége és magassága a következőképpen számítható ki:

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

var mapHeight = mapWidth;

Mivel a térkép szélessége és magassága minden nagyítási szinten eltérő, így a képpont koordinátái is eltérőek. A térkép bal felső sarkában lévő képpont mindig képpontkoordinátával rendelkezik (0, 0). A térkép jobb alsó sarkában lévő képpont képpontkoordinátával rendelkezik (szélesség-1, magasság–1) vagy az előző szakaszban szereplő egyenletekre hivatkozva ( tileSize * 2zoom–1, tileSize * 2zoom–1). Ha például 512 négyzet csempét használ a 2. szinten, a képpontkoordináta a (0, 0) és (2047, 2047) közötti tartományba esik, a következőképpen:

Képpontméreteket ábrázoló térkép

A képpont XY koordinátái a következők szerint lesznek kiszámítva, ha a szélességet és a hosszúságot fokban, valamint a részletességi szintet figyelembe véve számítják ki:

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

A szélességi és hosszúsági értékek a WGS 84 datumban vannak. Annak ellenére, hogy az Azure Térképek gömb alakú vetületet használ, fontos, hogy az összes földrajzi koordinátát közös datummá alakítsa. A WGS 84 a kijelölt datum. A hosszúsági érték -180 fok és +180 fok között van, a szélességi értéket pedig -85,05112878 és 85,05112878 közötti tartományba kell vágni. Ezeknek az értékeknek a betartásával elkerülhető a pólusok szingularitása, és biztosítja, hogy a kivetített térkép négyzet alakú legyen.

Csempekoordináták

A térképlekérés és -megjelenítés teljesítményének optimalizálása érdekében a renderelt térkép csempékre van vágva. A képpontok száma és a csempék száma minden nagyítási szinten eltér:

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

var numberOfTilesHigh = numberOfTilesWide;

Minden csempe XY koordinátákat kap a bal felső sarokban található (0, 0) és a jobb alsó sarokban lévő (2nagyítás–1, 2nagyítás–1) között. A 3. nagyítási szinten például a csempe koordinátái a (0, 0) és a (7, 7) közötti tartományba esnek az alábbiak szerint:

Csempekoordináták térképe

A képpont XY koordinátáinak párja alapján könnyen meghatározhatja az adott képpontot tartalmazó csempe XY koordinátáit:

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

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

A csempéket nagyítási szinttel hívjuk meg. Az x és az y koordináták megfelelnek a csempe rácson elfoglalt pozíciójának az adott nagyítási szinthez.

A használni kívánt nagyítási szint meghatározásakor ne feledje, hogy minden hely rögzített helyzetben van a csempéjén. Ennek eredményeképpen az adott területterület megjelenítéséhez szükséges csempék száma a nagyítási rács adott elhelyezésétől függ a világtérképen. Ha például két pont 900 méter távolságra van egymástól, akkor csak három csempére lehet szükség ahhoz, hogy 17-es nagyítási szinten megjelenítsük közöttük az útvonalat. Ha azonban a nyugati pont a csempe jobb oldalán található, és a csempe bal oldalán található keleti pont, négy csempét vehet igénybe:

Nagyítási bemutató skálázása

A nagyítási szint meghatározása után az x és az y értékek kiszámíthatók. Minden nagyítási rács bal felső csempéje x=0, y=0; a jobb alsó csempe x=2zoom-1, y=2zoom-1.

Íme az 1. nagyítási szint nagyítási rácsa:

Nagyítási rács az 1. nagyítási szinthez

Négykulcsos indexek

Egyes leképezési platformok olyan indexelési elnevezési konvenciót quadkey használnak, amely egyesíti a csempe ZY koordinátáit egy kulcsok nevű quadtree egydimenziós sztringben vagy quadkeys röviden. Mindegyik quadkey egyedileg azonosít egy csempét egy adott részletességi szinten, és kulcsként használható a közös adatbázis B-fa indexeiben. Az Azure Térképek SDK-k támogatják az elnevezési konvenciót használó quadkey csemperétegek felülírását a Csemperéteg hozzáadása dokumentumban dokumentált egyéb elnevezési konvenciók mellett.

Feljegyzés

Az quadkeys elnevezési konvenció csak egy vagy több nagyítási szint esetén működik. Az Azure Térképek SDK támogatási 0. szintű nagyítási szintje, amely egyetlen térképcsempe az egész világon.

A csempekoordináták egyré quadkeyalakításához az Y és az X koordináták bitjei egymásba vannak osztva, és az eredményt alap-4 számként értelmezik (a kezdő nullák megtartva), és sztringgé alakulnak. Ha például a csempe XY koordinátái (3, 5) a 3. szinten, az quadkey alábbiak szerint lesz meghatározva:

tileX = 3 = 011 (base 2)

tileY = 5 = 101 (base 2)

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

Qquadkeys számos érdekes tulajdonsággal rendelkezik. Először egy (a számjegyek száma) hossza quadkey megegyezik a megfelelő csempe nagyítási szintjével. Másodszor, minden quadkey csempe a szülőcsempe (az előző szinten lévő csempével) kezdődik quadkey . Az alábbi példában látható módon a 2. csempe a 20–23. csempék szülője:

Négykulcsos csempe piramis

Végül adjon meg egy egydimenziós indexkulcsot, quadkeys amely általában megőrzi a csempék közelségét az XY térben. Más szavakkal, a közeli XY koordinátákkal rendelkező csempék általában quadkeys viszonylag közel vannak egymáshoz. Ez az adatbázis teljesítményének optimalizálása szempontjából fontos, mivel a szomszédos csempéket gyakran csoportokban kérik, és célszerű ezeket a csempéket ugyanazon a lemezblokkon tartani a lemezolvasások számának minimalizálása érdekében.

Csempe matematikai forráskódja

Az alábbi mintakód bemutatja, hogyan valósítható meg a dokumentumban leírt függvények. Ezek a függvények igény szerint egyszerűen lefordíthatók más programozási nyelvekre.

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="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</param>
        /// <param name="tileSize">The size of the tiles in the tile pyramid.</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>
        public static void BestMapView(double[] bounds, double mapWidth, double mapHeight, int padding, int tileSize, out double centerLat, out double centerLon, out double zoom)
        {
            if (bounds == null || bounds.Length < 4)
            {
                centerLat = 0;
                centerLon = 0;
                zoom = 1;
                return;
            }

            double boundsDeltaX;

            //Check if east value is greater than west value which would indicate that bounding box crosses the antimeridian.
            if (bounds[2] > bounds[0])
            {
                boundsDeltaX = bounds[2] - bounds[0];
                centerLon = (bounds[2] + bounds[0]) / 2;
            }
            else
            {
                boundsDeltaX = 360 - (bounds[0] - bounds[2]);
                centerLon = ((bounds[2] + bounds[0]) / 2 + 360) % 360 - 180;
            }

            var ry1 = Math.Log((Math.Sin(bounds[1] * Math.PI / 180) + 1) / Math.Cos(bounds[1] * Math.PI / 180));
            var ry2 = Math.Log((Math.Sin(bounds[3] * Math.PI / 180) + 1) / Math.Cos(bounds[3] * Math.PI / 180));
            var ryc = (ry1 + ry2) / 2;

            centerLat = Math.Atan(Math.Sinh(ryc)) * 180 / Math.PI;

            var resolutionHorizontal = boundsDeltaX / (mapWidth - padding * 2);

            var vy0 = Math.Log(Math.Tan(Math.PI * (0.25 + centerLat / 360)));
            var vy1 = Math.Log(Math.Tan(Math.PI * (0.25 + bounds[3] / 360)));
            var zoomFactorPowered = (mapHeight * 0.5 - padding) / (40.7436654315252 * (vy1 - vy0));
            var resolutionVertical = 360.0 / (zoomFactorPowered * tileSize);

            var resolution = Math.Max(resolutionHorizontal, resolutionVertical);

            zoom = Math.Log(360 / (resolution * tileSize), 2);
        }
    }
}

Feljegyzés

Az Azure Térképek SDK interaktív térképvezérlői segédfüggvényekkel rendelkeznek a térinformatikai pozíciók és a nézetport képpontok közötti konvertáláshoz.

Következő lépések

Térképcsempék közvetlen elérése az Azure Térképek REST-szolgáltatásokból:

További információ a térinformatikai fogalmakról: