Exemple #1
0
    // Adds a circle to the map and holds a refference on this point
    public void AddCircle(double radius, Color color)
    {
        float  r = (float)radius / OnlineMapsUtils.tileSize;
        float  step = 360f / segments;
        double x, y;

        _Pin.GetPosition(out x, out y);

        OnlineMapsProjection projection = OnlineMaps.instance.projection;

        projection.CoordinatesToTile(x, y, OnlineMaps.instance.zoom, out x, out y);

        points = new List <Vector2>();
        for (int i = 0; i < segments; i++)
        {
            points.Add(new Vector2());

            double px = x + Mathf.Cos(step * i * Mathf.Deg2Rad) * r;
            double py = y + Mathf.Sin(step * i * Mathf.Deg2Rad) * r;

            projection.TileToCoordinates(px, py, OnlineMaps.instance.zoom, out px, out py);

            points[i] = new Vector2((float)px, (float)py);
        }

        _Circle = new OnlineMapsDrawingPoly(points, color, 3);

        OnlineMaps.instance.AddDrawingElement(_Circle);

        _Acting = false;
    }
Exemple #2
0
    private double Angle(Vector2 userCoordinares, Vector2 markerCoordinates)
    {
        int zoom = 15;
        int maxX = 1 << (zoom - 1);

        double userTileX, userTileY, markerTileX, markerTileY;

        OnlineMapsProjection projection = MapManager.Instance.map.projection;

        projection.CoordinatesToTile(userCoordinares.x, userCoordinares.y, zoom, out userTileX, out userTileY);
        projection.CoordinatesToTile(markerCoordinates.x, markerCoordinates.y, zoom, out markerTileX, out markerTileY);

        // Calculate the angle between locations.
        double angle = OnlineMapsUtils.Angle2D(userTileX, userTileY, markerTileX, markerTileY);

        return(angle);
    }
    public override bool HitTest(Vector2 positionLngLat, int zoom)
    {
        if (points == null)
        {
            return(false);
        }

        double cx, cy;
        OnlineMapsProjection projection = api.projection;

        projection.CoordinatesToTile(positionLngLat.x, positionLngLat.y, zoom, out cx, out cy);

        int valueType = -1; // 0 - Vector2, 1 - float, 2 - double, 3 - OnlineMapsVector2d

        object v1 = null;
        object v2 = null;
        object v3 = null;
        int    i  = 0;

        float w    = hitTestWidth.HasValue ? hitTestWidth.Value : width;
        float sqrW = w * w;

        foreach (object p in points)
        {
            if (valueType == -1)
            {
                if (p is Vector2)
                {
                    valueType = 0;
                }
                else if (p is float)
                {
                    valueType = 1;
                }
                else if (p is double)
                {
                    valueType = 2;
                }
                else if (p is OnlineMapsVector2d)
                {
                    valueType = 3;
                }
            }

            object v4 = v3;
            v3 = v2;
            v2 = v1;
            v1 = p;

            double p1tx = 0, p1ty = 0, p2tx = 0, p2ty = 0;
            bool   drawPart = false;

            if (valueType == 0)
            {
                if (i > 0)
                {
                    Vector2 p1 = (Vector2)v2;
                    Vector2 p2 = (Vector2)v1;

                    projection.CoordinatesToTile(p1.x, p1.y, zoom, out p1tx, out p1ty);
                    projection.CoordinatesToTile(p2.x, p2.y, zoom, out p2tx, out p2ty);
                    drawPart = true;
                }
            }
            else if (valueType == 3)
            {
                if (i > 0)
                {
                    OnlineMapsVector2d p1 = (OnlineMapsVector2d)v2;
                    OnlineMapsVector2d p2 = (OnlineMapsVector2d)v1;

                    projection.CoordinatesToTile(p1.x, p1.y, zoom, out p1tx, out p1ty);
                    projection.CoordinatesToTile(p2.x, p2.y, zoom, out p2tx, out p2ty);
                    drawPart = true;
                }
            }
            else if (i > 2 && i % 2 == 1)
            {
                if (valueType == 1)
                {
                    projection.CoordinatesToTile((float)v4, (float)v3, zoom, out p1tx, out p1ty);
                    projection.CoordinatesToTile((float)v2, (float)v1, zoom, out p2tx, out p2ty);
                }
                else if (valueType == 2)
                {
                    projection.CoordinatesToTile((double)v4, (double)v3, zoom, out p1tx, out p1ty);
                    projection.CoordinatesToTile((double)v2, (double)v1, zoom, out p2tx, out p2ty);
                }
                drawPart = true;
            }

            if (drawPart)
            {
                double nx, ny;
                OnlineMapsUtils.NearestPointStrict(cx, cy, p1tx, p1ty, p2tx, p2ty, out nx, out ny);
                double dx = (cx - nx) * OnlineMapsUtils.tileSize;
                double dy = (cy - ny) * OnlineMapsUtils.tileSize;
                double d  = dx * dx + dy * dy;
                if (d < sqrW)
                {
                    return(true);
                }
            }

            i++;
        }

        return(false);
    }
    protected List <Vector2> GetLocalPoints(IEnumerable points, bool closed = false, bool optimize = true)
    {
        double sx, sy;

        int   zoom     = map.zoom;
        float zoomCoof = map.zoomCoof;

        OnlineMapsProjection projection = map.projection;

        projection.CoordinatesToTile(tlx, tly, zoom, out sx, out sy);

        int max     = 1 << zoom;
        int halfMax = max / 2;

        if (localPoints == null)
        {
            localPoints = new List <Vector2>();
        }
        else
        {
            localPoints.Clear();
        }

        double ppx    = 0;
        double scaleX = OnlineMapsUtils.tileSize * OnlineMapsControlBaseDynamicMesh.instance.sizeInScene.x / map.buffer.renderState.width / zoomCoof;
        double scaleY = OnlineMapsUtils.tileSize * OnlineMapsControlBaseDynamicMesh.instance.sizeInScene.y / map.buffer.renderState.height / zoomCoof;

        double prx = 0, pry = 0;

        object v1 = null;
        int    i = -1;
        int    valueType = -1; // 0 - Vector2, 1 - float, 2 - double, 3 - OnlineMapsVector2d
        bool   isOptimized = false;
        double px = 0, py = 0;

        IEnumerator enumerator = points.GetEnumerator();

        while (enumerator.MoveNext())
        {
            i++;

            object p = enumerator.Current;
            if (valueType == -1)
            {
                if (p is Vector2)
                {
                    valueType = 0;
                }
                else if (p is float)
                {
                    valueType = 1;
                }
                else if (p is double)
                {
                    valueType = 2;
                }
                else if (p is OnlineMapsVector2d)
                {
                    valueType = 3;
                }
            }

            object v2 = v1;
            v1 = p;

            bool useValue = false;

            if (valueType == 0)
            {
                Vector2 point = (Vector2)p;
                projection.CoordinatesToTile(point.x, point.y, zoom, out px, out py);
                useValue = true;
            }
            else if (valueType == 3)
            {
                OnlineMapsVector2d point = (OnlineMapsVector2d)p;
                projection.CoordinatesToTile(point.x, point.y, zoom, out px, out py);
                useValue = true;
            }
            else if (i % 2 == 1)
            {
                if (valueType == 1)
                {
                    projection.CoordinatesToTile((float)v2, (float)v1, zoom, out px, out py);
                }
                else if (valueType == 2)
                {
                    projection.CoordinatesToTile((double)v2, (double)v1, zoom, out px, out py);
                }
                useValue = true;
            }

            if (!useValue)
            {
                continue;
            }

            isOptimized = false;

            if (optimize && i > 0)
            {
                if ((prx - px) * (prx - px) + (pry - py) * (pry - py) < 0.001)
                {
                    isOptimized = true;
                    continue;
                }
            }

            prx = px;
            pry = py;

            px -= sx;
            py -= sy;

            if (i == 0)
            {
                double ox = px - map.width / OnlineMapsUtils.tileSize / 2;
                if (ox < -halfMax)
                {
                    px += max;
                }
                else if (ox > halfMax)
                {
                    px -= max;
                }
            }
            else
            {
                double ox    = px - ppx;
                int    maxIt = 3;
                while (maxIt-- > 0)
                {
                    if (ox < -halfMax)
                    {
                        px += max;
                        ox += max;
                    }
                    else if (ox > halfMax)
                    {
                        px -= max;
                        ox -= max;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            ppx = px;

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
        }

        if (isOptimized)
        {
            px -= sx;
            py -= sy;

            if (i == 0)
            {
                double ox = px - map.width / OnlineMapsUtils.tileSize / 2;
                if (ox < -halfMax)
                {
                    px += max;
                }
                else if (ox > halfMax)
                {
                    px -= max;
                }
            }
            else
            {
                double ox    = px - ppx;
                int    maxIt = 3;
                while (maxIt-- > 0)
                {
                    if (ox < -halfMax)
                    {
                        px += max;
                        ox += max;
                    }
                    else if (ox > halfMax)
                    {
                        px -= max;
                        ox -= max;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
        }

        if (closed)
        {
            localPoints.Add(localPoints[0]);
        }

        return(localPoints);
    }
Exemple #5
0
    protected List <Vector2> GetLocalPoints(IEnumerable points, bool closed = false, bool optimize = true)
    {
        double               sx, sy;
        OnlineMaps           map        = api;
        int                  apiZoom    = map.buffer.apiZoom;
        OnlineMapsProjection projection = map.projection;

        projection.CoordinatesToTile(tlx, tly, apiZoom, out sx, out sy);

        int maxX = 1 << apiZoom;

        if (localPoints == null)
        {
            localPoints = new List <Vector2>();
        }
        else
        {
            localPoints.Clear();
        }

        double ppx    = 0;
        double scaleX = OnlineMapsUtils.tileSize * map.tilesetSize.x / map.tilesetWidth;
        double scaleY = OnlineMapsUtils.tileSize * map.tilesetSize.y / map.tilesetHeight;

        double prx = 0, pry = 0;

        object v1 = null;
        int    i = -1;
        int    valueType = -1; // 0 - Vector2, 1 - float, 2 - double, 3 - OnlineMapsVector2d
        bool   isOptimized = false;
        double px = 0, py = 0;

        IEnumerator enumerator = points.GetEnumerator();

        while (enumerator.MoveNext())
        {
            i++;

            object p = enumerator.Current;
            if (valueType == -1)
            {
                if (p is Vector2)
                {
                    valueType = 0;
                }
                else if (p is float)
                {
                    valueType = 1;
                }
                else if (p is double)
                {
                    valueType = 2;
                }
                else if (p is OnlineMapsVector2d)
                {
                    valueType = 3;
                }
            }

            object v2 = v1;
            v1 = p;

            bool useValue = false;

            if (valueType == 0)
            {
                Vector2 point = (Vector2)p;
                projection.CoordinatesToTile(point.x, point.y, apiZoom, out px, out py);
                useValue = true;
            }
            else if (valueType == 3)
            {
                OnlineMapsVector2d point = (OnlineMapsVector2d)p;
                projection.CoordinatesToTile(point.x, point.y, apiZoom, out px, out py);
                useValue = true;
            }
            else if (i % 2 == 1)
            {
                if (valueType == 1)
                {
                    projection.CoordinatesToTile((float)v2, (float)v1, apiZoom, out px, out py);
                }
                else if (valueType == 2)
                {
                    projection.CoordinatesToTile((double)v2, (double)v1, apiZoom, out px, out py);
                }
                useValue = true;
            }

            if (!useValue)
            {
                continue;
            }

            isOptimized = false;

            if (optimize && i > 0)
            {
                if ((prx - px) * (prx - px) + (pry - py) * (pry - py) < 0.001)
                {
                    isOptimized = true;
                    continue;
                }
            }

            prx = px;
            pry = py;

            px -= sx;
            py -= sy;

            if (i == 0)
            {
                if (px < maxX * -0.25)
                {
                    px += maxX;
                }
                else if (px > maxX * 0.75)
                {
                    px -= maxX;
                }
            }
            else
            {
                double gpx = px + maxX;
                double lpx = px - maxX;

                if (Math.Abs(ppx - gpx) < Math.Abs(ppx - px))
                {
                    px = gpx;
                }
                else if (Math.Abs(ppx - lpx) < Math.Abs(ppx - px))
                {
                    px = lpx;
                }
            }

            ppx = px;

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
        }

        if (isOptimized)
        {
            px -= sx;
            py -= sy;

            if (i == 0)
            {
                if (px < maxX * -0.25)
                {
                    px += maxX;
                }
                else if (px > maxX * 0.75)
                {
                    px -= maxX;
                }
            }
            else
            {
                double gpx = px + maxX;
                double lpx = px - maxX;

                if (Math.Abs(ppx - gpx) < Math.Abs(ppx - px))
                {
                    px = gpx;
                }
                else if (Math.Abs(ppx - lpx) < Math.Abs(ppx - px))
                {
                    px = lpx;
                }
            }

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
        }

        if (closed)
        {
            localPoints.Add(localPoints[0]);
        }

        return(localPoints);
    }
Exemple #6
0
    protected List <Vector2> GetLocalPoints(IEnumerable points, bool closed = false, bool optimize = true)
    {
        double sx, sy;
        int    apiZoom = api.buffer.apiZoom;
        OnlineMapsProjection projection = api.projection;

        projection.CoordinatesToTile(tlx, tly, apiZoom, out sx, out sy);

        int maxX = 1 << api.zoom;

        //int off = closed ? 1 : 0;
        //int pointsCount = points.Count;
        //int maxI = pointsCount + off;

        List <Vector2> localPoints = new List <Vector2>(1024);

        double ppx    = 0;
        double scaleX = OnlineMapsUtils.tileSize * api.tilesetSize.x / api.tilesetWidth;
        double scaleY = OnlineMapsUtils.tileSize * api.tilesetSize.y / api.tilesetHeight;

        double prx = 0, pry = 0;

        object v1 = null, v2 = null;
        int    i = 0;
        int    valueType = -1; // 0 - Vector2, 1 - float, 2 - double
        bool   isOptimized = false;
        double px = 0, py = 0;

        foreach (object p in points)
        {
            if (valueType == -1)
            {
                if (p is Vector2)
                {
                    valueType = 0;
                }
                else if (p is float)
                {
                    valueType = 1;
                }
                else if (p is double)
                {
                    valueType = 2;
                }
            }

            v2 = v1;
            v1 = p;

            bool useValue = false;

            if (valueType == 0)
            {
                Vector2 point = (Vector2)p;
                projection.CoordinatesToTile(point.x, point.y, apiZoom, out px, out py);
                useValue = true;
            }
            else if (i % 2 == 1)
            {
                if (valueType == 1)
                {
                    projection.CoordinatesToTile((float)v2, (float)v1, apiZoom, out px, out py);
                }
                else if (valueType == 2)
                {
                    projection.CoordinatesToTile((double)v2, (double)v1, apiZoom, out px, out py);
                }
                useValue = true;
            }

            i++;

            if (!useValue)
            {
                continue;
            }

            isOptimized = false;

            if (optimize && i > 0)
            {
                if ((prx - px) * (prx - px) + (pry - py) * (pry - py) < 0.001)
                {
                    isOptimized = true;
                    continue;
                }
            }

            prx = px;
            pry = py;

            px -= sx;
            py -= sy;

            if (i == 0)
            {
                if (px < maxX * -0.25)
                {
                    px += maxX;
                }
                else if (px > maxX * 0.75)
                {
                    px -= maxX;
                }
            }
            else
            {
                double gpx = px + maxX;
                double lpx = px - maxX;

                if (Math.Abs(ppx - gpx) < Math.Abs(ppx - px))
                {
                    px = gpx;
                }
                else if (Math.Abs(ppx - lpx) < Math.Abs(ppx - px))
                {
                    px = lpx;
                }
            }

            ppx = px;

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
        }

        if (isOptimized)
        {
            px -= sx;
            py -= sy;

            if (i == 0)
            {
                if (px < maxX * -0.25)
                {
                    px += maxX;
                }
                else if (px > maxX * 0.75)
                {
                    px -= maxX;
                }
            }
            else
            {
                double gpx = px + maxX;
                double lpx = px - maxX;

                if (Math.Abs(ppx - gpx) < Math.Abs(ppx - px))
                {
                    px = gpx;
                }
                else if (Math.Abs(ppx - lpx) < Math.Abs(ppx - px))
                {
                    px = lpx;
                }
            }

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
        }

        if (closed)
        {
            localPoints.Add(localPoints[0]);
        }

        /*for (int i = 0; i < maxI; i++)
         * {
         *  int ci = i;
         *  if (ci >= pointsCount) ci -= pointsCount;
         *  double px, py;
         *
         *  Vector2 point = points[ci];
         *  projection.CoordinatesToTile(point.x, point.y, apiZoom, out px, out py);
         *
         *  if (optimize && i > 0 && i < maxI - 1)
         *  {
         *      if ((prx - px) * (prx - px) + (pry - py) * (pry - py) < 0.001) continue;
         *  }
         *
         *  prx = px;
         *  pry = py;
         *
         *  px -= sx;
         *  py -= sy;
         *
         *  if (i == 0)
         *  {
         *      if (px < maxX * -0.25) px += maxX;
         *      else if (px > maxX * 0.75) px -= maxX;
         *  }
         *  else
         *  {
         *      double gpx = px + maxX;
         *      double lpx = px - maxX;
         *
         *      if (Math.Abs(ppx - gpx) < Math.Abs(ppx - px)) px = gpx;
         *      else if (Math.Abs(ppx - lpx) < Math.Abs(ppx - px)) px = lpx;
         *  }
         *
         *  ppx = px;
         *
         *  double rx1 = px * scaleX;
         *  double ry1 = py * scaleY;
         *
         *  Vector2 np = new Vector2((float)rx1, (float)ry1);
         *  localPoints.Add(np);
         *  if (localPoints.Count == localPoints.Capacity) localPoints.Capacity += 1024;
         * }*/
        return(localPoints);
    }
Exemple #7
0
    protected List <Vector2> GetLocalPoints(List <Vector2> points, bool closed = false, bool optimize = true)
    {
        double sx, sy;
        int    apiZoom = api.buffer.apiZoom;
        OnlineMapsProjection projection = api.projection;

        projection.CoordinatesToTile(tlx, tly, apiZoom, out sx, out sy);

        int maxX = 1 << api.zoom;

        int off         = closed ? 1 : 0;
        int pointsCount = points.Count;
        int maxI        = pointsCount + off;

        List <Vector2> localPoints = new List <Vector2>(Mathf.Min(maxI, 1024));

        double ppx    = 0;
        double scaleX = OnlineMapsUtils.tileSize * api.tilesetSize.x / api.tilesetWidth;
        double scaleY = OnlineMapsUtils.tileSize * api.tilesetSize.y / api.tilesetHeight;

        double prx = 0, pry = 0;

        for (int i = 0; i < maxI; i++)
        {
            int ci = i;
            if (ci >= pointsCount)
            {
                ci -= pointsCount;
            }
            double px, py;

            Vector2 point = points[ci];
            projection.CoordinatesToTile(point.x, point.y, apiZoom, out px, out py);

            if (optimize && i > 0 && i < maxI - 1)
            {
                if ((prx - px) * (prx - px) + (pry - py) * (pry - py) < 0.001)
                {
                    continue;
                }
            }

            prx = px;
            pry = py;

            px -= sx;
            py -= sy;

            if (i == 0)
            {
                if (px < maxX * -0.25)
                {
                    px += maxX;
                }
                else if (px > maxX * 0.75)
                {
                    px -= maxX;
                }
            }
            else
            {
                double gpx = px + maxX;
                double lpx = px - maxX;

                if (Math.Abs(ppx - gpx) < Math.Abs(ppx - px))
                {
                    px = gpx;
                }
                else if (Math.Abs(ppx - lpx) < Math.Abs(ppx - px))
                {
                    px = lpx;
                }
            }

            ppx = px;

            double rx1 = px * scaleX;
            double ry1 = py * scaleY;

            Vector2 np = new Vector2((float)rx1, (float)ry1);
            localPoints.Add(np);
            if (localPoints.Count == localPoints.Capacity)
            {
                localPoints.Capacity += 1024;
            }
        }
        return(localPoints);
    }
Exemple #8
0
        private void GroupMarkers()
        {
            OnlineMapsProjection projection = OnlineMaps.instance.projection;

            List <MarkerGroup> groups = new List <MarkerGroup>();

            for (int zoom = 20; zoom >= 3; zoom--)
            {
                List <OnlineMapsMarker> ms = markers.Select(m => m).ToList();

                for (int j = 0; j < ms.Count - 1; j++)
                {
                    OnlineMapsMarker marker = ms[j];
                    MarkerGroup      group = null;
                    double           mx, my;
                    marker.GetPosition(out mx, out my);

                    double px, py;
                    projection.CoordinatesToTile(mx, my, zoom, out px, out py);

                    int k = j + 1;

                    while (k < ms.Count)
                    {
                        OnlineMapsMarker marker2 = ms[k];

                        double m2x, m2y;
                        marker2.GetPosition(out m2x, out m2y);

                        double p2x, p2y;
                        projection.CoordinatesToTile(m2x, m2y, zoom, out p2x, out p2y);

                        if (OnlineMapsUtils.Magnitude(px, py, p2x, p2y) < distance)
                        {
                            if (group == null)
                            {
                                group = new MarkerGroup(zoom, groupTexture);
                                groups.Add(group);
                                group.Add(marker);
                                if (marker.range.min == 3)
                                {
                                    marker.range.min = zoom + 1;
                                }
                            }
                            group.Add(marker2);
                            if (marker2.range.min == 3)
                            {
                                marker2.range.min = zoom + 1;
                            }
                            ms.RemoveAt(k);
                            px = group.tilePositionX;
                            py = group.tilePositionY;
                        }
                        else
                        {
                            k++;
                        }
                    }
                }
            }

            foreach (MarkerGroup g in groups)
            {
                g.Apply(font);
            }
        }
    /// <summary>
    /// Get the center point and best zoom for the array of coordinates.
    /// </summary>
    /// <param name="positions">Array of coordinates</param>
    /// <param name="center">Center coordinate</param>
    /// <param name="zoom">Best zoom</param>
    public static void GetCenterPointAndZoom(Vector2[] positions, out Vector2 center, out int zoom)
    {
        OnlineMaps           api        = OnlineMaps.instance;
        OnlineMapsProjection projection = api.projection;

        float minX = Single.MaxValue;
        float minY = Single.MaxValue;
        float maxX = Single.MinValue;
        float maxY = Single.MinValue;

        foreach (Vector2 p in positions)
        {
            if (p.x < minX)
            {
                minX = p.x;
            }
            if (p.y < minY)
            {
                minY = p.y;
            }
            if (p.x > maxX)
            {
                maxX = p.x;
            }
            if (p.y > maxY)
            {
                maxY = p.y;
            }
        }

        float rx = maxX - minX;
        float ry = maxY - minY;

        center = new Vector2(rx / 2 + minX, ry / 2 + minY);

        int width  = api.width;
        int height = api.height;

        float countX = width / (float)tileSize / 2;
        float countY = height / (float)tileSize / 2;

        for (int z = 20; z > 4; z--)
        {
            bool success = true;

            double cx, cy;
            projection.CoordinatesToTile(center.x, center.y, z, out cx, out cy);

            foreach (Vector2 pos in positions)
            {
                double px, py;
                projection.CoordinatesToTile(pos.x, pos.y, z, out px, out py);


                px -= cx - countX;
                py -= cy - countY;

                if (px < 0 || py < 0 || px > width || py > height)
                {
                    success = false;
                    break;
                }
            }
            if (success)
            {
                zoom = z;
                return;
            }
        }

        zoom = 3;
    }
Exemple #10
0
    /// <summary>
    /// Get the center point and best zoom for the array of markers.
    /// </summary>
    /// <param name="markers">Array of markers.</param>
    /// <param name="center">Center point.</param>
    /// <param name="zoom">Best zoom.</param>
    public static void GetCenterPointAndZoom(OnlineMapsMarkerBase[] markers, out Vector2 center, out int zoom)
    {
        OnlineMaps           api        = OnlineMaps.instance;
        OnlineMapsProjection projection = api.projection;

        double minX = Double.MaxValue;
        double minY = Double.MaxValue;
        double maxX = Double.MinValue;
        double maxY = Double.MinValue;

        foreach (OnlineMapsMarkerBase marker in markers)
        {
            double mx, my;
            marker.GetPosition(out mx, out my);
            if (mx < minX)
            {
                minX = mx;
            }
            if (my < minY)
            {
                minY = my;
            }
            if (mx > maxX)
            {
                maxX = mx;
            }
            if (my > maxY)
            {
                maxY = my;
            }
        }

        double rx = maxX - minX;
        double ry = maxY - minY;

        center = new Vector2((float)(rx / 2 + minX), (float)(ry / 2 + minY));

        int width  = api.width;
        int height = api.height;

        float countX = width / (float)tileSize / 2;
        float countY = height / (float)tileSize / 2;

        bool useZoomMin = false;

        for (int z = 20; z > 4; z--)
        {
            bool success = true;

            double bx, by;
            projection.CoordinatesToTile(center.x, center.y, z, out bx, out by);

            foreach (OnlineMapsMarkerBase marker in markers)
            {
                double mx, my;
                marker.GetPosition(out mx, out my);

                double px, py;
                projection.CoordinatesToTile(mx, my, z, out px, out py);

                px -= bx - countX;
                py -= by - countY;

                if (marker is OnlineMapsMarker)
                {
                    useZoomMin = true;
                    OnlineMapsMarker   m  = marker as OnlineMapsMarker;
                    OnlineMapsVector2i ip = m.GetAlignedPosition(new OnlineMapsVector2i((int)(px * tileSize), (int)(py * tileSize)));
                    if (ip.x < 0 || ip.y < 0 || ip.x + m.width > width || ip.y + m.height > height)
                    {
                        success = false;
                        break;
                    }
                }
                else if (marker is OnlineMapsMarker3D)
                {
                    if (px < 0 || py < 0 || px > width || py > height)
                    {
                        success = false;
                        break;
                    }
                }
                else
                {
                    throw new Exception("Wrong marker type");
                }
            }
            if (success)
            {
                zoom = z;
                if (useZoomMin)
                {
                    zoom -= 1;
                }
                return;
            }
        }

        zoom = 3;
    }