/// <summary>
        /// Merges all provinces in each continent so their number doesn't exceed a given number
        /// </summary>
        /// <param name="max">Maximum number of countries per continent.</param>
        /// <param name="z">The current country index.</param>
        public void CountriesEqualize(int max, out bool repeat)
        {
            if (max < 1)
            {
                max = 1;
            }

            if (groupedCountries == null)
            {
                groupedCountries = new Dictionary <string, List <Country> >();
            }
            else
            {
                groupedCountries.Clear();
            }

            repeat = false;

            // Select continents
            for (int k = 0; k < map.countries.Length; k++)
            {
                Country country = map.countries[k];
                if (country.continent.Length > 0)
                {
                    List <Country> countries;
                    if (groupedCountries.TryGetValue(country.continent, out countries))
                    {
                        countries.Add(country);
                    }
                    else
                    {
                        countries = new List <Country>();
                        countries.Add(country);
                        groupedCountries[country.continent] = countries;
                    }
                }
            }

            List <string> continents = new List <string>(groupedCountries.Keys);

            for (int k = 0; k < continents.Count; k++)
            {
                string continent = continents[k];
                int    count     = groupedCountries[continent].Count;
                if (count > max)
                {
                    // Take first country and merge with first neighbour
                    for (int j = 0; j < count; j++)
                    {
                        Country country        = groupedCountries[continent][j];
                        int     countryIndex   = map.GetCountryIndex(country);
                        int     neighbourCount = country.mainRegion.neighbours.Count;
                        if (neighbourCount > 0)
                        {
                            int     randomNeighbour = Random.Range(0, neighbourCount - 1);
                            Region  otherRegion     = country.mainRegion.neighbours[randomNeighbour];
                            Country otherCountry    = (Country)otherRegion.entity;
                            if (otherCountry.continent.Equals(continent))
                            {
                                if (map.CountryTransferCountryRegion(countryIndex, otherRegion, false))
                                {
                                    countryChanges    = true;
                                    provinceChanges   = true;
                                    cityChanges       = true;
                                    mountPointChanges = true;
                                    repeat            = true;
                                    return;
                                }
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Creates a new country based on a given region. Existing region is removed from its source entity.
        /// </summary>
        /// <param name="region">Region.</param>
        public void CountryCreate(Region region)
        {
            // Remove region from source entity
            IAdminEntity entity = region.entity;

            entity.regions.Remove(region);
            Country country;

            // Refresh entity definition
            if (region.entity is Country)
            {
                int countryIndex = _map.GetCountryIndex((Country)region.entity);
                country = _map.countries[countryIndex];
                _map.RefreshCountryGeometry(country);
            }
            else
            {
                int provinceIndex = map.GetProvinceIndex((Province)region.entity);
                country = _map.countries[_map.provinces[provinceIndex].countryIndex];
                _map.RefreshProvinceGeometry(provinceIndex);
            }

            // Create the new country
            string  uniqueName = GetCountryUniqueName(country.name);
            Country newCountry = new Country(uniqueName, country.continent, map.GetUniqueId(new List <IExtendableAttribute>(map.countries)));

            if (entity is Country)
            {
                newCountry.regions.Add(region);
            }
            else
            {
                Region newRegion = new Region(newCountry, 0);
                newRegion.UpdatePointsAndRect(region.points);
                newCountry.regions.Add(newRegion);
            }
            countryIndex       = map.CountryAdd(newCountry);
            countryRegionIndex = 0;
            lastCountryCount   = -1;
            GUICountryName     = "";
            ReloadCountryNames();
            countryChanges = true;

            // Update cities
            List <City> cities = _map.GetCities(region);

            if (cities.Count > 0)
            {
                for (int k = 0; k < cities.Count; k++)
                {
                    if (cities [k].countryIndex != countryIndex)
                    {
                        cities [k].countryIndex = countryIndex;
                        cityChanges             = true;
                    }
                }
            }

            // Update mount points
            List <MountPoint> mp = _map.GetMountPoints(region);

            if (mp.Count > 0)
            {
                for (int k = 0; k < mp.Count; k++)
                {
                    if (mp [k].countryIndex != countryIndex)
                    {
                        mp [k].countryIndex = countryIndex;
                        mountPointChanges   = true;
                    }
                }
            }

            // Transfer any contained province
            if (entity is Country)
            {
                List <Province> provinces = _map.GetProvinces(region);
                for (int k = 0; k < provinces.Count; k++)
                {
                    Province prov = provinces[k];
                    if (prov.regions == null)
                    {
                        _map.ReadProvincePackedString(prov);
                    }
                    if (prov.regions == null)
                    {
                        continue;
                    }
                    if (_map.CountryTransferProvinceRegion(countryIndex, prov.mainRegion, false))
                    {
                        provinceChanges = true;
                    }
                }
            }

            map.Redraw();
            CountryRegionSelect();
        }
Exemplo n.º 3
0
        void DrawUnityStandardTextLabels()
        {
            ResetDefaultCountryLabelOffset();

            if (meshRects == null)
            {
                meshRects = new List <MeshRect>(_countries.Length);
            }
            else
            {
                meshRects.Clear();
            }
            float mw = mapWidth;
            float mh = mapHeight;

            for (int countryIndex = 0; countryIndex < _countries.Length; countryIndex++)
            {
                Country country = _countries[countryIndex];
                if (country.hidden || !country.labelVisible || country.mainRegionIndex < 0 || country.mainRegionIndex >= country.regions.Count)
                {
                    continue;
                }

                Vector2 center = new Vector2(country.center.x * mapWidth, country.center.y * mh) + country.labelOffset;
                center += GetDefaultCountryLabelOffset(countryIndex);

                Region region = country.regions[country.mainRegionIndex];

                // Adjusts country name length
                string countryName = country.customLabel != null ? country.customLabel : country.name.ToUpper();
                bool   introducedCarriageReturn = false;
                if (countryName.Length > 15)
                {
                    countryName = BreakOneLineString(countryName);
                    introducedCarriageReturn = true;
                }

                // add caption
                GameObject textObj;
                TextMesh   tm;
                Renderer   tmRenderer;
                TextMesh   tmShadow = null;
                if (country.labelTextMeshGO == null)
                {
                    Color labelColor = country.labelColorOverride ? country.labelColor : _countryLabelsColor;
                    Font  customFont = country.labelFontOverride ?? labelsFont;
                    if ((object)customFont == null)
                    {
                        continue;
                    }
                    Material customLabelShadowMaterial = country.labelFontShadowMaterial ?? labelsShadowMaterial;
                    tm      = Drawing.CreateText(countryName, null, center, customFont, labelColor, _showLabelsShadow, customLabelShadowMaterial, _countryLabelsShadowColor, out tmShadow);
                    textObj = tm.gameObject;
                    country.labelTextMesh   = tm;
                    country.labelTextMeshGO = tm.gameObject;
                    tmRenderer = textObj.GetComponent <Renderer>();
                    Bounds bounds = tmRenderer.bounds;
                    country.labelMeshWidth  = bounds.size.x;
                    country.labelMeshHeight = bounds.size.y;
                    country.labelMeshCenter = center;
                    textObj.transform.SetParent(textRoot.transform, false);
                    textObj.transform.localPosition = center;
                    textObj.layer = textRoot.gameObject.layer;
                    if (_showLabelsShadow)
                    {
                        country.labelShadowTextMesh = tmShadow; //textObj.transform.Find ("shadow").GetComponent<TextMesh> ();
                        country.labelShadowTextMesh.gameObject.layer = textObj.layer;
                    }
                }
                else
                {
                    tm      = country.labelTextMesh;
                    textObj = tm.gameObject;
                    textObj.transform.localPosition = center;
                    tmRenderer = textObj.GetComponent <Renderer>();
                }

                float meshWidth  = country.labelMeshWidth;
                float meshHeight = country.labelMeshHeight;

                // adjusts caption
                Rect  rect = new Rect(region.rect2D.xMin * mw, region.rect2D.yMin * mh, region.rect2D.width * mw, region.rect2D.height * mh);
                float absoluteHeight;
                if (country.labelRotation > 0)
                {
                    textObj.transform.localRotation = Quaternion.Euler(0, 0, country.labelRotation);
                    absoluteHeight = Mathf.Min(rect.height * _countryLabelsSize, rect.width);
                }
                else if (rect.height > rect.width * 1.45f)
                {
                    float angle;
                    if (rect.height > rect.width * 1.5f)
                    {
                        angle = 90;
                    }
                    else
                    {
                        angle = Mathf.Atan2(rect.height, rect.width) * Mathf.Rad2Deg;
                    }
                    textObj.transform.localRotation = Quaternion.Euler(0, 0, angle);
                    absoluteHeight = Mathf.Min(rect.width * _countryLabelsSize, rect.height);
                }
                else
                {
                    absoluteHeight = Mathf.Min(rect.height * _countryLabelsSize, rect.width);
                }

                // adjusts scale to fit width in rect
                float adjustedMeshHeight = introducedCarriageReturn ? meshHeight * 0.5f : meshHeight;
                float scale = absoluteHeight / adjustedMeshHeight;
                if (country.labelFontSizeOverride)
                {
                    scale = country.labelFontSize;
                }
                else
                {
                    float desiredWidth = meshWidth * scale;
                    if (desiredWidth > rect.width)
                    {
                        scale = rect.width / meshWidth;
                    }
                    if (adjustedMeshHeight * scale < _countryLabelsAbsoluteMinimumSize)
                    {
                        scale = _countryLabelsAbsoluteMinimumSize / adjustedMeshHeight;
                    }
                }

                // stretchs out the caption
                float  displayedMeshWidth  = meshWidth * scale;
                float  displayedMeshHeight = meshHeight * scale;
                string wideName;
                int    times = Mathf.FloorToInt(rect.width * 0.45f / (meshWidth * scale));
                if (times > 10)
                {
                    times = 10;
                }
                if (times > 0)
                {
                    StringBuilder sb     = new StringBuilder();
                    string        spaces = new string(' ', times * 2);
                    for (int c = 0; c < countryName.Length; c++)
                    {
                        sb.Append(countryName[c]);
                        if (c < countryName.Length - 1)
                        {
                            sb.Append(spaces);
                        }
                    }
                    wideName = sb.ToString();
                }
                else
                {
                    wideName = countryName;
                }

                if (tm.text.Length != wideName.Length)
                {
                    tm.text             = wideName;
                    displayedMeshWidth  = tmRenderer.bounds.size.x * scale;
                    displayedMeshHeight = tmRenderer.bounds.size.y * scale;
                    if (_showLabelsShadow)
                    {
                        tmShadow.text = wideName;
                    }
                }

                // apply scale
                textObj.transform.localScale = new Vector3(scale, scale, 1);

                // Save mesh rect for overlapping checking
                if (country.labelOffset == Misc.Vector2zero)
                {
                    float    xMin = center.x - displayedMeshWidth * 0.5f;
                    float    yMin = center.y - displayedMeshHeight * 0.5f;
                    float    xMax = xMin + displayedMeshWidth;
                    float    yMax = yMin + displayedMeshHeight;
                    MeshRect mr   = new MeshRect(countryIndex, new Vector4(xMin, yMin, xMax, yMax));
                    meshRects.Add(mr);
                }
            }

            // Simple-fast overlapping checking
            int  cont        = 0;
            bool needsResort = true;

            int meshRectsCount = meshRects.Count;

            while (needsResort && ++cont < 10)
            {
                meshRects.Sort(overlapComparer);
                needsResort = false;
                for (int c = 1; c < meshRectsCount; c++)
                {
                    Vector4 r1 = meshRects[c].rect;
                    for (int prevc = c - 1; prevc >= 0; prevc--)
                    {
                        Vector4 r2       = meshRects[prevc].rect;
                        bool    overlaps = !(r2.x > r1.z || r2.z <r1.x || r2.y> r1.w || r2.w < r1.y);
                        if (overlaps)
                        {
                            needsResort = true;
                            int        thisCountryIndex = meshRects[c].entityIndex;
                            Country    country          = _countries[thisCountryIndex];
                            GameObject thisLabel        = country.labelTextMeshGO;

                            // displaces this label
                            float offsety = r1.w - r2.y;
                            offsety = Mathf.Min(country.regions[country.mainRegionIndex].rect2D.height * mh * 0.35f, offsety);
                            thisLabel.transform.localPosition = new Vector3(country.labelMeshCenter.x, country.labelMeshCenter.y - offsety, thisLabel.transform.localPosition.z);
                            float width  = r1.z - r1.x;
                            float height = r1.w - r1.y;
                            float xMin   = thisLabel.transform.localPosition.x - width * 0.5f;
                            float yMin   = thisLabel.transform.localPosition.y - height * 0.5f;
                            float xMax   = xMin + width;
                            float yMax   = yMin + height;
                            r1 = new Vector4(xMin, yMin, xMax, yMax);
                            meshRects[c].rect = r1;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Exports the geographic data in packed string format with reduced quality.
        /// </summary>
        public string GetCountryGeoDataLowQuality()
        {
            // step 1: duplicate data
            IAdminEntity[] entities;
            if (editingMode == EDITING_MODE.COUNTRIES)
            {
                entities = map.countries;
            }
            else
            {
                entities = map.provinces;
            }
            List <IAdminEntity> entities1 = new List <IAdminEntity>(entities);

            for (int k = 0; k < entities1.Count; k++)
            {
                entities1[k].regions = new List <Region>(entities1[k].regions);
                for (int r = 0; r < entities[k].regions.Count; r++)
                {
                    entities1[k].regions[r].points = new List <Vector2>(entities1[k].regions[r].points).ToArray();
                }
            }
            // step 2: ensure near points between neighbours
            float MAX_DIST = 0.00000001f;

            //			int join = 0;
            for (int k = 0; k < entities1.Count; k++)
            {
                for (int r = 0; r < entities1[k].regions.Count; r++)
                {
                    Region region1 = entities1[k].regions[r];
                    for (int p = 0; p < entities1[k].regions[r].points.Length; p++)
                    {
                        // Search near points
                        for (int k2 = 0; k2 < region1.neighbours.Count; k2++)
                        {
                            for (int r2 = 0; r2 < entities1[k2].regions.Count; r2++)
                            {
                                Region region2 = entities1[k2].regions[r2];
                                for (int p2 = 0; p2 < entities1[k2].regions[r2].points.Length; p2++)
                                {
                                    float dist = (region1.points[p].x - region2.points[p2].x) * (region1.points[p].x - region2.points[p2].x) +
                                                 (region1.points[p].y - region2.points[p2].y) * (region1.points[p].y - region2.points[p2].y);
                                    if (dist < MAX_DIST)
                                    {
                                        region2.points[p2] = region1.points[p];
                                        //										join++;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // step 2: simplify
            Dictionary <Vector2, bool> frontiersHit = new Dictionary <Vector2, bool>();
            List <IAdminEntity>        entities2 = new List <IAdminEntity>(entities1.Count);
            int   savings = 0, totalPoints = 0;
            float FACTOR = 1000f;

            for (int k = 0; k < entities1.Count; k++)
            {
                IAdminEntity refEntity = entities1[k];
                IAdminEntity newEntity;
                if (refEntity is Country)
                {
                    newEntity = new Country(refEntity.name, ((Country)refEntity).continent, map.GetUniqueId(new List <IExtendableAttribute>(map.countries)));
                }
                else
                {
                    newEntity = new Province(refEntity.name, ((Province)refEntity).countryIndex, map.GetUniqueId(new List <IExtendableAttribute>(map.provinces)));
                }
                for (int r = 0; r < refEntity.regions.Count; r++)
                {
                    Region region    = refEntity.regions[r];
                    int    numPoints = region.points.Length;
                    totalPoints += numPoints;
                    List <Vector2> points = new List <Vector2>(numPoints);
                    frontiersHit.Clear();

                    Vector3[] blockyPoints = new Vector3[numPoints];
                    for (int p = 0; p < numPoints; p++)
                    {
                        blockyPoints[p] = new Vector2(Mathf.RoundToInt(region.points[p].x * FACTOR) / FACTOR, Mathf.RoundToInt(region.points[p].y * FACTOR) / FACTOR);
                    }

                    points.Add(region.points[0] * WMSK.MAP_PRECISION);
                    for (int p = 1; p < numPoints - 1; p++)
                    {
                        if (blockyPoints[p - 1].y == blockyPoints[p].y && blockyPoints[p].y == blockyPoints[p + 1].y ||
                            blockyPoints[p - 1].x == blockyPoints[p].x && blockyPoints[p].x == blockyPoints[p + 1].x)
                        {
                            savings++;
                            continue;
                        }
                        if (!frontiersHit.ContainsKey(blockyPoints[p]))                           // add neighbour references
                        {
                            frontiersHit.Add(blockyPoints[p], true);
                            points.Add(region.points[p] * WMSK.MAP_PRECISION);
                        }
                        else
                        {
                            savings++;
                        }
                    }
                    points.Add(region.points[numPoints - 1] * WMSK.MAP_PRECISION);
                    if (points.Count >= 5)
                    {
                        Region newRegion = new Region(newEntity, newEntity.regions.Count);
                        newRegion.points = points.ToArray();
                        newEntity.regions.Add(newRegion);
                    }
                }
                if (newEntity.regions.Count > 0)
                {
                    entities2.Add(newEntity);
                }
            }

            Debug.Log(savings + " points removed of " + totalPoints + " (" + (((float)savings / totalPoints) * 100.0f).ToString("F1") + "%)");

            StringBuilder sb = new StringBuilder();

            for (int k = 0; k < entities2.Count; k++)
            {
                IAdminEntity entity = entities2[k];
                if (k > 0)
                {
                    sb.Append("|");
                }
                sb.Append(entity.name + "$");
                if (entity is Country)
                {
                    sb.Append(((Country)entity).continent + "$");
                }
                else
                {
                    sb.Append(map.countries[((Province)entity).countryIndex].name + "$");
                }
                for (int r = 0; r < entity.regions.Count; r++)
                {
                    if (r > 0)
                    {
                        sb.Append("*");
                    }
                    Region region = entity.regions[r];
                    for (int p = 0; p < region.points.Length; p++)
                    {
                        if (p > 0)
                        {
                            sb.Append(";");
                        }
                        Vector2 point = region.points[p];
                        sb.Append(point.x.ToString() + ",");
                        sb.Append(point.y.ToString());
                    }
                }
            }
            return(sb.ToString());
        }
Exemplo n.º 5
0
        void DrawTextMeshProLabels()
        {
            if (labelsFontTMPro == null)
            {
                ReloadFont();
                if (labelsFontTMPro == null)
                {
                    return;
                }
            }

            float mw = mapWidth;
            float mh = mapHeight;

            if (labelsCurve == null || labelsCurve.Length == 0)
            {
                ComputeLabelsCurve();
            }

            Vector2 center = Misc.Vector2zero;

            for (int countryIndex = 0; countryIndex < _countries.Length; countryIndex++)
            {
                Country country = _countries[countryIndex];
                if (country.hidden || !country.labelVisible || country.mainRegionIndex < 0 || country.mainRegionIndex >= country.regions.Count)
                {
                    continue;
                }

                Region region = country.regions[country.mainRegionIndex];
                if (!ComputeCurvedLabelData(region))
                {
                    continue;
                }

                if (country.labelOffset.x != 0 || country.labelOffset.y != 0)
                {
                    center = country.center + country.labelOffset;
                }
                else
                {
                    FastVector.Average(ref region.curvedLabelInfo.axisStart, ref region.curvedLabelInfo.axisEnd, ref center); // (curvedLabel.axisStart + curvedLabel.axisEnd) * 0.5f;
                }
                center.x *= mw;
                center.y *= mh;

                // Adjusts country name length
                string countryName = country.customLabel != null ? country.customLabel : country.name.ToUpper();
                if (countryName.Length == 0)
                {
                    continue;
                }

                if (countryName.Length > 15)
                {
                    countryName = BreakOneLineString(countryName);
                }

                // add caption
                GameObject  textObj;
                TextMeshPro tm;
                Color       labelColor = country.labelColorOverride ? country.labelColor : _countryLabelsColor;
                if (country.labelTextMeshGO == null)
                {
                    // create base text
                    textObj            = new GameObject(countryName);
                    textObj.hideFlags  = HideFlags.DontSave;
                    textObj.hideFlags |= HideFlags.HideInHierarchy;
                    tm                       = textObj.AddComponent <TextMeshPro>();
                    tm.alignment             = TextAlignmentOptions.Center;
                    tm.enableWordWrapping    = false;
                    country.labelTextMeshPro = tm;
                    country.labelTextMeshGO  = tm.gameObject;
                    textObj.transform.SetParent(textRoot.transform, false);
                    textObj.layer = textRoot.gameObject.layer;
                }
                else
                {
                    tm      = (TextMeshPro)country.labelTextMeshPro;
                    textObj = tm.gameObject;
                    textObj.transform.localPosition = center;
                }
                tm.font  = (TMP_FontAsset)labelsFontTMPro;
                tm.color = labelColor;

                Material fontMat;
                if (_countryLabelsEnableAutomaticFade)
                {
                    // By using fontMaterial we're forcing to instantiate the material which will enable individual colors and alpha
                    fontMat           = tm.fontMaterial;
                    fontMat.hideFlags = HideFlags.DontSave;
                }
                else
                {
                    fontMat = tm.fontSharedMaterial;
                }

                if (_countryLabelsOutlineWidth > 0)
                {
                    fontMat.SetColor("_OutlineColor", _countryLabelsOutlineColor);
                    fontMat.SetFloat("_OutlineWidth", _countryLabelsOutlineWidth);
                    fontMat.EnableKeyword("OUTLINE_ON");
                }
                else
                {
                    fontMat.DisableKeyword("OUTLINE_ON");
                }

                tm.text = countryName;
                textObj.transform.localPosition = center;
                country.labelMeshWidth          = tm.preferredWidth;
                country.labelMeshHeight         = tm.preferredHeight;
                country.labelMeshCenter         = center;

                float meshWidth  = country.labelMeshWidth;
                float meshHeight = country.labelMeshHeight;

                // adjusts scale to fit in region
                Vector2 axis = region.curvedLabelInfo.axisEnd - region.curvedLabelInfo.axisStart;
                float   scale;
                if (country.labelFontSizeOverride)
                {
                    scale = country.labelFontSize;
                }
                else
                {
                    // axisWidth represents the length of the label along the longest axis
                    float axisWidth = new Vector2(axis.x * mw, axis.y * mh).magnitude;
                    // axisAveragedWidth represents the average length of the region (used as a maximum height for the label)
                    float axisAveragedThickness = new Vector2(region.curvedLabelInfo.axisAveragedThickness.x * mw, region.curvedLabelInfo.axisAveragedThickness.y * mh).magnitude;
                    float scaleheight           = axisAveragedThickness / meshHeight;
                    float scaleWidth            = axisWidth / meshWidth;
                    scale = Mathf.Min(scaleWidth, scaleheight);
                    if (meshHeight * scale < _countryLabelsAbsoluteMinimumSize)
                    {
                        scale = _countryLabelsAbsoluteMinimumSize / meshHeight;
                    }
                    scale *= _countryLabelsSize * 2f;
                }

                // apply scale
                textObj.transform.localScale = new Vector3(scale, scale, 1);

                // Apply axis rotation or user defined rotation
                if (country.labelRotation > 0)
                {
                    textObj.transform.localRotation = Quaternion.Euler(0, 0, country.labelRotation);
                }
                else
                {
                    textObj.transform.localRotation = Quaternion.Euler(0, 0, region.curvedLabelInfo.axisAngle);
                }

                if (_countryLabelsCurvature > 0)
                {
                    // Compute fitting curve
                    tm.havePropertiesChanged = true; // Need to force the TextMeshPro Object to be updated.
                    tm.ForceMeshUpdate();            // Generate the mesh and populate the textInfo with data we can use and manipulate.

                    TMP_TextInfo textInfo       = tm.textInfo;
                    int          characterCount = textInfo.characterCount;

                    float boundsMinX = tm.bounds.min.x;
                    float boundsMaxX = tm.bounds.max.x;
                    // map bounds to axis length
                    float axisLengthWS = new Vector2(axis.x * mw / scale, axis.y * mh / scale).magnitude;
                    float boundsLength = boundsMaxX - boundsMinX;
                    float boundsMid    = (boundsMaxX + boundsMinX) * 0.5f;
                    boundsMinX = boundsMid - (boundsMid - boundsMinX) * axisLengthWS / boundsLength;
                    boundsMaxX = boundsMid + (boundsMaxX - boundsMid) * axisLengthWS / boundsLength;

                    float curveMultiplier = new Vector2(region.curvedLabelInfo.axisMidDisplacement.x * mw / scale, region.curvedLabelInfo.axisMidDisplacement.y * mh / scale).magnitude *_countryLabelsCurvature;
                    // check if axisAveragedThickness is above or below axis
                    Vector2 a   = axis * 0.5f + region.curvedLabelInfo.axisMidDisplacement;
                    float   dot = a.x * -axis.y + a.y * axis.x;
                    if (dot < 0)
                    {
                        curveMultiplier *= -1f;
                    }
                    float boundsWidth = boundsMaxX - boundsMinX;

                    // Get the index of the mesh used by this character.
                    int       materialIndex = textInfo.characterInfo[0].materialReferenceIndex;
                    Vector3[] vertices      = textInfo.meshInfo[materialIndex].vertices;

                    for (int i = 0; i < characterCount; i++)
                    {
                        if (!textInfo.characterInfo[i].isVisible)
                        {
                            continue;
                        }

                        int vertexIndex = textInfo.characterInfo[i].vertexIndex;

                        // Compute the baseline mid point for each character
                        Vector2 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine);
                        if (float.IsNaN(offsetToMidBaseline.x) || float.IsNaN(offsetToMidBaseline.y))
                        {
                            continue;
                            //offsetToMidBaseline.x = offsetToMidBaseline.y = 0;
                        }

                        // Apply offset to adjust our pivot point.
                        vertices[vertexIndex + 0].x -= offsetToMidBaseline.x;
                        vertices[vertexIndex + 0].y -= offsetToMidBaseline.y;
                        vertices[vertexIndex + 1].x -= offsetToMidBaseline.x;
                        vertices[vertexIndex + 1].y -= offsetToMidBaseline.y;
                        vertices[vertexIndex + 2].x -= offsetToMidBaseline.x;
                        vertices[vertexIndex + 2].y -= offsetToMidBaseline.y;
                        vertices[vertexIndex + 3].x -= offsetToMidBaseline.x;
                        vertices[vertexIndex + 3].y -= offsetToMidBaseline.y;

                        // Compute the angle of rotation for each character based on the animation curve
                        float       x0   = (offsetToMidBaseline.x - boundsMinX) / boundsWidth; // Character's position relative to the bounds of the mesh.
                        float       x1   = x0 + 0.01f;
                        const float minT = 0.0f;
                        const float maxT = 0.9999f;
                        if (x0 < minT)
                        {
                            x0 = minT;
                        }
                        else if (x0 > maxT)
                        {
                            x0 = maxT;
                        }
                        int   ix0 = (int)(x0 * labelsCurve.Length);
                        float y0  = labelsCurve[ix0] * curveMultiplier;
                        if (x1 < minT)
                        {
                            x1 = minT;
                        }
                        else if (x1 > maxT)
                        {
                            x1 = maxT;
                        }
                        int   ix1 = (int)(x1 * labelsCurve.Length);
                        float y1  = labelsCurve[ix1] * curveMultiplier;

                        Vector2 tangent = new Vector2(x1 * boundsWidth + boundsMinX - offsetToMidBaseline.x, y1 - y0);
                        dot = Mathf.Acos(tangent.normalized.x) * Mathf.Rad2Deg;
                        float angle = tangent.y > 0 ? dot : 360 - dot;

                        Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(offsetToMidBaseline.x, y0 + offsetToMidBaseline.y, 0), Quaternion.Euler(0, 0, angle), Misc.Vector3one);

                        vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]);
                        vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]);
                        vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]);
                        vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]);
                    }

                    // Upload the mesh with the revised information
                    tm.UpdateVertexData();
                }
                country.labelMeshWidth  = tm.bounds.size.x;
                country.labelMeshHeight = tm.bounds.size.y;

                //																GameObject sphere3 = GameObject.CreatePrimitive (PrimitiveType.Sphere);
                //																sphere3.name = "Axis Middle";
                //																sphere3.transform.SetParent (o.transform, true);
                //																sphere3.transform.localPosition = (curvedLabel.axisStart + curvedLabel.axisEnd) * 0.5f;
                //																sphere3.transform.localScale *= 0.3f;
                //
                //																GameObject sphere4 = GameObject.CreatePrimitive (PrimitiveType.Sphere);
                //																sphere4.name = "avgAxisPoint";
                //																sphere4.transform.SetParent (o.transform, true);
                //																sphere4.transform.localPosition = (curvedLabel.axisStart + curvedLabel.axisEnd) * 0.5f + curvedLabel.axisMidDisplacement;
                //																sphere4.GetComponent<Renderer> ().material.color = Color.red;
                //																sphere4.transform.localScale *= 0.2f;
            }

            StartCoroutine(RepositionTexts());
        }