Beispiel #1
0
		/// <summary>
		/// Initializes a new instance of the <see cref="SharpNav.ContourVertex"/> struct.
		/// </summary>
		/// <param name="vec">The array of X,Y,Z coordinates.</param>
		/// <param name="region">The Region ID.</param>
		public ContourVertex(Vector3 vec, RegionId region)
		{
			this.X = (int)vec.X;
			this.Y = (int)vec.Y;
			this.Z = (int)vec.Z;
			this.RegionId = region;
		}
Beispiel #2
0
		/// <summary>
		/// Initializes a new instance of the <see cref="ContourVertex"/> struct as a copy.
		/// </summary>
		/// <param name="vert">The original vertex.</param>
		/// <param name="index">The index of the original vertex, which is temporarily stored in the <see cref="RegionId"/> field.</param>
		public ContourVertex(ContourVertex vert, int index)
		{
			this.X = vert.X;
			this.Y = vert.Y;
			this.Z = vert.Z;
			this.RegionId = new RegionId(index);
		}
Beispiel #3
0
		/// <summary>
		/// Initializes a new instance of the <see cref="ContourVertex"/> struct.
		/// </summary>
		/// <param name="x">The X coordinate.</param>
		/// <param name="y">The Y coordinate.</param>
		/// <param name="z">The Z coordinate.</param>
		/// <param name="region">The region ID.</param>
		public ContourVertex(int x, int y, int z, RegionId region)
		{
			this.X = x;
			this.Y = y;
			this.Z = z;
			this.RegionId = region;
		}
Beispiel #4
0
		/// <summary>
		/// Initializes a new instance of the <see cref="CompactSpan"/> struct.
		/// </summary>
		/// <param name="minimum">The span minimum.</param>
		/// <param name="height">The number of voxels the span contains.</param>
		public CompactSpan(int minimum, int height)
		{
			this.Minimum = minimum;
			this.Height = height;
			this.ConnectionWest = NotConnected;
			this.ConnectionNorth = NotConnected;
			this.ConnectionEast = NotConnected;
			this.ConnectionSouth = NotConnected;
			this.Region = RegionId.Null;
		}
Beispiel #5
0
		/// <summary>
		/// Initializes a new instance of the <see cref="Contour"/> class.
		/// </summary>
		/// <param name="verts">The raw vertices of the contour.</param>
		/// <param name="region">The region ID of the contour.</param>
		/// <param name="area">The area ID of the contour.</param>
		/// <param name="borderSize">The size of the border.</param>
		public Contour(List<ContourVertex> verts, RegionId region, Area area, int borderSize)
		{
			this.vertices = verts.ToArray();
			this.regionId = region;
			this.area = area;

			//remove offset
			if (borderSize > 0)
			{
				for (int j = 0; j < vertices.Length; j++)
				{
					vertices[j].X -= borderSize;
					vertices[j].Z -= borderSize;
				}
			}
		}
Beispiel #6
0
        public void LoadView(Type viewType, RegionId regionId)
        {
            var view = ServiceLocator.Instance[viewType];

            switch (regionId)
            {
                case RegionId.CONTENT:
                    {
                        MessageBus.Instance.Publish(UXMessage.ASSIGN_CONTENT_REGION, view);
                        break;
                    }

                case RegionId.NINE_OCLOCK:
                    {
                        MessageBus.Instance.Publish(UXMessage.NINE_OCLOCK_REGION, view);
                        break;
                    }

                default:
                    {
                        throw new NotImplementedException();
                    }
            }
        }
Beispiel #7
0
            private int[] vertices; //"numVertsPerPoly" elements

            #endregion Fields

            #region Constructors

            /// <summary>
            /// Initializes a new instance of the <see cref="Polygon" /> class.
            /// </summary>
            /// <param name="numVertsPerPoly">The number of vertices per polygon.</param>
            /// <param name="area">The AreaId</param>
            /// <param name="regionId">The RegionId</param>
            /// <param name="flags">Polygon flags</param>
            public Polygon(int numVertsPerPoly, Area area, RegionId regionId, int flags)
            {
                vertices = new int[numVertsPerPoly];
                neighborEdges = new int[numVertsPerPoly];
                this.area = area;
                this.regionId = regionId;
                this.flags = flags;

                for (int i = 0; i < numVertsPerPoly; i++)
                {
                    vertices[i] = NullId;
                    neighborEdges[i] = NullId;
                }
            }
