/// <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 cIndex = _map.GetCountryIndex((Country)region.entity); country = _map.countries [cIndex]; _map.RefreshCountryGeometry(cIndex); } else { int provinceIndex = map.GetProvinceIndex((Province)region.entity); country = _map.countries [_map.provinces [provinceIndex].countryIndex]; _map.RefreshProvinceGeometry(provinceIndex); } // Create the new country indeed string uniqueName = GetCountryUniqueName(country.name); Country newCountry = new Country(uniqueName, country.continent); 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; map.RefreshCountryDefinition(countryIndex, null); lastCountryCount = -1; GUICountryName = ""; ReloadCountryNames(); countryChanges = true; // Update cities List <City> cities = _map.GetCities(region); if (cities.Count > 0) { cityChanges = true; for (int k = 0; k < cities.Count; k++) { cities [k].countryIndex = countryIndex; } } // Update mount points List <MountPoint> mp = _map.GetMountPoints(region); if (mp.Count > 0) { mountPointChanges = true; for (int k = 0; k < mp.Count; k++) { mp [k].countryIndex = countryIndex; } } // 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; } int pIndex = _map.GetProvinceIndex(prov); ProvinceTransferTo(countryIndex, pIndex); provinceChanges = true; } } map.Redraw(); CountryRegionSelect(); }
/// <summary> /// Makes one country region to annex another country /// </summary> public void CountryRegionTransferTo() { if (countryIndex < 0 || GUICountryTransferToCountryIndex < 0 || GUICountryTransferToCountryIndex >= countryNames.Length || countryRegionIndex < 0) { return; } // Get target country // recover GUI country index selection int targetCountryIndex = -1; string[] s = countryNames [GUICountryTransferToCountryIndex].Split(new char[] { '(', ')' }, System.StringSplitOptions.RemoveEmptyEntries); if (s.Length >= 2) { if (!int.TryParse(s [1], out targetCountryIndex)) { return; } } Country sourceCountry = map.countries [countryIndex]; Country targetCountry = map.countries [targetCountryIndex]; Region sourceRegion = sourceCountry.regions [countryRegionIndex]; Region targetRegion = targetCountry.regions [targetCountry.mainRegionIndex]; // Transfer all provinces records to target country if (targetCountry.provinces == null && !map.showProvinces) { map.showProvinces = true; // Forces loading of provinces map.showProvinces = false; } if (sourceCountry.provinces != null) { List <Province> destProvinces; if (targetCountry.provinces != null) { destProvinces = new List <Province> (targetCountry.provinces); } else { destProvinces = new List <Province> (); } List <Province> sourceProvinces = new List <Province> (sourceCountry.provinces); for (int k = 0; k < sourceCountry.provinces.Length; k++) { Province province = sourceCountry.provinces [k]; if (sourceRegion.Contains(province.center)) { province.countryIndex = targetCountryIndex; destProvinces.Add(province); sourceProvinces.Remove(province); provinceChanges = true; } } sourceCountry.provinces = sourceProvinces.ToArray(); targetCountry.provinces = destProvinces.ToArray(); } // Add region to target country's polygon - only if the province is touching or crossing target country frontier PolygonClipper pc = new PolygonClipper(targetRegion, sourceRegion); if (pc.OverlapsSubjectAndClipping()) { pc.Compute(PolygonOp.UNION); } else { // Add new region to country Region newCountryRegion = new Region(targetCountry, targetCountry.regions.Count); newCountryRegion.points = new List <Vector3> (sourceRegion.points).ToArray(); targetCountry.regions.Add(newCountryRegion); } // Transfer cities & mount points TransferRegionCities(countryIndex, sourceRegion, targetCountryIndex); TransferRegionMountPoints(countryIndex, sourceRegion, targetCountryIndex); // Remove region from source country sourceCountry.regions.Remove(sourceRegion); // Finish operation map.HideCountryRegionHighlights(true); map.HideProvinceRegionHighlights(true); map.RefreshCountryDefinition(countryIndex, null); map.RefreshCountryDefinition(targetCountryIndex, null); countryChanges = true; countryIndex = targetCountryIndex; countryRegionIndex = targetCountry.mainRegionIndex; CountryRegionSelect(); map.RedrawMapLabels(); }
/// <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 <Vector3> (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++; } } } } } } } // if (join>0) // Debug.Log (join + " points fused."); // 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); } else { newEntity = new Province(refEntity.name, ((Province)refEntity).countryIndex); } for (int r = 0; r < refEntity.regions.Count; r++) { Region region = refEntity.regions [r]; int numPoints = region.points.Length; totalPoints += numPoints; List <Vector3> points = new List <Vector3> (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] * WorldMap2D.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] * WorldMap2D.MAP_PRECISION); } else { savings++; } } points.Add(region.points [numPoints - 1] * WorldMap2D.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(CultureInfo.InvariantCulture) + ","); sb.Append(point.y.ToString(CultureInfo.InvariantCulture)); } } } return(sb.ToString()); }
public bool GetVertexNearSpherePos(Vector3 mapPos, out Vector2 nearPoint) { // Iterate country regions int numCountries = _map.countries.Length; Vector2 np = mapPos; float minDist = float.MaxValue; // Countries for (int c = 0; c < numCountries; c++) { Country country = _map.countries [c]; int regCount = country.regions.Count; for (int cr = 0; cr < regCount; cr++) { Region region = country.regions [cr]; int pointCount = region.points.Length; for (int p = 0; p < pointCount; p++) { float dist = (mapPos - region.points [p]).sqrMagnitude; if (dist < minDist) { minDist = dist; np = region.points [p]; } } } } // Provinces if (_map.editor.editingMode == EDITING_MODE.PROVINCES) { int numProvinces = _map.provinces.Length; for (int p = 0; p < numProvinces; p++) { Province province = _map.provinces [p]; if (province.regions == null) { _map.ReadProvincePackedString(province); } if (province.regions == null) { continue; } int regCount = province.regions.Count; for (int pr = 0; pr < regCount; pr++) { Region region = province.regions [pr]; int pointCount = region.points.Length; for (int po = 0; po < pointCount; po++) { float dist = (mapPos - region.points [po]).sqrMagnitude; if (dist < minDist) { minDist = dist; np = region.points [p]; } } } } } nearPoint = np; return(nearPoint.x != mapPos.x || nearPoint.y != mapPos.y); }
public void SplitVertically() { if (entityIndex < 0 || entityIndex >= entities.Length) { return; } IAdminEntity currentEntity = entities [entityIndex]; Region currentRegion = currentEntity.regions [regionIndex]; Vector2 center = currentRegion.center; List <Vector3> half1 = new List <Vector3> (); List <Vector3> half2 = new List <Vector3> (); int prevSide = 0; for (int k = 0; k < currentRegion.points.Length; k++) { Vector3 p = currentRegion.points [k]; if (p.x > currentRegion.center.x) { half1.Add(p); if (prevSide == -1) { half2.Add(p); } prevSide = 1; } if (p.x <= currentRegion.center.x) { half2.Add(p); if (prevSide == 1) { half1.Add(p); } prevSide = -1; } } // Setup new entity IAdminEntity newEntity; if (currentEntity is Country) { newEntity = new Country("New " + currentEntity.name, ((Country)currentEntity).continent); } else { newEntity = new Province("New " + currentEntity.name, ((Province)currentEntity).countryIndex); newEntity.regions = new List <Region> (); } EntityAdd(newEntity); // Update polygons Region newRegion = new Region(newEntity, 0); if (entities [countryIndex].center.x > center.x) { currentRegion.points = half1.ToArray(); newRegion.points = half2.ToArray(); } else { currentRegion.points = half2.ToArray(); newRegion.points = half1.ToArray(); } newEntity.regions.Add(newRegion); // Refresh old entity and selects the new if (currentEntity is Country) { map.RefreshCountryDefinition(countryIndex, highlightedRegions); countryIndex = map.countries.Length - 1; countryRegionIndex = 0; } else { map.RefreshProvinceDefinition(provinceIndex); provinceIndex = map.provinces.Length - 1; provinceRegionIndex = 0; } // Refresh lines highlightedRegions.Add(newRegion); RedrawFrontiers(); map.RedrawMapLabels(); }
/// <summary> /// Separates a province from its current country producing a new country /// </summary> public void ProvinceSeparate(string newCountryName) { if (provinceIndex < 0 || provinceIndex >= map.provinces.Length) { return; } // Remove province form source country Province province = map.provinces [provinceIndex]; Country sourceCountry = map.countries [countryIndex]; if (map.countries [countryIndex].provinces != null) { List <Province> sourceProvinces = new List <Province> (sourceCountry.provinces); int provIndex = -1; for (int k = 0; k < sourceCountry.provinces.Length; k++) { if (sourceCountry.provinces [k].name.Equals(province.name)) { provIndex = k; } } if (provIndex >= 0) { sourceProvinces.RemoveAt(provIndex); sourceCountry.provinces = sourceProvinces.ToArray(); } } // Adds province region to a new country Region regionProvince = province.regions [provinceRegionIndex]; Country targetCountry = new Country(newCountryName, sourceCountry.continent); Region region = new Region(targetCountry, 0); region.points = new List <Vector3> (regionProvince.points).ToArray(); targetCountry.regions.Add(region); map.CountryAdd(targetCountry); int targetCountryIndex = map.countries.Length - 1; map.RefreshCountryDefinition(targetCountryIndex, null); lastCountryCount = -1; // Add province to the new country if (targetCountry.provinces == null) { targetCountry.provinces = new Province[0]; } List <Province> destProvinces = new List <Province> (targetCountry.provinces); destProvinces.Add(province); targetCountry.provinces = destProvinces.ToArray(); // Apply boolean operations on country polygons Region provinceRegion = province.regions [provinceRegionIndex]; Region sourceRegion = sourceCountry.regions [sourceCountry.mainRegionIndex]; // Extract from source country - only if province is in the frontier or is crossing the country for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; otherSourceRegion.sanitized = true; } PolygonClipper pc = new PolygonClipper(sourceRegion, provinceRegion); if (pc.OverlapsSubjectAndClipping()) { sourceRegion.sanitized = false; pc.Compute(PolygonOp.DIFFERENCE); } else { // Look for other regions to substract for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; pc = new PolygonClipper(otherSourceRegion, provinceRegion); if (pc.OverlapsSubjectAndClipping()) { otherSourceRegion.sanitized = false; pc.Compute(PolygonOp.DIFFERENCE); } } } // Remove invalid regions from source country for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; if (!otherSourceRegion.sanitized && otherSourceRegion.points.Length < 5) { sourceCountry.regions.RemoveAt(k); k--; } } // Transfer cities int cityCount = map.cities.Count; for (int k = 0; k < cityCount; k++) { City city = map.cities [k]; if (city.countryIndex == countryIndex && city.province.Equals(province.name)) { city.countryIndex = targetCountryIndex; } } // Transfer mount points int mountPointCount = map.mountPoints.Count; for (int k = 0; k < mountPointCount; k++) { MountPoint mp = map.mountPoints [k]; if (mp.countryIndex == countryIndex && mp.provinceIndex == provinceIndex) { mp.countryIndex = targetCountryIndex; } } // Finish operation map.HideCountryRegionHighlights(true); map.HideProvinceRegionHighlights(true); map.RefreshCountryDefinition(province.countryIndex, null); province.countryIndex = targetCountryIndex; map.RefreshProvinceDefinition(provinceIndex); map.RefreshCountryDefinition(targetCountryIndex, null); countryChanges = true; provinceChanges = true; cityChanges = true; mountPointChanges = true; ProvinceRegionSelect(); }
/// <summary> /// Makes one country to annex another /// </summary> public void CountryTransferTo() { if (countryIndex < 0 || GUICountryTransferToCountryIndex < 0 || GUICountryTransferToCountryIndex >= countryNames.Length) { return; } // Get target country // recover GUI country index selection int targetCountryIndex = -1; string[] s = countryNames [GUICountryTransferToCountryIndex].Split(new char[] { '(', ')' }, System.StringSplitOptions.RemoveEmptyEntries); if (s.Length >= 2) { if (!int.TryParse(s [1], out targetCountryIndex)) { return; } } // Transfer all provinces records to target country Country sourceCountry = map.countries [countryIndex]; Country targetCountry = map.countries [targetCountryIndex]; //MAX! mergeCountryData(sourceCountry, targetCountry); dataChanges = true; ndChanges = true; if (targetCountry.provinces == null && !map.showProvinces) { map.showProvinces = true; // Forces loading of provinces map.showProvinces = false; } if (sourceCountry.provinces != null) { List <Province> destProvinces; if (targetCountry.provinces != null) { destProvinces = new List <Province> (targetCountry.provinces); } else { destProvinces = new List <Province> (); } for (int k = 0; k < sourceCountry.provinces.Length; k++) { Province province = sourceCountry.provinces [k]; province.countryIndex = targetCountryIndex; destProvinces.Add(province); } targetCountry.provinces = destProvinces.ToArray(); } // Add main region of the source country to target if they are joint Region sourceRegion = sourceCountry.regions [sourceCountry.mainRegionIndex]; Region targetRegion = targetCountry.regions [targetCountry.mainRegionIndex]; //MAX! if (sourceRegion.neighbours.Contains(targetRegion)) { // Add region to target country's polygon - only if the province is touching or crossing target country frontier PolygonClipper pc = new PolygonClipper(targetRegion, sourceRegion); if (pc.OverlapsSubjectAndClipping()) { pc.Compute(PolygonOp.UNION); } //MAX! } else { // Add new region to country Region newCountryRegion = new Region(targetCountry, targetCountry.regions.Count); newCountryRegion.points = new List <Vector3> (sourceRegion.points).ToArray(); targetCountry.regions.Add(newCountryRegion); } // Transfer additional regions if (sourceCountry.regions.Count > 1) { List <Region> targetRegions = new List <Region> (targetCountry.regions); for (int k = 0; k < sourceCountry.regions.Count; k++) { if (k != sourceCountry.mainRegionIndex) { targetRegions.Add(sourceCountry.regions [k]); } } targetCountry.regions = targetRegions; } //MAX! if (!map.showCities && map.cities == null) { map.ReadCitiesPackedString(); } // Transfer cities & mount points TransferCities(countryIndex, targetCountryIndex); TransferMountPoints(countryIndex, targetCountryIndex); // Finish operation map.HideCountryRegionHighlights(true); map.HideProvinceRegionHighlights(true); map.CountryDelete(countryIndex, false); map.RefreshCountryDefinition(targetCountryIndex, null); countryChanges = true; provinceChanges = true; countryIndex = targetCountryIndex; countryRegionIndex = targetCountry.mainRegionIndex; CountryRegionSelect(); map.RedrawMapLabels(); }
/// <summary> /// Deletes current region or province if this was the last region /// </summary> public void ProvinceDelete() { if (provinceIndex < 0 || provinceIndex >= map.provinces.Length) { return; } // Apply boolean operations on country polygons Province province = map.provinces [provinceIndex]; Region provinceRegion = province.regions [provinceRegionIndex]; Country sourceCountry = map.countries [countryIndex]; // Extract from source country - only if province is in the frontier or is crossing the country for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; otherSourceRegion.sanitized = true; } for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; PolygonClipper pc = new PolygonClipper(otherSourceRegion, provinceRegion); if (pc.OverlapsSubjectAndClipping()) { otherSourceRegion.sanitized = false; pc.Compute(PolygonOp.DIFFERENCE); } } // Remove invalid regions from source country for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; if (!otherSourceRegion.sanitized && otherSourceRegion.points.Length < 5) { sourceCountry.regions.RemoveAt(k); k--; } } // Remove it from the country array List <Province> newProvinces = new List <Province> (map.countries [countryIndex].provinces.Length - 1); for (int k = 0; k < map.countries [countryIndex].provinces.Length; k++) { if (!map.countries [countryIndex].provinces [k].name.Equals(GUIProvinceName)) { newProvinces.Add(map.countries [countryIndex].provinces [k]); } } map.countries [countryIndex].provinces = newProvinces.ToArray(); // Remove from the global array newProvinces = new List <Province> (map.provinces.Length - 1); for (int k = 0; k < map.provinces.Length; k++) { if (k != provinceIndex) { newProvinces.Add(map.provinces [k]); } } map.provinces = newProvinces.ToArray(); // Finish operation map.HideCountryRegionHighlights(true); map.HideProvinceRegionHighlights(true); map.RefreshCountryDefinition(countryIndex, null); ClearProvinceSelection(); map.OptimizeFrontiers(); map.Redraw(); countryChanges = true; provinceChanges = true; CountryRegionSelect(); }
/// <summary> /// Used internally by the Map Editor. It will recalculate de boundaries and optimize frontiers based on new data of provinces array /// </summary> public void RefreshProvinceGeometry(int provinceIndex) { lastProvinceLookupCount = -1; if (provinceIndex < 0 || provinceIndex >= provinces.Length) { return; } float maxVol = 0; Vector2 minProvince = Misc.Vector2one * 10; Vector2 maxProvince = -minProvince; Province province = provinces [provinceIndex]; if (province.regions == null) { ReadProvincePackedString(province); } int regionCount = province.regions.Count; for (int r = 0; r < regionCount; r++) { Region provinceRegion = province.regions [r]; provinceRegion.entity = province; // just in case one country has been deleted provinceRegion.regionIndex = r; // just in case a region has been deleted int coorCount = provinceRegion.points.Length; Vector3 min = Misc.Vector3one * 10; Vector3 max = -min; for (int c = 0; c < coorCount; c++) { float x = provinceRegion.points [c].x; float y = provinceRegion.points [c].y; if (x < min.x) { min.x = x; } if (x > max.x) { max.x = x; } if (y < min.y) { min.y = y; } if (y > max.y) { max.y = y; } } Vector3 normRegionCenter = (min + max) * 0.5f; provinceRegion.center = normRegionCenter; // Calculate country bounding rect if (min.x < minProvince.x) { minProvince.x = min.x; } if (min.y < minProvince.y) { minProvince.y = min.y; } if (max.x > maxProvince.x) { maxProvince.x = max.x; } if (max.y > maxProvince.y) { maxProvince.y = max.y; } provinceRegion.rect2D = new Rect(min.x, min.y, Math.Abs(max.x - min.x), Mathf.Abs(max.y - min.y)); float vol = (max - min).sqrMagnitude; if (vol > maxVol) { maxVol = vol; province.mainRegionIndex = r; province.center = provinceRegion.center; } } province.regionsRect2D = new Rect(minProvince.x, minProvince.y, Math.Abs(maxProvince.x - minProvince.x), Mathf.Abs(maxProvince.y - minProvince.y)); }
bool DrawProvinces(List <Country> targetCountries, bool forceRefresh) { // optimize required lines if (frontiersPoints == null) { frontiersPoints = new List <Vector3> (1000000); } else { frontiersPoints.Clear(); } if (frontiersCacheHit == null) { frontiersCacheHit = new Dictionary <double, Region> (500000); } else { frontiersCacheHit.Clear(); } for (int c = 0; c < targetCountries.Count; c++) { Country targetCountry = targetCountries [c]; if (targetCountry.provinces == null) { continue; } for (int p = 0; p < targetCountry.provinces.Length; p++) { Province province = targetCountry.provinces [p]; if (province.regions == null) // read province data the first time we need it { ReadProvincePackedString(province); } for (int r = 0; r < province.regions.Count; r++) { Region region = province.regions [r]; region.entity = province; region.regionIndex = r; region.neighbours.Clear(); int numPoints = region.points.Length - 1; for (int i = 0; i < numPoints; i++) { Vector3 p0 = region.points [i]; Vector3 p1 = region.points [i + 1]; double v = (p0.x + p1.x) + MAP_PRECISION * (p0.y + p1.y); if (frontiersCacheHit.ContainsKey(v)) { Region neighbour = frontiersCacheHit [v]; if (neighbour != region) { if (!region.neighbours.Contains(neighbour)) { region.neighbours.Add(neighbour); neighbour.neighbours.Add(region); } } } else { frontiersCacheHit.Add(v, region); frontiersPoints.Add(p0); frontiersPoints.Add(p1); } } // Close the polygon frontiersPoints.Add(region.points [numPoints]); frontiersPoints.Add(region.points [0]); } } } int meshGroups = (frontiersPoints.Count / 65000) + 1; int meshIndex = -1; int[][] provincesIndices = new int[meshGroups][]; Vector3[][] provincesBorders = new Vector3[meshGroups][]; for (int k = 0; k < frontiersPoints.Count; k += 65000) { int max = Mathf.Min(frontiersPoints.Count - k, 65000); provincesBorders [++meshIndex] = new Vector3[max]; provincesIndices [meshIndex] = new int[max]; for (int j = k; j < k + max; j++) { provincesBorders [meshIndex] [j - k] = frontiersPoints [j]; provincesIndices [meshIndex] [j - k] = j - k; } } // Create province layer if needed if (provincesObj != null) { DestroyImmediate(provincesObj); } provincesObj = new GameObject("Provinces"); provincesObj.hideFlags = HideFlags.DontSave; provincesObj.transform.SetParent(transform, false); provincesObj.transform.localPosition = Misc.Vector3back * 0.002f; provincesObj.layer = gameObject.layer; for (int k = 0; k < provincesBorders.Length; k++) { GameObject flayer = new GameObject("flayer"); flayer.hideFlags = HideFlags.DontSave | HideFlags.HideInHierarchy; flayer.transform.SetParent(provincesObj.transform, false); flayer.transform.localPosition = Misc.Vector3zero; flayer.transform.localRotation = Quaternion.Euler(Misc.Vector3zero); flayer.layer = provincesObj.layer; Mesh mesh = new Mesh(); mesh.vertices = provincesBorders [k]; mesh.SetIndices(provincesIndices [k], MeshTopology.Lines, 0); mesh.RecalculateBounds(); mesh.hideFlags = HideFlags.DontSave; MeshFilter mf = flayer.AddComponent <MeshFilter> (); mf.sharedMesh = mesh; MeshRenderer mr = flayer.AddComponent <MeshRenderer> (); mr.receiveShadows = false; mr.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off; mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; // mr.useLightProbes = false; mr.sharedMaterial = provincesMat; } return(true); }
/// <summary> /// Unpacks province geodata information. Used by Map Editor. /// </summary> /// <param name="province">Province.</param> public void ReadProvincePackedString(Province province) { string[] regions = province.packedRegions.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries); int regionCount = regions.Length; province.regions = new List <Region> (regionCount); float maxVol = float.MinValue; Vector2 minProvince = Misc.Vector2one * 10; Vector2 maxProvince = -minProvince; char[] separatorRegions = new char[] { ';' }; for (int r = 0; r < regionCount; r++) { string[] coordinates = regions [r].Split(separatorRegions, StringSplitOptions.RemoveEmptyEntries); int coorCount = coordinates.Length; if (coorCount < 3) { continue; } Vector3 min = Misc.Vector3one * 10; Vector3 max = -min; Region provinceRegion = new Region(province, province.regions.Count); provinceRegion.points = new Vector3[coorCount]; for (int c = 0; c < coorCount; c++) { float x, y; GetPointFromPackedString(coordinates [c], out x, out y); Vector2 point = new Vector2(x, y); provinceRegion.points [c] = point; if (x < min.x) { min.x = x; } if (x > max.x) { max.x = x; } if (y < min.y) { min.y = y; } if (y > max.y) { max.y = y; } } Vector3 normRegionCenter = (min + max) * 0.5f; provinceRegion.center = normRegionCenter; province.regions.Add(provinceRegion); // Calculate country bounding rect if (min.x < minProvince.x) { minProvince.x = min.x; } if (min.y < minProvince.y) { minProvince.y = min.y; } if (max.x > maxProvince.x) { maxProvince.x = max.x; } if (max.y > maxProvince.y) { maxProvince.y = max.y; } provinceRegion.rect2D = new Rect(min.x, min.y, Math.Abs(max.x - min.x), Mathf.Abs(max.y - min.y)); float vol = (max - min).sqrMagnitude; if (vol > maxVol) { maxVol = vol; province.mainRegionIndex = r; province.center = provinceRegion.center; } } province.regionsRect2D = new Rect(minProvince.x, minProvince.y, Math.Abs(maxProvince.x - minProvince.x), Mathf.Abs(maxProvince.y - minProvince.y)); }
public void ProvinceTransferTo(int targetCountryIndex, int provinceIndex) { // Remove province form source country Province province = map.provinces [provinceIndex]; Country sourceCountry = map.countries [countryIndex]; if (map.countries [countryIndex].provinces != null) { List <Province> sourceProvinces = new List <Province> (sourceCountry.provinces); int provIndex = -1; for (int k = 0; k < sourceCountry.provinces.Length; k++) { if (sourceCountry.provinces [k].name.Equals(province.name)) { provIndex = k; } } if (provIndex >= 0) { sourceProvinces.RemoveAt(provIndex); sourceCountry.provinces = sourceProvinces.ToArray(); } } // Adds province to target country Country targetCountry = map.countries [targetCountryIndex]; if (targetCountry.provinces == null) { targetCountry.provinces = new Province[0]; } List <Province> destProvinces = new List <Province> (targetCountry.provinces); destProvinces.Add(province); targetCountry.provinces = destProvinces.ToArray(); // Apply boolean operations on country polygons Region provinceRegion = province.regions [provinceRegionIndex]; Region sourceRegion = sourceCountry.regions [sourceCountry.mainRegionIndex]; Region targetRegion = targetCountry.regions [targetCountry.mainRegionIndex]; // Extract from source country - only if province is in the frontier or is crossing the country for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; otherSourceRegion.sanitized = true; } PolygonClipper pc = new PolygonClipper(sourceRegion, provinceRegion); if (pc.OverlapsSubjectAndClipping()) { sourceRegion.sanitized = false; pc.Compute(PolygonOp.DIFFERENCE); } else { // Look for other regions to substract for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; pc = new PolygonClipper(otherSourceRegion, provinceRegion); if (pc.OverlapsSubjectAndClipping()) { otherSourceRegion.sanitized = false; pc.Compute(PolygonOp.DIFFERENCE); } } } // Remove invalid regions from source country for (int k = 0; k < sourceCountry.regions.Count; k++) { Region otherSourceRegion = sourceCountry.regions [k]; if (!otherSourceRegion.sanitized && otherSourceRegion.points.Length < 5) { sourceCountry.regions.RemoveAt(k); k--; } } // Add region to target country's polygon - only if the province is touching or crossing target country frontier pc = new PolygonClipper(targetRegion, provinceRegion); if (pc.OverlapsSubjectAndClipping()) { pc.Compute(PolygonOp.UNION); } else { // Add new region to country Region newCountryRegion = new Region(targetCountry, targetCountry.regions.Count); newCountryRegion.points = new List <Vector3> (provinceRegion.points).ToArray(); targetCountry.regions.Add(newCountryRegion); } //Max! if (!map.showCities && map.cities == null) { map.ReadCitiesPackedString(); } // Transfer cities int cityCount = map.cities.Count; for (int k = 0; k < cityCount; k++) { City city = map.cities [k]; if (city.countryIndex == countryIndex && city.province.Equals(province.name)) { city.countryIndex = targetCountryIndex; } } // Transfer mount points int mountPointCount = map.mountPoints.Count; for (int k = 0; k < mountPointCount; k++) { MountPoint mp = map.mountPoints [k]; if (mp.countryIndex == countryIndex && mp.provinceIndex == provinceIndex) { mp.countryIndex = targetCountryIndex; } } // Finish operation map.HideCountryRegionHighlights(true); map.HideProvinceRegionHighlights(true); map.RefreshCountryDefinition(province.countryIndex, null); province.countryIndex = targetCountryIndex; map.RefreshProvinceDefinition(provinceIndex); map.RefreshCountryDefinition(targetCountryIndex, null); countryChanges = true; provinceChanges = true; cityChanges = true; mountPointChanges = true; }