/// <summary>
    /// Updates billboard markers.
    /// </summary>
    protected void UpdateMarkersBillboard()
    {
        if (markersGameObject == null)
        {
            InitMarkersMesh();
        }
        if (markerBillboards == null)
        {
            markerBillboards = new Dictionary <int, OnlineMapsMarkerBillboard>();
        }

        double tlx, tly, brx, bry;

        api.GetTopLeftPosition(out tlx, out tly);
        api.GetBottomRightPosition(out brx, out bry);
        if (brx < tlx)
        {
            brx += 360;
        }

        int maxX = (2 << api.buffer.apiZoom) / 2;

        double px, py;

        OnlineMapsUtils.LatLongToTiled(tlx, tly, api.zoom, out px, out py);

        float yScale = GetBestElevationYScale(tlx, tly, brx, bry);

        Bounds  mapBounds      = cl.bounds;
        Vector3 positionOffset = transform.position - mapBounds.min;
        Vector3 size           = mapBounds.size;

        size = transform.rotation * size;
        if (api.target == OnlineMapsTarget.tileset)
        {
            positionOffset.x -= size.x;
        }

        foreach (KeyValuePair <int, OnlineMapsMarkerBillboard> billboard in markerBillboards)
        {
            billboard.Value.used = false;
        }

        foreach (OnlineMapsMarker marker in api.markers)
        {
            if (!marker.enabled || !marker.range.InRange(api.zoom))
            {
                continue;
            }
            float mx = marker.position.x;
            if (!(((mx > tlx && mx < brx) || (mx + 360 > tlx && mx + 360 < brx) ||
                   (mx - 360 > tlx && mx - 360 < brx)) &&
                  marker.position.y < tly && marker.position.y > bry))
            {
                continue;
            }

            int markerHashCode = marker.GetHashCode();
            OnlineMapsMarkerBillboard markerBillboard = null;

            if (!markerBillboards.ContainsKey(markerHashCode))
            {
                markerBillboard = OnlineMapsMarkerBillboard.Create(marker);
                markerBillboard.transform.parent = markersGameObject.transform;

                markerBillboards.Add(markerHashCode, markerBillboard);
            }
            else
            {
                markerBillboard = markerBillboards[markerHashCode];
            }

            float sx = size.x / api.width * marker2DSize * marker.scale;
            float sz = size.z / api.height * marker2DSize * marker.scale;
            float s  = Mathf.Max(sx, sz);
            markerBillboard.transform.localScale = new Vector3(-s, s, s);

            Vector2 p = OnlineMapsUtils.LatLongToTilef(marker.position, api.buffer.apiZoom);

            p.x  = Mathf.Repeat(p.x - (float)px, maxX);
            p.y -= (float)py;

            float x = -p.x / api.width * OnlineMapsUtils.tileSize * size.x + positionOffset.x;
            float z = p.y / api.height * OnlineMapsUtils.tileSize * size.z - positionOffset.z;

            float y = GetElevationValue(x, z, yScale, tlx, tly, brx, bry);

            markerBillboard.transform.localPosition = transform.rotation * new Vector3(x, y, z);
            markerBillboard.used = true;
        }

        List <int> keysForRemove = new List <int>();

        foreach (KeyValuePair <int, OnlineMapsMarkerBillboard> billboard in markerBillboards)
        {
            if (!billboard.Value.used)
            {
                billboard.Value.Dispose();
                keysForRemove.Add(billboard.Key);
            }
        }

        foreach (int key in keysForRemove)
        {
            markerBillboards.Remove(key);
        }
    }
    /// <summary>
    /// Updates billboard markers.
    /// </summary>
    protected void UpdateMarkersBillboard()
    {
        if (markersGameObjects == null)
        {
            InitMarkersMesh(0);
        }
        if (markerBillboards == null)
        {
            markerBillboards = new Dictionary <int, OnlineMapsMarkerBillboard>();
        }
        //  Debug.Log("update " + markerBillboards.Count());
        double tlx, tly, brx, bry;

        map.GetCorners(out tlx, out tly, out brx, out bry);
        if (brx < tlx)
        {
            brx += 360;
        }

        int maxX = (2 << map.buffer.apiZoom) / 2;

        double px, py;

        map.projection.CoordinatesToTile(tlx, tly, map.zoom, out px, out py);

        float yScale = GetBestElevationYScale(tlx, tly, brx, bry);

        Bounds  mapBounds      = cl.bounds;
        Vector3 positionOffset = transform.position - mapBounds.min;
        Vector3 size           = mapBounds.size;

        size = transform.rotation * size;
        if (map.target == OnlineMapsTarget.tileset)
        {
            positionOffset.x -= size.x;
        }

        foreach (KeyValuePair <int, OnlineMapsMarkerBillboard> billboard in markerBillboards)
        {
            billboard.Value.used = false;
        }

        foreach (OnlineMapsMarker marker in map.markers)
        {
            //   Debug.Log("mảk");
            if (!marker.enabled || !marker.range.InRange(map.zoom))
            {
                continue;
            }
            //    Debug.Log("mảk enable");
            double mx, my;
            marker.GetPosition(out mx, out my);

            if (!(((mx > tlx && mx < brx) || (mx + 360 > tlx && mx + 360 < brx) ||
                   (mx - 360 > tlx && mx - 360 < brx)) &&
                  my < tly && my > bry))
            {
                continue;
            }

            int markerHashCode = marker.GetHashCode();
            OnlineMapsMarkerBillboard markerBillboard;

            if (!markerBillboards.ContainsKey(markerHashCode))
            {
                //  Debug.Log("mảk hashcode");
                markerBillboard = OnlineMapsMarkerBillboard.Create(marker);
                markerBillboard.transform.parent = markersGameObjects[0].transform;
                markerBillboard.gameObject.layer = markersGameObjects[0].layer;

                markerBillboards.Add(markerHashCode, markerBillboard);
            }
            else
            {
                markerBillboard = markerBillboards[markerHashCode];
            }

            if (markerBillboard == null)
            {
                continue;
            }

            float sx = size.x / map.width * marker2DSize * marker.scale;
            float sz = size.z / map.height * marker2DSize * marker.scale;
            float s  = Mathf.Max(sx, sz);

#if !UNITY_4_6 && !UNITY_4_7 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2
            markerBillboard.transform.localScale = new Vector3(s, s, s);
#else
            markerBillboard.transform.localScale = new Vector3(-s, s, s);
#endif

            double mpx, mpy;
            map.projection.CoordinatesToTile(mx, my, map.buffer.apiZoom, out mpx, out mpy);

            mpx  = OnlineMapsUtils.Repeat(mpx - px, 0, maxX);
            mpy -= py;

            float x = (float)(-mpx / map.width * OnlineMapsUtils.tileSize * size.x + positionOffset.x);
            float z = (float)(mpy / map.height * OnlineMapsUtils.tileSize * size.z - positionOffset.z);

            float y = GetElevationValue(x, z, yScale, tlx, tly, brx, bry);

            markerBillboard.transform.localPosition = transform.rotation * new Vector3(x, y, z);
            markerBillboard.used = true;
        }

        List <int> keysForRemove = new List <int>();

        foreach (KeyValuePair <int, OnlineMapsMarkerBillboard> billboard in markerBillboards)
        {
            if (!billboard.Value.used)
            {
                billboard.Value.Dispose();
                keysForRemove.Add(billboard.Key);
            }
        }

        foreach (int key in keysForRemove)
        {
            markerBillboards.Remove(key);
        }
    }
    private void OnDrawMarkers()
    {
        if (markersGameObjects == null)
        {
            InitMarkersMesh(0);
        }
        if (markerBillboards == null)
        {
            markerBillboards = new Dictionary <int, OnlineMapsMarkerBillboard>();
        }

        double tlx, tly, brx, bry;

        map.GetCorners(out tlx, out tly, out brx, out bry);
        if (brx < tlx)
        {
            brx += 360;
        }

        double px, py;

        map.projection.CoordinatesToTile(tlx, tly, map.zoom, out px, out py);

        Bounds  mapBounds      = control.cl.bounds;
        Vector3 positionOffset = control.transform.position - mapBounds.min;
        Vector3 size           = mapBounds.size;

        size = control.transform.rotation * size;
        if (!control.resultIsTexture)
        {
            positionOffset.x -= size.x;
        }

        foreach (KeyValuePair <int, OnlineMapsMarkerBillboard> billboard in markerBillboards)
        {
            billboard.Value.used = false;
        }

        foreach (OnlineMapsMarker marker in OnlineMapsMarkerManager.instance)
        {
            if (!marker.enabled || !marker.range.InRange(map.zoom))
            {
                continue;
            }

            double mx, my;
            marker.GetPosition(out mx, out my);

            if (!((mx > tlx && mx < brx || mx + 360 > tlx && mx + 360 < brx ||
                   mx - 360 > tlx && mx - 360 < brx) &&
                  my < tly && my > bry))
            {
                continue;
            }

            int markerHashCode = marker.GetHashCode();
            OnlineMapsMarkerBillboard markerBillboard;

            if (!markerBillboards.ContainsKey(markerHashCode))
            {
                markerBillboard = OnlineMapsMarkerBillboard.Create(marker);
                markerBillboard.transform.parent = markersGameObjects[0].transform;
                markerBillboard.gameObject.layer = markersGameObjects[0].layer;

                markerBillboards.Add(markerHashCode, markerBillboard);
            }
            else
            {
                markerBillboard = markerBillboards[markerHashCode];
            }

            if (markerBillboard == null)
            {
                continue;
            }

            float sx = size.x / map.buffer.renderState.width * marker2DSize * marker.scale;
            float sz = size.z / map.buffer.renderState.height * marker2DSize * marker.scale;
            float s  = Mathf.Max(sx, sz);

            markerBillboard.transform.localScale = new Vector3(s, s, s);
            markerBillboard.transform.position   = control.GetWorldPositionWithElevation(mx, my, tlx, tly, brx, bry);


            markerBillboard.used = true;
        }

        List <int> keysForRemove = new List <int>();

        foreach (KeyValuePair <int, OnlineMapsMarkerBillboard> billboard in markerBillboards)
        {
            if (!billboard.Value.used)
            {
                billboard.Value.Dispose();
                keysForRemove.Add(billboard.Key);
            }
        }

        foreach (int key in keysForRemove)
        {
            markerBillboards.Remove(key);
        }
    }