Beispiel #8
0
		/// <summary>
		/// Simplify the contours by reducing the number of edges
		/// </summary>
		/// <param name="rawVerts">Initial vertices</param>
		/// <param name="simplified">New and simplified vertices</param>
		/// <param name="maxError">Maximum error allowed</param>
		/// <param name="maxEdgeLen">The maximum edge length allowed</param>
		/// <param name="buildFlags">Flags determines how to split the long edges</param>
		public static void Simplify(List<ContourVertex> rawVerts, List<ContourVertex> simplified, float maxError, int maxEdgeLen, ContourBuildFlags buildFlags)
		{
			bool tesselateWallEdges = (buildFlags & ContourBuildFlags.TessellateWallEdges) == ContourBuildFlags.TessellateWallEdges;
			bool tesselateAreaEdges = (buildFlags & ContourBuildFlags.TessellateAreaEdges) == ContourBuildFlags.TessellateAreaEdges;

			//add initial points
			bool hasConnections = false;
			for (int i = 0; i < rawVerts.Count; i++)
			{
				if (rawVerts[i].RegionId.Id != 0)
				{
					hasConnections = true;
					break;
				}
			}

			if (hasConnections)
			{
				//contour has some portals to other regions
				//add new point to every location where region changes
				for (int i = 0, end = rawVerts.Count; i < end; i++)
				{
					int ii = (i + 1) % end;
					bool differentRegions = rawVerts[i].RegionId.Id != rawVerts[ii].RegionId.Id;
					bool areaBorders = RegionId.HasFlags(rawVerts[i].RegionId, RegionFlags.AreaBorder) != RegionId.HasFlags(rawVerts[ii].RegionId, RegionFlags.AreaBorder);

					if (differentRegions || areaBorders)
					{
						simplified.Add(new ContourVertex(rawVerts[i], i));
					}
				}
			}

			//add some points if thhere are no connections
			if (simplified.Count == 0)
			{
				//find lower-left and upper-right vertices of contour
				int lowerLeftX = rawVerts[0].X;
				int lowerLeftY = rawVerts[0].Y;
				int lowerLeftZ = rawVerts[0].Z;
				RegionId lowerLeftI = RegionId.Null;

				int upperRightX = rawVerts[0].X;
				int upperRightY = rawVerts[0].Y;
				int upperRightZ = rawVerts[0].Z;
				RegionId upperRightI = RegionId.Null;

				//iterate through points
				for (int i = 0; i < rawVerts.Count; i++)
				{
					int x = rawVerts[i].X;
					int y = rawVerts[i].Y;
					int z = rawVerts[i].Z;

					if (x < lowerLeftX || (x == lowerLeftX && z < lowerLeftZ))
					{
						lowerLeftX = x;
						lowerLeftY = y;
						lowerLeftZ = z;
						lowerLeftI = new RegionId(i);
					}

					if (x > upperRightX || (x == upperRightX && z > upperRightZ))
					{
						upperRightX = x;
						upperRightY = y;
						upperRightZ = z;
						upperRightI = new RegionId(i);
					}
				}

				//save the points
				simplified.Add(new ContourVertex(lowerLeftX, lowerLeftY, lowerLeftZ, lowerLeftI));
				simplified.Add(new ContourVertex(upperRightX, upperRightY, upperRightZ, upperRightI));
			}

			//add points until all points are within error tolerance of simplified slope
			int numPoints = rawVerts.Count;
			for (int i = 0; i < simplified.Count;)
			{
				int ii = (i + 1) % simplified.Count;

				//obtain (x, z) coordinates, along with region id
				int ax = simplified[i].X;
				int az = simplified[i].Z;
				int ai = (int)simplified[i].RegionId;

				int bx = simplified[ii].X;
				int bz = simplified[ii].Z;
				int bi = (int)simplified[ii].RegionId;

				float maxDeviation = 0;
				int maxi = -1;
				int ci, countIncrement, endi;

				//traverse segment in lexilogical order (try to go from smallest to largest coordinates?)
				if (bx > ax || (bx == ax && bz > az))
				{
					countIncrement = 1;
					ci = (int)(ai + countIncrement) % numPoints;
					endi = (int)bi;
				}
				else
				{
					countIncrement = numPoints - 1;
					ci = (int)(bi + countIncrement) % numPoints;
					endi = (int)ai;
				}

				//tessellate only outer edges or edges between areas
				if (rawVerts[ci].RegionId.Id == 0 || RegionId.HasFlags(rawVerts[ci].RegionId, RegionFlags.AreaBorder))
				{
					//find the maximum deviation
					while (ci != endi)
					{
						float deviation = Distance.PointToSegment2DSquared(rawVerts[ci].X, rawVerts[ci].Z, ax, az, bx, bz);

						if (deviation > maxDeviation)
						{
							maxDeviation = deviation;
							maxi = ci;
						}

						ci = (ci + countIncrement) % numPoints;
					}
				}

				//If max deviation is larger than accepted error, add new point
				if (maxi != -1 && maxDeviation > (maxError * maxError))
				{
					simplified.Insert(i + 1, new ContourVertex(rawVerts[maxi], maxi));
				}
				else
				{
					i++;
				}
			}

			//split too long edges
			if (maxEdgeLen > 0 && (tesselateAreaEdges || tesselateWallEdges))
			{
				for (int i = 0; i < simplified.Count;)
				{
					int ii = (i + 1) % simplified.Count;

					//get (x, z) coordinates along with region id
					int ax = simplified[i].X;
					int az = simplified[i].Z;
					int ai = (int)simplified[i].RegionId;

					int bx = simplified[ii].X;
					int bz = simplified[ii].Z;
					int bi = (int)simplified[ii].RegionId;

					//find maximum deviation from segment
					int maxi = -1;
					int ci = (int)(ai + 1) % numPoints;

					//tessellate only outer edges or edges between areas
					bool tess = false;

					//wall edges
					if (tesselateWallEdges && rawVerts[ci].RegionId.Id == 0)
						tess = true;

					//edges between areas
					if (tesselateAreaEdges && RegionId.HasFlags(rawVerts[ci].RegionId, RegionFlags.AreaBorder))
						tess = true;

					if (tess)
					{
						int dx = bx - ax;
						int dz = bz - az;
						if (dx * dx + dz * dz > maxEdgeLen * maxEdgeLen)
						{
							//round based on lexilogical direction (smallest to largest cooridinates, first by x.
							//if x coordinates are equal, then compare z coordinates)
							int n = bi < ai ? (bi + numPoints - ai) : (bi - ai);

							if (n > 1)
							{
								if (bx > ax || (bx == ax && bz > az))
									maxi = (int)(ai + n / 2) % numPoints;
								else
									maxi = (int)(ai + (n + 1) / 2) % numPoints;
							}
						}
					}

					//add new point
					if (maxi != -1)
					{
						simplified.Insert(i + 1, new ContourVertex(rawVerts[maxi], maxi));
					}
					else
					{
						i++;
					}
				}
			}

			for (int i = 0; i < simplified.Count; i++)
			{
				ContourVertex sv = simplified[i];

				//take edge vertex flag from current raw point and neighbor region from next raw point
				int ai = ((int)sv.RegionId + 1) % numPoints;
				RegionId bi = sv.RegionId;

				//save new region id
				sv.RegionId = RegionId.FromRawBits(((int)rawVerts[ai].RegionId & (RegionId.MaskId | (int)RegionFlags.AreaBorder)) | ((int)rawVerts[(int)bi].RegionId & (int)RegionFlags.VertexBorder));

				simplified[i] = sv;
			}
		}
Beispiel #9
0
		/// <summary>
		/// Initializes a new instance of the <see cref="ContourVertex"/> struct as a copy.
		/// </summary>
		/// <param name="vert">The original vertex.</param>
		/// <param name="region">The region that the vertex belongs to.</param>
		public ContourVertex(ContourVertex vert, RegionId region)
		{
			this.X = vert.X;
			this.Y = vert.Y;
			this.Z = vert.Z;
			this.RegionId = region;
		}
        /// <summary>
        /// Merge two stacks to get a single stack.
        /// </summary>
        /// <param name="source">The original stack</param>
        /// <param name="destination">The new stack</param>
        /// <param name="regions">Region ids</param>
        private static void AppendStacks(List<CompactSpanReference> source, List<CompactSpanReference> destination, RegionId[] regions)
        {
            for (int j = 0; j < source.Count; j++)
            {
                var spanRef = source[j];
                if (spanRef.Index < 0 || regions[spanRef.Index] != 0)
                    continue;

                destination.Add(spanRef);
            }
        }
        /// <summary>
        /// Try to visit all the spans. May be needed in filtering small regions. 
        /// </summary>
        /// <param name="regions">an array of region values</param>
        /// <param name="spanRef">The span to start walking from.</param>
        /// <param name="dir">The direction to start walking in.</param>
        /// <param name="cont">A collection of regions to append to.</param>
        private void WalkContour(RegionId[] regions, CompactSpanReference spanRef, Direction dir, List<RegionId> cont)
        {
            Direction startDir = dir;
            int starti = spanRef.Index;

            CompactSpan ss = spans[starti];
            RegionId curReg = RegionId.Null;

            if (ss.IsConnected(dir))
            {
                int dx = spanRef.X + dir.GetHorizontalOffset();
                int dy = spanRef.Y + dir.GetVerticalOffset();
                int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref ss, dir);
                curReg = regions[di];
            }

            cont.Add(curReg);

            int iter = 0;
            while (++iter < 40000)
            {
                CompactSpan s = spans[spanRef.Index];

                if (IsSolidEdge(regions, ref spanRef, dir))
                {
                    //choose the edge corner
                    RegionId r = RegionId.Null;
                    if (s.IsConnected(dir))
                    {
                        int dx = spanRef.X + dir.GetHorizontalOffset();
                        int dy = spanRef.Y + dir.GetVerticalOffset();
                        int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref s, dir);
                        r = regions[di];
                    }

                    if (r != curReg)
                    {
                        curReg = r;
                        cont.Add(curReg);
                    }

                    dir = dir.NextClockwise(); //rotate clockwise
                }
                else
                {
                    int di = -1;
                    int dx = spanRef.X + dir.GetHorizontalOffset();
                    int dy = spanRef.Y + dir.GetVerticalOffset();

                    if (s.IsConnected(dir))
                    {
                        CompactCell dc = cells[dx + dy * width];
                        di = dc.StartIndex + CompactSpan.GetConnection(ref s, dir);
                    }

                    if (di == -1)
                    {
                        //shouldn't happen
                        return;
                    }

                    spanRef = new CompactSpanReference(dx, dy, di);
                    dir = dir.NextCounterClockwise(); //rotate counterclockwise
                }

                if (starti == spanRef.Index && startDir == dir)
                    break;
            }

            //remove adjacent duplicates
            if (cont.Count > 1)
            {
                for (int j = 0; j < cont.Count;)
                {
                    //next element
                    int nj = (j + 1) % cont.Count;

                    //adjacent duplicate found
                    if (cont[j] == cont[nj])
                        cont.RemoveAt(j);
                    else
                        j++;
                }
            }
        }
        /// <summary>
        /// Checks whether the edge from a span in a direction is a solid edge.
        /// A solid edge is an edge between two regions.
        /// </summary>
        /// <param name="regions">The region ID array.</param>
        /// <param name="spanRef">A reference to the span connected to the edge.</param>
        /// <param name="dir">The direction of the edge.</param>
        /// <returns>A value indicating whether the described edge is solid.</returns>
        private bool IsSolidEdge(RegionId[] regions, ref CompactSpanReference spanRef, Direction dir)
        {
            CompactSpan s = spans[spanRef.Index];
            RegionId r = RegionId.Null;

            if (s.IsConnected(dir))
            {
                int dx = spanRef.X + dir.GetHorizontalOffset();
                int dy = spanRef.Y + dir.GetVerticalOffset();
                int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref s, dir);
                r = regions[di];
            }

            if (r == regions[spanRef.Index])
                return false;

            return true;
        }
        /// <summary>
        /// Floods the regions at a certain level
        /// </summary>
        /// <param name="regions">source region</param>
        /// <param name="floodDistances">source distances</param>
        /// <param name="regionIndex">region id</param>
        /// <param name="level">current level</param>
        /// <param name="start">A reference to the starting span.</param>
        /// <returns>Always true.</returns>
        private bool FloodRegion(RegionId[] regions, int[] floodDistances, int regionIndex, int level, ref CompactSpanReference start)
        {
            //TODO this method should always return true, make it not return a bool?
            //flood fill mark region
            Stack<CompactSpanReference> stack = new Stack<CompactSpanReference>();
            stack.Push(start);

            Area area = areas[start.Index];
            regions[start.Index] = new RegionId(regionIndex);
            floodDistances[start.Index] = 0;

            int lev = level >= 2 ? level - 2 : 0;
            int count = 0;

            while (stack.Count > 0)
            {
                CompactSpanReference cell = stack.Pop();
                CompactSpan cs = spans[cell.Index];

                //check if any of the neighbors already have a valid reigon set
                RegionId ar = RegionId.Null;
                for (var dir = Direction.West; dir <= Direction.South; dir++)
                {
                    //8 connected
                    if (cs.IsConnected(dir))
                    {
                        int dx = cell.X + dir.GetHorizontalOffset();
                        int dy = cell.Y + dir.GetVerticalOffset();
                        int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref cs, dir);

                        if (areas[di] != area)
                            continue;

                        RegionId nr = regions[di];

                        if (RegionId.HasFlags(nr, RegionFlags.Border)) //skip borders
                            continue;

                        if (nr != 0 && nr != regionIndex)
                        {
                            ar = nr;
                            break;
                        }

                        CompactSpan ds = spans[di];
                        Direction dir2 = dir.NextClockwise();
                        if (ds.IsConnected(dir2))
                        {
                            int dx2 = dx + dir2.GetHorizontalOffset();
                            int dy2 = dy + dir2.GetVerticalOffset();
                            int di2 = cells[dx2 + dy2 * width].StartIndex + CompactSpan.GetConnection(ref ds, dir2);

                            if (areas[di2] != area)
                                continue;

                            RegionId nr2 = regions[di2];
                            if (nr2 != 0 && nr2 != regionIndex)
                            {
                                ar = nr2;
                                break;
                            }
                        }
                    }
                }

                if (ar != 0)
                {
                    regions[cell.Index] = RegionId.Null;
                    continue;
                }

                count++;

                //expand neighbors
                for (var dir = Direction.West; dir <= Direction.South; dir++)
                {
                    if (cs.IsConnected(dir))
                    {
                        int dx = cell.X + dir.GetHorizontalOffset();
                        int dy = cell.Y + dir.GetVerticalOffset();
                        int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref cs, dir);

                        if (areas[di] != area)
                            continue;

                        if (distances[di] >= lev && regions[di] == 0)
                        {
                            regions[di] = new RegionId(regionIndex);
                            floodDistances[di] = 0;
                            stack.Push(new CompactSpanReference(dx, dy, di));
                        }
                    }
                }
            }

            return count > 0;
        }
 /// <summary>
 /// Fill in a rectangular area with a region ID. Spans in a null area are skipped.
 /// </summary>
 /// <param name="regions">The region ID array.</param>
 /// <param name="newRegionId">The ID to fill in.</param>
 /// <param name="left">The left edge of the rectangle.</param>
 /// <param name="right">The right edge of the rectangle.</param>
 /// <param name="bottom">The bottom edge of the rectangle.</param>
 /// <param name="top">The top edge of the rectangle.</param>
 private void FillRectangleRegion(RegionId[] regions, RegionId newRegionId, int left, int right, int bottom, int top)
 {
     for (int y = bottom; y < top; y++)
     {
         for (int x = left; x < right; x++)
         {
             CompactCell c = cells[x + y * width];
             for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++)
             {
                 if (areas[i].IsWalkable)
                     regions[i] = newRegionId;
             }
         }
     }
 }
Beispiel #15
0
        protected void Page_Load(object sender, EventArgs e)
        {
            SetMeta(string.Format("{0} - {1}", AdvantShop.Configuration.SettingsMain.ShopName, Resources.Resource.Admin_MasterPageAdmin_Sities));

            if (RegionId < 0 && CountryId < 0)
            {
                Response.Redirect("Country.aspx");
            }

            if (RegionId != 0)
            {
                var region = RegionService.GetRegion(RegionId);
                if (region != null)
                {
                    lblHead.Text       = region.Name;
                    hlBack.NavigateUrl = "Regions.aspx?CountryId=" + region.CountryID;
                    hlBack.Text        = Resources.Resource.Admin_Cities_BackToRegions;

                    hlBack2.NavigateUrl = "Country.aspx";
                    hlBack2.Text        = Resources.Resource.Admin_Cities_BackToCoutries;
                }
            }

            if (CountryId != 0)
            {
                var country = CountryService.GetCountry(CountryId);
                if (country != null)
                {
                    lblHead.Text       = country.Name;
                    hlBack.NavigateUrl = "Regions.aspx?CountryId=" + country.CountryId;
                    hlBack.Text        = Resources.Resource.Admin_Cities_BackToRegions;

                    hlBack2.NavigateUrl = "Country.aspx";
                    hlBack2.Text        = Resources.Resource.Admin_Cities_BackToCoutries;
                }
                btnAddCity.Visible = false;
            }



            if (!IsPostBack)
            {
                _paging = new SqlPaging
                {
                    TableName    = "[Customers].[City] Left Join Customers.Region On Region.RegionId=City.RegionId",
                    ItemsPerPage = 20
                };

                _paging.AddFieldsRange(
                    new List <Field>
                {
                    new Field {
                        Name = "CityID as ID", IsDistinct = true
                    },
                    new Field {
                        Name = "CityName", Sorting = SortDirection.Ascending
                    },
                    new Field {
                        Name = "CitySort"
                    },
                    new Field {
                        Name = "City.RegionID"
                    },
                    new Field {
                        Name = "City.DisplayInPopup"
                    },
                    new Field {
                        Name = "PhoneNumber"
                    },
                    new Field {
                        Name = "Region.CountryId", NotInQuery = true
                    },
                });

                if (RegionId != 0)
                {
                    _paging.Fields["City.RegionID"].Filter = new EqualFieldFilter
                    {
                        ParamName = "@RegionID",
                        Value     = RegionId.ToString()
                    };
                }

                if (CountryId != 0)
                {
                    _paging.Fields["Region.CountryId"].Filter = new EqualFieldFilter
                    {
                        ParamName = "@CountryId",
                        Value     = CountryId.ToString()
                    };
                }

                grid.ChangeHeaderImageUrl("arrowCityName", "images/arrowup.gif");

                pageNumberer.CurrentPageIndex = 1;
                _paging.CurrentPageIndex      = 1;
                ViewState["Paging"]           = _paging;
            }
            else
            {
                _paging = (SqlPaging)(ViewState["Paging"]);
                _paging.ItemsPerPage = SQLDataHelper.GetInt(ddRowsPerPage.SelectedValue);

                if (_paging == null)
                {
                    throw (new Exception("Paging lost"));
                }

                string strIds = Request.Form["SelectedIds"];

                if (!string.IsNullOrEmpty(strIds))
                {
                    strIds = strIds.Trim();
                    string[] arrids = strIds.Split(' ');

                    var ids = new string[arrids.Length];
                    _selectionFilter = new InSetFieldFilter {
                        IncludeValues = true
                    };
                    for (int idx = 0; idx <= ids.Length - 1; idx++)
                    {
                        int t = int.Parse(arrids[idx]);
                        if (t != -1)
                        {
                            ids[idx] = t.ToString();
                        }
                        else
                        {
                            _selectionFilter.IncludeValues = false;
                            _inverseSelection = true;
                        }
                    }
                    _selectionFilter.Values = ids;
                }
            }
        }
Beispiel #16
0
 /// <summary>
 /// Initializes a new instance of the <see cref="Edge"/> struct.
 /// </summary>
 /// <param name="vert0">Vertex A</param>
 /// <param name="vert1">Vertex B</param>
 /// <param name="region">Region id</param>
 /// <param name="area">Area id</param>
 public Edge(int vert0, int vert1, RegionId region, Area area)
 {
     Vert0 = vert0;
     Vert1 = vert1;
     Region = region;
     Area = area;
 }
        /// <summary>
        ///     地方ノードを追加する
        /// </summary>
        /// <param name="region">地方</param>
        /// <param name="parent">親ノード</param>
        private static void AddRegionTreeItem(RegionId region, TreeNode parent)
        {
            // 地方ノードを追加する
            TreeNode node = new TreeNode { Text = Provinces.GetRegionName(region), Tag = region };
            parent.Nodes.Add(node);

            // 地域ノードを順に追加する
            if (Provinces.RegionAreaMap.ContainsKey(region))
            {
                foreach (AreaId area in Provinces.RegionAreaMap[region])
                {
                    AddAreaTreeItem(area, node);
                }
            }
        }
Beispiel #18
0
        public void ParseJsonFiles()
        {
            // matches the [region]_xxx of the file
            // so the file must be named with the region of the matches first
            var regex = new Regex(@"^([A-Z]+)");
            foreach (string filename in fileNames)
            {
                var fileids = DeserializeFile(filename);
                System.Text.RegularExpressions.Match match = regex.Match(filename);
                foreach(string id in fileids.Skip(4000).Take(1000))
                {
                    var regionid = new RegionId()
                    {
                        Id = id,
                        Region = match.Value
                    };

                    IDMatches.Enqueue(regionid);
                }
            }
        }
Beispiel #19
0
        /// <summary>
        ///     地方名を取得する
        /// </summary>
        /// <param name="region">地方</param>
        /// <returns>地方名</returns>
        public static string GetRegionName(RegionId region)
        {
            // AoD1.10以降の場合、文字列定義が変更になっているかをチェックする
            if ((Game.Type == GameType.ArsenalOfDemocracy) && (Game.Version >= 110))
            {
                if (ReplacingRegionNamesAod.ContainsKey(region))
                {
                    return Config.GetText(ReplacingRegionNamesAod[region]);
                }
            }

            return Config.GetText(RegionNames[(int) region]);
        }
        /// <summary>
        /// Discards regions that are too small. 
        /// </summary>
        /// <param name="regionIds">region data</param>
        /// <param name="minRegionArea">The minimum area a region can have</param>
        /// <param name="mergeRegionSize">The size of the regions after merging</param>
        /// <param name="maxRegionId">determines the number of regions available</param>
        /// <returns>The reduced number of regions.</returns>
        private int FilterSmallRegions(RegionId[] regionIds, int minRegionArea, int mergeRegionSize, int maxRegionId)
        {
            int numRegions = maxRegionId + 1;
            Region[] regions = new Region[numRegions];

            //construct regions
            for (int i = 0; i < numRegions; i++)
                regions[i] = new Region(i);

            //find edge of a region and find connections around a contour
            for (int y = 0; y < length; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    CompactCell c = cells[x + y * width];
                    for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++)
                    {
                        CompactSpanReference spanRef = new CompactSpanReference(x, y, i);

                        //HACK since the border region flag makes r negative, I changed r == 0 to r <= 0. Figure out exactly what maxRegionId's purpose is and see if Region.IsBorderOrNull is all we need.
                        int r = (int)regionIds[i];
                        if (r <= 0 || (int)r >= numRegions)
                            continue;

                        Region reg = regions[(int)r];
                        reg.SpanCount++;

                        //update floors
                        for (int j = c.StartIndex; j < end; j++)
                        {
                            if (i == j) continue;
                            RegionId floorId = regionIds[j];
                            if (floorId == 0 || (int)floorId >= numRegions)
                                continue;
                            reg.AddUniqueFloorRegion(floorId);
                        }

                        //have found contour
                        if (reg.Connections.Count > 0)
                            continue;

                        reg.AreaType = areas[i];

                        //check if this cell is next to a border
                        for (var dir = Direction.West; dir <= Direction.South; dir++)
                        {
                            if (IsSolidEdge(regionIds, ref spanRef, dir))
                            {
                                //The cell is at a border.
                                //Walk around contour to find all neighbors
                                WalkContour(regionIds, spanRef, dir, reg.Connections);
                                break;
                            }
                        }
                    }
                }
            }

            //Remove too small regions
            Stack<RegionId> stack = new Stack<RegionId>();
            List<RegionId> trace = new List<RegionId>();
            for (int i = 0; i < numRegions; i++)
            {
                Region reg = regions[i];
                if (reg.IsBorderOrNull || reg.SpanCount == 0 || reg.Visited)
                    continue;

                //count the total size of all connected regions
                //also keep track of the regions connections to a tile border
                bool connectsToBorder = false;
                int spanCount = 0;
                stack.Clear();
                trace.Clear();

                reg.Visited = true;
                stack.Push(reg.Id);

                while (stack.Count > 0)
                {
                    //pop
                    RegionId ri = stack.Pop();

                    Region creg = regions[(int)ri];

                    spanCount += creg.SpanCount;
                    trace.Add(ri);

                    for (int j = 0; j < creg.Connections.Count; j++)
                    {
                        if (RegionId.HasFlags(creg.Connections[j], RegionFlags.Border))
                        {
                            connectsToBorder = true;
                            continue;
                        }

                        Region neiReg = regions[(int)creg.Connections[j]];
                        if (neiReg.Visited || neiReg.IsBorderOrNull)
                            continue;

                        //visit
                        stack.Push(neiReg.Id);
                        neiReg.Visited = true;
                    }
                }

                //if the accumulated region size is too small, remove it
                //do not remove areas which connect to tile borders as their size can't be estimated correctly
                //and removing them can potentially remove necessary areas
                if (spanCount < minRegionArea && !connectsToBorder)
                {
                    //kill all visited regions
                    for (int j = 0; j < trace.Count; j++)
                    {
                        int index = (int)trace[j];

                        regions[index].SpanCount = 0;
                        regions[index].Id = RegionId.Null;
                    }
                }
            }

            //Merge too small regions to neighbor regions
            int mergeCount = 0;
            do
            {
                mergeCount = 0;
                for (int i = 0; i < numRegions; i++)
                {
                    Region reg = regions[i];
                    if (reg.IsBorderOrNull || reg.SpanCount == 0)
                        continue;

                    //check to see if region should be merged
                    if (reg.SpanCount > mergeRegionSize && reg.IsConnectedToBorder())
                        continue;

                    //small region with more than one connection or region which is not connected to border at all
                    //find smallest neighbor that connects to this one
                    int smallest = int.MaxValue;
                    RegionId mergeId = reg.Id;
                    for (int j = 0; j < reg.Connections.Count; j++)
                    {
                        if (RegionId.HasFlags(reg.Connections[j], RegionFlags.Border))
                            continue;

                        Region mreg = regions[(int)reg.Connections[j]];
                        if (mreg.IsBorderOrNull)
                            continue;

                        if (mreg.SpanCount < smallest && reg.CanMergeWith(mreg) && mreg.CanMergeWith(reg))
                        {
                            smallest = mreg.SpanCount;
                            mergeId = mreg.Id;
                        }
                    }

                    //found new id
                    if (mergeId != reg.Id)
                    {
                        RegionId oldId = reg.Id;
                        Region target = regions[(int)mergeId];

                        //merge regions
                        if (target.MergeWithRegion(reg))
                        {
                            //fix regions pointing to current region
                            for (int j = 0; j < numRegions; j++)
                            {
                                if (regions[j].IsBorderOrNull)
                                    continue;

                                //if another regions was already merged into current region
                                //change the nid of the previous region too
                                if (regions[j].Id == oldId)
                                    regions[j].Id = mergeId;

                                //replace current region with new one if current region is neighbor
                                regions[j].ReplaceNeighbour(oldId, mergeId);
                            }

                            mergeCount++;
                        }
                    }
                }
            }
            while (mergeCount > 0);

            //Compress region ids
            for (int i = 0; i < numRegions; i++)
            {
                regions[i].Remap = false;

                if (regions[i].IsBorderOrNull)
                    continue;

                regions[i].Remap = true;
            }

            int regIdGen = 0;
            for (int i = 0; i < numRegions; i++)
            {
                if (!regions[i].Remap)
                    continue;

                RegionId oldId = regions[i].Id;
                RegionId newId = new RegionId(++regIdGen);
                for (int j = i; j < numRegions; j++)
                {
                    if (regions[j].Id == oldId)
                    {
                        regions[j].Id = newId;
                        regions[j].Remap = false;
                    }
                }
            }

            //Remap regions
            for (int i = 0; i < spans.Length; i++)
            {
                if (!RegionId.HasFlags(regionIds[i], RegionFlags.Border))
                    regionIds[i] = regions[(int)regionIds[i]].Id;
            }

            return regIdGen;
        }
Beispiel #21
0
        /// <summary>
        ///     プロヴィンスの地方を変更する
        /// </summary>
        /// <param name="province">プロヴィンス</param>
        /// <param name="region">地方</param>
        public static void ModifyRegion(Province province, RegionId region)
        {
            // 地方と地域の対応付けを変更する
            DetachRegionArea(province.Region, province.Area);
            AttachRegionArea(region, province.Area);

            // 大陸と地方の対応付けを変更する
            DetachContinentRegion(province.Continent, province.Region);
            AttachContinentRegion(province.Continent, region);

            // 値を更新する
            province.Region = region;
        }
        /// <summary>
        /// Helper method for WalkContour function
        /// </summary>
        /// <param name="sr">The span to get the corner height for.</param>
        /// <param name="dir">The direction to get the corner height from.</param>
        /// <param name="isBorderVertex">Determine whether the vertex is a border or not.</param>
        /// <returns>The corner height.</returns>
        private int GetCornerHeight(CompactSpanReference sr, Direction dir, out bool isBorderVertex)
        {
            isBorderVertex = false;

            CompactSpan s = this[sr];
            int cornerHeight = s.Minimum;
            Direction dirp = dir.NextClockwise(); //new clockwise direction

            RegionId[] cornerRegs = new RegionId[4];
            Area[] cornerAreas = new Area[4];

            //combine region and area codes in order to prevent border vertices, which are in between two areas, to be removed
            cornerRegs[0] = s.Region;
            cornerAreas[0] = areas[sr.Index];

            if (s.IsConnected(dir))
            {
                //get neighbor span
                int dx = sr.X + dir.GetHorizontalOffset();
                int dy = sr.Y + dir.GetVerticalOffset();
                int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref s, dir);
                CompactSpan ds = spans[di];

                cornerHeight = Math.Max(cornerHeight, ds.Minimum);
                cornerRegs[1] = spans[di].Region;
                cornerAreas[1] = areas[di];

                //get neighbor of neighbor's span
                if (ds.IsConnected(dirp))
                {
                    int dx2 = dx + dirp.GetHorizontalOffset();
                    int dy2 = dy + dirp.GetVerticalOffset();
                    int di2 = cells[dx2 + dy2 * width].StartIndex + CompactSpan.GetConnection(ref ds, dirp);
                    CompactSpan ds2 = spans[di2];

                    cornerHeight = Math.Max(cornerHeight, ds2.Minimum);
                    cornerRegs[2] = ds2.Region;
                    cornerAreas[2] = areas[di2];
                }
            }

            //get neighbor span
            if (s.IsConnected(dirp))
            {
                int dx = sr.X + dirp.GetHorizontalOffset();
                int dy = sr.Y + dirp.GetVerticalOffset();
                int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref s, dirp);
                CompactSpan ds = spans[di];

                cornerHeight = Math.Max(cornerHeight, ds.Minimum);
                cornerRegs[3] = ds.Region;
                cornerAreas[3] = areas[di];

                //get neighbor of neighbor's span
                if (ds.IsConnected(dir))
                {
                    int dx2 = dx + dir.GetHorizontalOffset();
                    int dy2 = dy + dir.GetVerticalOffset();
                    int di2 = cells[dx2 + dy2 * width].StartIndex + CompactSpan.GetConnection(ref ds, dir);
                    CompactSpan ds2 = spans[di2];

                    cornerHeight = Math.Max(cornerHeight, ds2.Minimum);
                    cornerRegs[2] = ds2.Region;
                    cornerAreas[2] = areas[di2];
                }
            }

            //check if vertex is special edge vertex
            //if so, these vertices will be removed later
            for (int j = 0; j < 4; j++)
            {
                int a = j;
                int b = (j + 1) % 4;
                int c = (j + 2) % 4;
                int d = (j + 3) % 4;

                RegionId ra = cornerRegs[a], rb = cornerRegs[b], rc = cornerRegs[c], rd = cornerRegs[d];
                Area aa = cornerAreas[a], ab = cornerAreas[b], ac = cornerAreas[c], ad = cornerAreas[d];

                //the vertex is a border vertex if:
                //two same exterior cells in a row followed by two interior cells and none of the regions are out of bounds
                bool twoSameExteriors = RegionId.HasFlags(ra, RegionFlags.Border) && RegionId.HasFlags(rb, RegionFlags.Border) && (ra == rb && aa == ab);
                bool twoSameInteriors = !(RegionId.HasFlags(rc, RegionFlags.Border) || RegionId.HasFlags(rd, RegionFlags.Border));
                bool intsSameArea = ac == ad;
                bool noZeros = ra != 0 && rb != 0 && rc != 0 && rd != 0 && aa != 0 && ab != 0 && ac != 0 && ad != 0;
                if (twoSameExteriors && twoSameInteriors && intsSameArea && noZeros)
                {
                    isBorderVertex = true;
                    break;
                }
            }

            return cornerHeight;
        }
Beispiel #23
0
        /// <summary>
        ///     大陸と地方の対応付けを設定する
        /// </summary>
        /// <param name="continentId">大陸</param>
        /// <param name="regionId">地方</param>
        private static void AttachContinentRegion(ContinentId continentId, RegionId regionId)
        {
            // 大陸の項目がなければ作成する
            if (!ContinentRegionMap.ContainsKey(continentId))
            {
                ContinentRegionMap.Add(continentId, new List<RegionId>());
            }

            // 地方リストに地方を追加する
            if (!ContinentRegionMap[continentId].Contains(regionId))
            {
                ContinentRegionMap[continentId].Add(regionId);
            }
        }
        /// <summary>
        /// Sort the compact spans
        /// </summary>
        /// <param name="regions">Region data</param>
        /// <param name="stacks">Temporary stack of CompactSpanReference values</param>
        /// <param name="startlevel">Starting level</param>
        /// <param name="numStacks">The number of layers</param>
        /// <param name="logLevelsPerStack">log base 2 of stack levels</param>
        private void SortCellsByLevel(RegionId[] regions, List<CompactSpanReference>[] stacks, int startlevel, int numStacks, int logLevelsPerStack)
        {
            startlevel = startlevel >> logLevelsPerStack;
            for (int j = 0; j < numStacks; j++)
                stacks[j].Clear();

            for (int y = 0; y < length; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    CompactCell c = cells[y * width + x];
                    for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++)
                    {
                        if (!areas[i].IsWalkable || !regions[i].IsNull)
                            continue;

                        int level = distances[i] >> logLevelsPerStack;
                        int sId = startlevel - level;
                        if (sId >= numStacks)
                            continue;
                        if (sId < 0)
                            sId = 0;

                        stacks[sId].Add(new CompactSpanReference(x, y, i));
                    }
                }
            }
        }
Beispiel #25
0
        /// <summary>
        ///     地方と地域の対応付けを設定する
        /// </summary>
        /// <param name="regionId">地方</param>
        /// <param name="areaId">地域</param>
        private static void AttachRegionArea(RegionId regionId, AreaId areaId)
        {
            // 地方の項目がなければ作成する
            if (!RegionAreaMap.ContainsKey(regionId))
            {
                RegionAreaMap.Add(regionId, new List<AreaId>());
            }

            // 地域リストに地域を追加する
            if (!RegionAreaMap[regionId].Contains(areaId))
            {
                RegionAreaMap[regionId].Add(areaId);
            }
        }
        /// <summary>
        /// The central method for building regions, which consists of connected, non-overlapping walkable spans.
        /// </summary>
        /// <param name="borderSize">The border size</param>
        /// <param name="minRegionArea">If smaller than this value, region will be null</param>
        /// <param name="mergeRegionArea">Reduce unneccesarily small regions</param>
        public void BuildRegions(int borderSize, int minRegionArea, int mergeRegionArea)
        {
            if (distances == null)
                BuildDistanceField();

            const int LogStackCount = 3;
            const int StackCount = 1 << LogStackCount;
            List<CompactSpanReference>[] stacks = new List<CompactSpanReference>[StackCount];
            for (int i = 0; i < stacks.Length; i++)
                stacks[i] = new List<CompactSpanReference>(1024);

            RegionId[] regions = new RegionId[spans.Length];
            int[] floodDistances = new int[spans.Length];

            RegionId[] regionBuffer = new RegionId[spans.Length];
            int[] distanceBuffer = new int[spans.Length];

            int regionIndex = 1;
            int level = ((maxDistance + 1) / 2) * 2;

            const int ExpandIters = 8;

            if (borderSize > 0)
            {
                //make sure border doesn't overflow
                int borderWidth = Math.Min(width, borderSize);
                int borderHeight = Math.Min(length, borderSize);

                //fill regions
                FillRectangleRegion(regions, new RegionId(regionIndex++, RegionFlags.Border), 0, borderWidth, 0, length);
                FillRectangleRegion(regions, new RegionId(regionIndex++, RegionFlags.Border), width - borderWidth, width, 0, length);
                FillRectangleRegion(regions, new RegionId(regionIndex++, RegionFlags.Border), 0, width, 0, borderHeight);
                FillRectangleRegion(regions, new RegionId(regionIndex++, RegionFlags.Border), 0, width, length - borderHeight, length);

                this.borderSize = borderSize;
            }

            int stackId = -1;
            while (level > 0)
            {
                level = level >= 2 ? level - 2 : 0;
                stackId = (stackId + 1) & (StackCount - 1);

                if (stackId == 0)
                    SortCellsByLevel(regions, stacks, level, StackCount, 1);
                else
                    AppendStacks(stacks[stackId - 1], stacks[stackId], regions);

                //expand current regions until no new empty connected cells found
                ExpandRegions(regions, floodDistances, ExpandIters, level, stacks[stackId], regionBuffer, distanceBuffer);

                //mark new regions with ids
                for (int j = 0; j < stacks[stackId].Count; j++)
                {
                    var spanRef = stacks[stackId][j];
                    if (spanRef.Index >= 0 && regions[spanRef.Index] == 0)
                        if (FloodRegion(regions, floodDistances, regionIndex, level, ref spanRef))
                            regionIndex++;
                }
            }

            //expand current regions until no new empty connected cells found
            ExpandRegions(regions, floodDistances, ExpandIters * 8, 0, null, regionBuffer, distanceBuffer);

            //filter out small regions
            this.maxRegions = FilterSmallRegions(regions, minRegionArea, mergeRegionArea, regionIndex);

            //write the result out
            for (int i = 0; i < spans.Length; i++)
                spans[i].Region = regions[i];
        }
Beispiel #27
0
        /// <summary>
        ///     大陸と地方の対応付けを解除する
        /// </summary>
        /// <param name="continentId">大陸</param>
        /// <param name="regionId">地方</param>
        private static void DetachContinentRegion(ContinentId continentId, RegionId regionId)
        {
            // 大陸の項目がなければ何もしない
            if (!ContinentRegionMap.ContainsKey(continentId))
            {
                return;
            }

            // 地方リストから地方を削除する
            if (ContinentRegionMap[continentId].Contains(regionId))
            {
                ContinentRegionMap[continentId].Remove(regionId);
                // 地方リストの項目がなくなれば大陸の項目を削除する
                if (ContinentRegionMap[continentId].Count == 0)
                {
                    ContinentRegionMap.Remove(continentId);
                }
            }
        }
        /// <summary>
        /// Expands regions to include spans above a specified water level.
        /// </summary>
        /// <param name="regions">The array of region IDs.</param>
        /// <param name="floodDistances">The array of flooding distances.</param>
        /// <param name="maxIterations">The maximum number of allowed iterations before breaking.</param>
        /// <param name="level">The current water level.</param>
        /// <param name="stack">A stack of span references that are being expanded.</param>
        /// <param name="regionBuffer">A buffer to store region IDs. Must be at least the same size as <c>regions</c>.</param>
        /// <param name="distanceBuffer">A buffer to store flood distances. Must be at least the same size as <c>floodDistances</c>.</param>
        private void ExpandRegions(RegionId[] regions, int[] floodDistances, int maxIterations, int level, List<CompactSpanReference> stack = null, RegionId[] regionBuffer = null, int[] distanceBuffer = null)
        {
            //generate buffers if they're not passed in or if they're too small.
            if (regionBuffer == null || regionBuffer.Length < regions.Length)
                regionBuffer = new RegionId[regions.Length];

            if (distanceBuffer == null || distanceBuffer.Length < floodDistances.Length)
                distanceBuffer = new int[floodDistances.Length];

            //copy existing data into the buffers.
            Array.Copy(regions, 0, regionBuffer, 0, regions.Length);
            Array.Copy(floodDistances, 0, distanceBuffer, 0, floodDistances.Length);

            //find cells that are being expanded to.
            if (stack == null)
            {
                stack = new List<CompactSpanReference>();
                for (int y = 0; y < length; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        CompactCell c = cells[x + y * width];
                        for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++)
                        {
                            //a cell is being expanded to if it's distance is greater than the current level,
                            //but no region has been asigned yet. It must also not be in a null area.
                            if (this.distances[i] >= level && regions[i] == 0 && areas[i].IsWalkable)
                                stack.Add(new CompactSpanReference(x, y, i));
                        }
                    }
                }
            }
            else
            {
                for (int j = 0; j < stack.Count; j++)
                {
                    if (regions[stack[j].Index] != 0)
                        stack[j] = CompactSpanReference.Null;
                }
            }

            //assign regions to all the cells that are being expanded to.
            //will run until it's done or it runs maxIterations times.
            int iter = 0;
            while (stack.Count > 0)
            {
                //spans in the stack that are skipped:
                // - assigned a region ID in an earlier iteration
                // - not neighboring any spans with region IDs
                int skipped = 0;

                for (int j = 0; j < stack.Count; j++)
                {
                    CompactSpanReference spanRef = stack[j];
                    int x = spanRef.X;
                    int y = spanRef.Y;
                    int i = spanRef.Index;

                    //skip regions already assigned to
                    if (i < 0)
                    {
                        skipped++;
                        continue;
                    }

                    RegionId r = regions[i];
                    Area area = areas[i];
                    CompactSpan s = spans[i];

                    //search direct neighbors for the one with the smallest distance value
                    int minDist = int.MaxValue;
                    for (var dir = Direction.West; dir <= Direction.South; dir++)
                    {
                        if (!s.IsConnected(dir))
                            continue;

                        int dx = x + dir.GetHorizontalOffset();
                        int dy = y + dir.GetVerticalOffset();
                        int di = cells[dx + dy * width].StartIndex + CompactSpan.GetConnection(ref s, dir);

                        if (areas[di] != area)
                            continue;

                        //compare distance to previous best
                        RegionId ri = regions[di];
                        int dist = floodDistances[di];
                        if (!(ri.IsNull || RegionId.HasFlags(ri, RegionFlags.Border)))
                        {
                            //set region and distance if better
                            if (dist + 2 < minDist)
                            {
                                r = ri;
                                minDist = dist + 2;
                            }
                        }
                    }

                    if (r != 0)
                    {
                        //set the region and distance for this span
                        regionBuffer[i] = r;
                        distanceBuffer[i] = minDist;

                        //mark this item in the stack as assigned for the next iteration.
                        stack[j] = CompactSpanReference.Null;
                    }
                    else
                    {
                        //skip spans that don't neighbor any regions
                        skipped++;
                    }
                }

                //if the entire stack is being skipped, we're done.
                if (skipped == stack.Count)
                    break;

                //Copy from the buffers back to the original arrays. This is done after each iteration
                //because changing it in-place has some side effects for the other spans in the stack.
                Array.Copy(regionBuffer, 0, regions, 0, regions.Length);
                Array.Copy(distanceBuffer, 0, floodDistances, 0, floodDistances.Length);

                if (level > 0)
                {
                    //if we hit maxIterations before expansion is done, break out anyways.
                    ++iter;
                    if (iter >= maxIterations)
                        break;
                }
            }
        }
Beispiel #29
0
        /// <summary>
        ///     地方と地域の対応付けを解除する
        /// </summary>
        /// <param name="regionId">地方</param>
        /// <param name="areaId">地域</param>
        private static void DetachRegionArea(RegionId regionId, AreaId areaId)
        {
            // 地方の項目がなければ何もしない
            if (!RegionAreaMap.ContainsKey(regionId))
            {
                return;
            }

            // 地域リストから地域を削除する
            if (RegionAreaMap[regionId].Contains(areaId))
            {
                RegionAreaMap[regionId].Remove(areaId);
                // 地域リストの項目がなくなれば地方の項目を削除する
                if (RegionAreaMap[regionId].Count == 0)
                {
                    RegionAreaMap.Remove(regionId);
                }
            }
        }