├── README.md ├── VoronoiElements.cs ├── PolyManager.cs ├── PolyInit.cs └── Voronoi.cs /README.md: -------------------------------------------------------------------------------- 1 | "# PolygonalMap" 2 | -------------------------------------------------------------------------------- /VoronoiElements.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.Collections.Generic; 4 | namespace lvlv_voronoi 5 | { 6 | 7 | //点 8 | public class Site 9 | { 10 | public double x, y; 11 | 12 | public Site() 13 | { } 14 | public Site(double x, double y) 15 | { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | } 20 | 21 | 22 | //三角形的边 23 | public class CenterEdge 24 | { 25 | 26 | public Center a, b; 27 | public CenterEdge(Center a, Center b) 28 | { 29 | this.a = a; 30 | this.b = b; 31 | 32 | } 33 | } 34 | 35 | public class CornerEdge 36 | { 37 | 38 | public Corner a, b; 39 | public CornerEdge(Corner a, Corner b) 40 | { 41 | this.a = a; 42 | this.b = b; 43 | 44 | } 45 | } 46 | public class Edge 47 | { 48 | 49 | public Site a, b; 50 | public Center ca, cb; 51 | public Corner cora, corb; 52 | public int river; 53 | public Edge(Site a, Site b,Center ca,Center cb) 54 | { 55 | this.a = a; 56 | this.b = b; 57 | this.ca = ca; 58 | this.cb = cb; 59 | 60 | } 61 | 62 | public Edge(Site a, Site b, Corner ca, Corner cb) 63 | { 64 | this.a = a; 65 | this.b = b; 66 | this.cora = ca; 67 | this.corb = cb; 68 | 69 | } 70 | } 71 | 72 | //自定义排序规则 73 | public class SiteSorterXY : IComparer 74 | { 75 | public int Compare(Site p1, Site p2) 76 | { 77 | if ( p1.x > p2.x ) return 1; 78 | if (p1.x < p2.x) return -1; 79 | return 0; 80 | } 81 | } 82 | public class CenterSorterXY : IComparer
83 | { 84 | public int Compare(Center p1, Center p2) 85 | { 86 | if (p1.point.x > p2.point.x) return 1; 87 | if (p1.point.x < p2.point.x) return -1; 88 | return 0; 89 | } 90 | } 91 | 92 | public class DelaunayTriangle 93 | { 94 | Voronoi voronoi = new Voronoi(); 95 | public Site site1, site2, site3;//三角形三点 96 | public Center center1, center2, center3; 97 | public Site centerPoint;//外界圆圆心 98 | public double radius;//外接圆半径 99 | public List adjoinTriangle;//邻接三角形 100 | 101 | 102 | 103 | public DelaunayTriangle(Site site1, Site site2, Site site3,Center center1, Center center2, Center center3) 104 | { 105 | centerPoint = new Site(); 106 | this.site1 = site1; 107 | this.site2 = site2; 108 | this.site3 = site3; 109 | this.center1 = center1; 110 | 111 | this.center2 = center2; 112 | 113 | this.center3 = center3; 114 | 115 | //构造外接圆圆心以及半径 116 | voronoi.circle_center(centerPoint, site1, site2, site3, ref radius); 117 | } 118 | } 119 | public enum BiomeType 120 | { 121 | SNOW, 122 | TUNDRA, 123 | ROCK, 124 | SCORCH, 125 | CONIFEROUS, 126 | SHRUB, 127 | TEMPERATE_DESERT, 128 | TEMPERATE_RAINFOREST, 129 | TEMPERATE_DECIDUOUS, 130 | GRASSLAND, 131 | RAINFOREST, 132 | TROPICAL_MONSOON, 133 | SUBTROPICAL_DESERT 134 | } 135 | public class Center 136 | { 137 | public int index; 138 | 139 | public Site point; // location 140 | public bool water; // lake or ocean 141 | public bool ocean; // ocean 142 | public bool coast; // land polygon touching an ocean 143 | public bool border; // at the edge of the map 144 | public BiomeType biome; // biome type (see article) 145 | public float elevation = 0; // 0.0-1.0 146 | public float moisture = 0; // 0.0-1.0 147 | 148 | public Dictionary neighbors; 149 | public Dictionary borders; 150 | public Dictionary corners; 151 | 152 | public Center() 153 | { 154 | neighbors = new Dictionary(); 155 | borders = new Dictionary(); 156 | corners = new Dictionary(); 157 | } 158 | } 159 | 160 | public class Corner 161 | { 162 | public int index; 163 | 164 | public Site point; // location 165 | public bool water; // lake or ocean 166 | public bool ocean; // ocean 167 | public bool coast; // land polygon touching an ocean 168 | public bool border; // at the edge of the map 169 | public float elevation = 0; // 0.0-1.0 170 | public float moisture = 0; // 0.0-1.0 171 | 172 | public Dictionary touches; 173 | public Dictionary protrudes; 174 | public Dictionary adjacent; 175 | 176 | public int river; // 0 if no river, or volume of water in river 177 | public Corner downslope; // pointer to adjacent corner most downhill 178 | public Corner watershed; // pointer to coastal corner, or null 179 | public int watershed_size; 180 | public int water_distance; 181 | 182 | public Corner() 183 | { 184 | touches = new Dictionary(); 185 | protrudes = new Dictionary(); 186 | adjacent = new Dictionary(); 187 | } 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /PolyManager.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using lvlv_voronoi; 5 | using System.Linq; 6 | using System.IO; 7 | using System; 8 | 9 | public class PolyManager : MonoBehaviour { 10 | voronoi voro = new voronoi(); 11 | 12 | public GameObject terrain; 13 | public Color[] biomeColor = new Color[13]; 14 | public Material[] biomeMat = new Material[13]; 15 | 16 | // Use this for initialization 17 | void Start () { 18 | voro.InitVoroni(500, 500, 400); 19 | voro.SetWater(0.03f,500,400); 20 | voro.SetOcean(); 21 | voro.SetElevation(); 22 | voro.SetRiver(UnityEngine.Random.Range(10, 15), 0.5f); 23 | voro.SetMoisture(0.3f); 24 | voro.SetBiome(voro.BioDiagram); 25 | //InitMeshData(terrain, 100); 26 | } 27 | 28 | // Update is called once per frame 29 | void Update () { 30 | 31 | } 32 | void OnPostRender() 33 | { 34 | GL.LoadOrtho(); 35 | 36 | for (int j = 0; j < voro.voronoiCenterList.Count; j++) 37 | { 38 | Dictionary edges = voro.voronoiCenterList[j].borders; 39 | Site center = voro.voronoiCenterList[j].point; 40 | 41 | 42 | foreach (KeyValuePair k in edges) 43 | { 44 | Color c = Color.black; 45 | if (voro.voronoiCenterList[j].water) 46 | { 47 | if (voro.voronoiCenterList[j].ocean) 48 | c = Color.blue; 49 | else 50 | { 51 | c = Color.blue; 52 | c.g += 0.8f; 53 | } 54 | 55 | } 56 | else if (voro.voronoiCenterList[j].coast) 57 | { 58 | c = new Color((float)193 / 255, (float)165 / 255, (float)124 / 255); 59 | } 60 | else 61 | { 62 | c = biomeColor[(int)voro.voronoiCenterList[j].biome]; 63 | 64 | } 65 | 66 | 67 | GL.Begin(GL.TRIANGLES); 68 | GL.Color(c); 69 | GL.Vertex3((float)k.Value.a.x / Screen.width, (float)k.Value.a.y / Screen.height, 0); 70 | GL.Vertex3((float)k.Value.b.x / Screen.width, (float)k.Value.b.y / Screen.height, 0); 71 | GL.Vertex3((float)center.x / Screen.width, (float)center.y / Screen.height, 0); 72 | GL.End(); 73 | } 74 | 75 | } 76 | for (int i = 0; i < voro.voronoiEdgeList.Count; i++) 77 | { 78 | Color c = Color.black; 79 | GL.Begin(GL.LINES); 80 | 81 | Edge e = voro.voronoiEdgeList[i]; 82 | if (e.cora.water && e.corb.water) 83 | { 84 | c = Color.blue; 85 | } 86 | if (e.cora.coast && e.corb.coast) 87 | { 88 | c = Color.red; 89 | } 90 | if (e.cora.river > 0) 91 | { 92 | c = (Color.blue + new Color(0, 0.8f, 0)); 93 | } 94 | GL.Color(c); 95 | GL.Vertex3((float)e.a.x / Screen.width, (float)e.a.y / Screen.height, 0); 96 | GL.Vertex3((float)e.b.x / Screen.width, (float)e.b.y / Screen.height, 0); 97 | GL.End(); 98 | } 99 | } 100 | 101 | void InitMeshData(GameObject gameObject,float maxHeight) 102 | { 103 | List triangles = new List(); 104 | Dictionary vertexes = new Dictionary(); 105 | Dictionary biomeValue = new Dictionary(); 106 | Dictionary biomeDis = new Dictionary(); 107 | Texture2D biomeTexture = new Texture2D(500, 400); 108 | Color[,] textureColor = new Color[600, 500]; 109 | Queue> queue = new Queue>(); 110 | 111 | for (int i=0;i k in voro.voronoiCornerList) 128 | { 129 | Site s = k.Key; 130 | 131 | Vector3 v = new Vector3((float)s.x, k.Value.elevation * maxHeight, (float)s.y); 132 | v += gameObject.transform.position; 133 | Vector4 v4 = v; 134 | v4.w = vertexes.Count; 135 | vertexes.Add(s,v4); 136 | int sumBio = 0; 137 | foreach(KeyValuePair kc in k.Value.touches) 138 | { 139 | sumBio += (int)kc.Value.biome; 140 | } 141 | 142 | float c = (float)sumBio / (float)13; 143 | int x = (int)s.x; 144 | int y = (int)s.y; 145 | 146 | 147 | 148 | } 149 | Dictionary biomeDic = new Dictionary(); 150 | for (int i = 0; i < voro.voronoiCenterList.Count; i++) 151 | { 152 | Center c = voro.voronoiCenterList[i]; 153 | 154 | if(!c.water) 155 | { 156 | foreach(KeyValuePair k in c.borders) 157 | { 158 | Vector4 v4; 159 | vertexes.TryGetValue(c.point, out v4); 160 | triangles.Add((int)v4.w); 161 | biomeDic.Add(triangles.Count - 1, (int)c.biome); 162 | double x1, x2, y1, y2; 163 | x1 = k.Value.a.x - c.point.x; 164 | x2 = k.Value.b.x - c.point.x; 165 | y1 = k.Value.a.y - c.point.y; 166 | y2 = k.Value.b.y - c.point.y; 167 | float j = (float)(x1 * y2 - x2 * y1); 168 | if (j < 0) 169 | { 170 | vertexes.TryGetValue(k.Value.a, out v4); 171 | triangles.Add((int)v4.w); 172 | biomeDic.Add(triangles.Count - 1, (int)c.biome); 173 | 174 | vertexes.TryGetValue(k.Value.b, out v4); 175 | triangles.Add((int)v4.w); 176 | biomeDic.Add(triangles.Count - 1, (int)c.biome); 177 | } 178 | else 179 | { 180 | vertexes.TryGetValue(k.Value.b, out v4); 181 | triangles.Add((int)v4.w); 182 | biomeDic.Add(triangles.Count - 1, (int)c.biome); 183 | 184 | vertexes.TryGetValue(k.Value.a, out v4); 185 | triangles.Add((int)v4.w); 186 | biomeDic.Add(triangles.Count - 1, (int)c.biome); 187 | } 188 | } 189 | } 190 | } 191 | 192 | Vector3[] vertexesArray = new Vector3[vertexes.Count]; 193 | int[] trianglesArray = new int[triangles.Count]; 194 | Vector2[] uvArray = new Vector2[vertexes.Count]; 195 | List[] trianglesList = new List[13]; 196 | for(int i=0;i<13;i++) 197 | { 198 | trianglesList[i] = new List(); 199 | } 200 | 201 | 202 | foreach(KeyValuePair k in vertexes) 203 | { 204 | Vector3 v3 = k.Value; 205 | vertexesArray[(int)k.Value.w] = v3; 206 | uvArray[(int)k.Value.w] = new Vector2(v3.x / 500, v3.z / 400); 207 | } 208 | for(int i=0;i().mesh; 215 | 216 | 217 | gameObject.AddComponent(); 218 | 219 | 220 | gameObject.GetComponent().materials = biomeMat; 221 | for(int i=0;i<13;i++) 222 | { 223 | gameObject.GetComponent().materials[i].color = biomeColor[i]; 224 | } 225 | 226 | /*设置mesh*/ 227 | mesh.Clear();//更新 228 | mesh.vertices = vertexesArray; 229 | mesh.uv = uvArray; 230 | mesh.triangles = trianglesArray; 231 | mesh.subMeshCount = 13; 232 | for(int i=0;i<13;i++) 233 | { 234 | mesh.SetTriangles(trianglesList[i], i); 235 | } 236 | 237 | mesh.RecalculateNormals(); 238 | mesh.RecalculateBounds(); 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /PolyInit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Collections.Generic; 4 | using UnityEngine; 5 | 6 | 7 | namespace lvlv_voronoi 8 | { 9 | 10 | public class voronoi 11 | { 12 | public BiomeType[,] BioDiagram = new BiomeType[4, 6] 13 | { 14 | {BiomeType.SUBTROPICAL_DESERT,BiomeType.GRASSLAND,BiomeType.TROPICAL_MONSOON,BiomeType.TROPICAL_MONSOON,BiomeType.RAINFOREST,BiomeType.RAINFOREST }, 15 | {BiomeType.TEMPERATE_DESERT,BiomeType.GRASSLAND,BiomeType.GRASSLAND,BiomeType.TEMPERATE_DECIDUOUS,BiomeType.TEMPERATE_DECIDUOUS,BiomeType.TEMPERATE_RAINFOREST }, 16 | {BiomeType.TEMPERATE_DESERT,BiomeType.TEMPERATE_DESERT,BiomeType.SHRUB,BiomeType.SHRUB,BiomeType.CONIFEROUS,BiomeType.CONIFEROUS }, 17 | {BiomeType.SCORCH,BiomeType.ROCK,BiomeType.TUNDRA,BiomeType.SNOW,BiomeType.SNOW,BiomeType.SNOW } 18 | }; 19 | System.Random seeder; 20 | public List
voronoiCenterList = new List
();//voroni图所有的中心点 21 | public Dictionary voronoiCornerList = new Dictionary();//voroni图所有的拐角点 22 | public List voronoiEdgeList = new List();//vironoi图所有边 23 | 24 | Voronoi voroObject = new Voronoi(); 25 | 26 | 27 | public voronoi() 28 | { 29 | 30 | //初始化随机数对象 31 | seeder = new System.Random(); 32 | 33 | } 34 | 35 | 36 | public void InitVoroni(int siteCount,int width,int height) 37 | { 38 | List allTriangle = new List();//delaunay三角形集合 39 | List sitesP = new List(); 40 | int seed = seeder.Next(); 41 | System.Random rand = new System.Random(seed); 42 | List trianglesEdgeList = new List();//Delaunay三角形网所有边 43 | 44 | List voronoiRayEdgeList = new List();//voroni图外围射线边 45 | //初始设定点数为20 46 | //初始设定画布大小是500*400 47 | //超级三角形顶点坐标为(250,0),(0,400),(500,400) 48 | //点集区域为(125,200),(125,400),(375,200),(375,400),随便设置,只要满足点落在三角形区域中 49 | for (int i = 0; i < siteCount; i++) 50 | { 51 | 52 | Vector2 pf = new Vector2((float)(rand.NextDouble() * width), (float)(rand.NextDouble() * height)); 53 | //PointF pf=new PointF((float)(rand.NextDouble() * 250 + 125), (float)(rand.NextDouble() * 200 + 200)); 54 | Site site = new Site(pf.x, pf.y); 55 | sitesP.Add(site); 56 | Center c = new Center(); 57 | c.point = site; 58 | voronoiCenterList.Add(c); 59 | 60 | } 61 | 62 | //按点集坐标X值排序 63 | sitesP.Sort(new SiteSorterXY()); 64 | voronoiCenterList.Sort(new CenterSorterXY()); 65 | for (int i = 0; i < voronoiCenterList.Count; i++) 66 | { 67 | voronoiCenterList[i].index = i; 68 | } 69 | 70 | 71 | int relaxNum = 2; 72 | for (int r = 0; r < relaxNum; r++) 73 | { 74 | if (r > 0) 75 | { 76 | allTriangle.Clear(); 77 | trianglesEdgeList.Clear(); 78 | voronoiEdgeList.Clear(); 79 | voronoiRayEdgeList.Clear(); 80 | voronoiCornerList.Clear(); 81 | 82 | for (int t = 0; t < voronoiCenterList.Count; t++) 83 | { 84 | bool isBorder = false; 85 | double sumx = 0, sumy = 0; 86 | double num = voronoiCenterList[t].corners.Count; 87 | foreach (KeyValuePair k in voronoiCenterList[t].corners) 88 | { 89 | if (k.Value.point.x <= 20 || k.Value.point.x >= width - 20 || k.Value.point.y <= 20 || k.Value.point.y >= height - 20) 90 | { 91 | isBorder = true; 92 | break; 93 | } 94 | sumx += k.Value.point.x; 95 | sumy += k.Value.point.y; 96 | } 97 | Center c = new Center(); 98 | if (!isBorder) 99 | { 100 | c.point = new Site(sumx / num, sumy / num); 101 | voronoiCenterList[t] = c; 102 | sitesP[t] = new Site(sumx / num, sumy / num); 103 | } 104 | else 105 | { 106 | c.point = voronoiCenterList[t].point; 107 | c.border = true; 108 | voronoiCenterList[t] = c; 109 | sitesP[t] = c.point; 110 | } 111 | } 112 | 113 | 114 | } 115 | 116 | //将超级三角形的三点添加到三角形网中 117 | Site A = new Site(0, 0); 118 | Site B = new Site(width, 0); 119 | Site C = new Site(0, height); 120 | Site D = new Site(width, height); 121 | Center CA = new Center(); 122 | CA.point = A; 123 | CA.index = -1; 124 | Center CB = new Center(); 125 | CB.point = B; 126 | CB.index = -1; 127 | Center CC = new Center(); 128 | CC.point = C; 129 | CC.index = -1; 130 | Center CD = new Center(); 131 | CD.point = D; 132 | CD.index = -1; 133 | sitesP.Add(A); 134 | sitesP.Add(B); 135 | sitesP.Add(C); 136 | sitesP.Add(D); 137 | 138 | voronoiCenterList.Add(CA); 139 | voronoiCenterList.Add(CB); 140 | voronoiCenterList.Add(CC); 141 | voronoiCenterList.Add(CD); 142 | 143 | DelaunayTriangle dt = new DelaunayTriangle(A, B, C, CA, CB, CC); 144 | DelaunayTriangle dt2 = new DelaunayTriangle(D, B, C, CD, CB, CC); 145 | allTriangle.Add(dt); 146 | allTriangle.Add(dt2); 147 | //构造Delaunay三角形网 148 | voroObject.setDelaunayTriangle(allTriangle, sitesP, voronoiCenterList); 149 | 150 | sitesP.Sort(new SiteSorterXY()); 151 | voronoiCenterList.Sort(new CenterSorterXY()); 152 | for (int i = 0; i < voronoiCenterList.Count; i++) 153 | { 154 | voronoiCenterList[i].index = i; 155 | } 156 | // 157 | //不要移除,这样就不用画Delaunay三角形网外围边的射线 158 | //移除超级三角形 159 | //voroObject.remmoveTrianglesByOnePoint(allTriangle, A); 160 | //voroObject.remmoveTrianglesByOnePoint(allTriangle, B); 161 | //voroObject.remmoveTrianglesByOnePoint(allTriangle, C); 162 | 163 | //返回Delaunay三角形网所有边 164 | trianglesEdgeList = voroObject.returnEdgesofTriangleList(allTriangle); 165 | 166 | 167 | 168 | //填充neighbor 169 | for (int i = 0; i < allTriangle.Count; i++) 170 | { 171 | DelaunayTriangle t = allTriangle[i]; 172 | try 173 | { 174 | t.center1.neighbors.Add(t.center2.index, t.center2); 175 | } 176 | catch (ArgumentException) 177 | { 178 | 179 | } 180 | try 181 | { 182 | t.center1.neighbors.Add(t.center3.index, t.center2); 183 | } 184 | catch (ArgumentException) 185 | { 186 | 187 | } 188 | try 189 | { 190 | t.center2.neighbors.Add(t.center1.index, t.center1); 191 | } 192 | catch (ArgumentException) 193 | { 194 | 195 | } 196 | try 197 | { 198 | t.center2.neighbors.Add(t.center3.index, t.center3); 199 | } 200 | catch (ArgumentException) 201 | { 202 | 203 | } 204 | try 205 | { 206 | t.center3.neighbors.Add(t.center1.index, t.center1); 207 | 208 | } 209 | catch (ArgumentException) 210 | { 211 | 212 | } 213 | try 214 | { 215 | t.center3.neighbors.Add(t.center2.index, t.center2); 216 | } 217 | catch (ArgumentException) 218 | { 219 | 220 | } 221 | 222 | 223 | } 224 | //获取所有Voronoi边 225 | voronoiEdgeList = voroObject.returnVoronoiEdgesFromDelaunayTriangles(allTriangle, voronoiRayEdgeList, voronoiCenterList, voronoiCornerList); 226 | 227 | foreach (KeyValuePair k in voronoiCornerList) 228 | { 229 | if (k.Value.point.x <= 20 || k.Value.point.x >= width - 20 || k.Value.point.y <= 20 || k.Value.point.y >= height - 20) 230 | { 231 | k.Value.border = true; 232 | 233 | } 234 | } 235 | 236 | } 237 | 238 | 239 | 240 | } 241 | Texture2D spreadPoints() 242 | { 243 | 244 | Texture2D texture = new Texture2D(1000, 800); 245 | 246 | 247 | 248 | 249 | return texture; 250 | } 251 | 252 | 253 | public void SetWater(float waterRate,int width,int height) 254 | { 255 | foreach(KeyValuePair k in voronoiCornerList) 256 | { 257 | if (k.Value.border || Mathf.PerlinNoise((float)k.Key.x, (float)k.Key.y) < waterRate + 0.0008f * Vector2.Distance(new Vector2((float)k.Key.x, (float)k.Key.y), new Vector2(width / 2, height / 2))) 258 | { 259 | k.Value.water = true; 260 | foreach(KeyValuePair kc in k.Value.touches) 261 | { 262 | kc.Value.water = true; 263 | } 264 | } 265 | } 266 | } 267 | 268 | public void SetOcean() 269 | { 270 | Queue
queue = new Queue
(); 271 | for(int i=0;i ck in voronoiCenterList[i].corners) 278 | { 279 | ck.Value.ocean = true; 280 | ck.Value.water = true; 281 | } 282 | queue.Enqueue(voronoiCenterList[i]); 283 | } 284 | } 285 | while(queue.Count > 0) 286 | { 287 | Center c = queue.Dequeue(); 288 | foreach(KeyValuePair k in c.neighbors) 289 | { 290 | if(!k.Value.ocean) 291 | { 292 | if(k.Value.water) 293 | { 294 | k.Value.ocean = true; 295 | foreach(KeyValuePair ck in k.Value.corners) 296 | { 297 | ck.Value.ocean = true; 298 | ck.Value.water = true; 299 | } 300 | queue.Enqueue(k.Value); 301 | } 302 | else 303 | { 304 | foreach (KeyValuePair ck in k.Value.corners) 305 | { 306 | ck.Value.coast = true; 307 | } 308 | k.Value.coast = true; 309 | } 310 | } 311 | } 312 | } 313 | 314 | } 315 | 316 | public void SetElevation() 317 | { 318 | Queue queue = new Queue(); 319 | foreach(KeyValuePair k in voronoiCornerList) 320 | { 321 | if(k.Value.coast) 322 | { 323 | k.Value.elevation = 0.0f; 324 | queue.Enqueue(k.Value); 325 | } 326 | else 327 | { 328 | k.Value.elevation = -1; 329 | } 330 | foreach(KeyValuePair kcen in k.Value.touches) 331 | { 332 | if(kcen.Value.water) 333 | { 334 | k.Value.water = true; 335 | break; 336 | } 337 | } 338 | } 339 | 340 | while(queue.Count > 0) 341 | { 342 | Corner c = queue.Dequeue(); 343 | float newElevation = c.elevation + 0.01f; 344 | foreach(KeyValuePair k in c.adjacent) 345 | { 346 | 347 | if (!c.water && !k.Value.water) 348 | { 349 | newElevation += 1; 350 | newElevation += UnityEngine.Random.Range(0, 10); 351 | } 352 | if(newElevation < k.Value.elevation || k.Value.elevation < 0 ) 353 | { 354 | k.Value.elevation = newElevation; 355 | 356 | queue.Enqueue(k.Value); 357 | } 358 | } 359 | 360 | } 361 | 362 | float maxElevation = 0; 363 | 364 | foreach(KeyValuePair k in voronoiCornerList) 365 | { 366 | if(k.Value.elevation > maxElevation) 367 | { 368 | maxElevation = k.Value.elevation; 369 | } 370 | } 371 | foreach (KeyValuePair k in voronoiCornerList) 372 | { 373 | k.Value.elevation /= maxElevation; 374 | float maxEle = 0; 375 | Corner temp = null; 376 | foreach (KeyValuePair kc in k.Value.adjacent) 377 | { 378 | if((k.Value.elevation - kc.Value.elevation)>maxEle) 379 | { 380 | maxEle = k.Value.elevation - kc.Value.elevation; 381 | temp = kc.Value; 382 | } 383 | } 384 | k.Value.downslope = temp; 385 | } 386 | for(int i=0;i k in voronoiCenterList[i].corners) 390 | { 391 | sumEle += k.Value.elevation; 392 | } 393 | voronoiCenterList[i].elevation = sumEle / voronoiCenterList[i].corners.Count; 394 | } 395 | 396 | } 397 | 398 | public void SetRiver(int RiverCount,float minElevation) 399 | { 400 | for (int i = 0; i < RiverCount; i++) 401 | { 402 | Corner startCorner = null; 403 | while (startCorner == null || startCorner.elevation <= minElevation) 404 | { 405 | int pos = UnityEngine.Random.Range(0, voronoiCornerList.Count); 406 | startCorner = voronoiCornerList.Values.ElementAt(pos); 407 | } 408 | Corner nextCorner = startCorner; 409 | while(nextCorner!=null && !nextCorner.water) 410 | { 411 | nextCorner.river += 1; 412 | nextCorner = nextCorner.downslope; 413 | } 414 | } 415 | } 416 | 417 | public void SetMoisture(float wet) 418 | { 419 | Queue queue = new Queue(); 420 | foreach (KeyValuePair k in voronoiCornerList) 421 | { 422 | if ((k.Value.water && !k.Value.ocean) || k.Value.coast || k.Value.river > 0) 423 | { 424 | k.Value.water_distance = 0; 425 | queue.Enqueue(k.Value); 426 | } 427 | else 428 | { 429 | k.Value.water_distance = -1; 430 | } 431 | } 432 | 433 | while (queue.Count > 0) 434 | { 435 | Corner c = queue.Dequeue(); 436 | int newWaterdistance = c.water_distance + 1; 437 | foreach (KeyValuePair k in c.adjacent) 438 | { 439 | 440 | if (!c.water && !k.Value.water) 441 | { 442 | newWaterdistance += 1; 443 | } 444 | if (newWaterdistance < k.Value.elevation || k.Value.elevation < 0) 445 | { 446 | k.Value.water_distance = newWaterdistance; 447 | queue.Enqueue(k.Value); 448 | } 449 | } 450 | 451 | } 452 | 453 | foreach (KeyValuePair k in voronoiCornerList) 454 | { 455 | k.Value.moisture = Mathf.Pow(UnityEngine.Random.Range(0.95f, 1) * wet, k.Value.water_distance); 456 | } 457 | float maxMoisture = 0; 458 | foreach (KeyValuePair k in voronoiCornerList) 459 | { 460 | if(k.Value.moisture > maxMoisture) 461 | { 462 | maxMoisture = k.Value.moisture; 463 | } 464 | } 465 | foreach (KeyValuePair k in voronoiCornerList) 466 | { 467 | 468 | k.Value.moisture /= maxMoisture; 469 | 470 | } 471 | 472 | for (int i = 0; i < voronoiCenterList.Count; i++) 473 | { 474 | float sumMoi = 0; 475 | foreach (KeyValuePair k in voronoiCenterList[i].corners) 476 | { 477 | sumMoi += k.Value.moisture; 478 | } 479 | voronoiCenterList[i].moisture = sumMoi / voronoiCenterList[i].corners.Count; 480 | } 481 | } 482 | 483 | public void SetBiome(BiomeType[,] BiomeDiagram) 484 | { 485 | for(int i=0;i returnVoronoiEdgesFromDelaunayTriangles(List allTriangle, List voronoiRayEdgeList,List
voronoiCenterList,Dictionary voronoiCornerList) 11 | { 12 | List voronoiEdgeList = new List(); 13 | //List voronoiRayEdgeList = new List(); 14 | for (int i = 0; i < allTriangle.Count; i++) 15 | { 16 | List neighborEdgeList=new List();//三角形邻接边集合 17 | for (int j = 0; j < allTriangle.Count; j++)//为了找出邻接三角形数为2的三角形,即最外边的三角形,循环只能从0开始 18 | { 19 | if (j != i)//不与自身比较 20 | { 21 | Edge neighborEdge = findCommonEdge(allTriangle[i], allTriangle[j]); 22 | if (neighborEdge != null) 23 | { 24 | neighborEdgeList.Add(neighborEdge); 25 | //构造Voronoi边 26 | Corner c1, c2; 27 | if (!voronoiCornerList.TryGetValue(allTriangle[i].centerPoint, out c1)) 28 | { 29 | c1 = new Corner(); 30 | c1.point = allTriangle[i].centerPoint; 31 | c1.index = voronoiCornerList.Count; 32 | voronoiCornerList.Add(allTriangle[i].centerPoint, c1); 33 | } 34 | if (!voronoiCornerList.TryGetValue(allTriangle[j].centerPoint, out c2)) 35 | { 36 | c2 = new Corner(); 37 | c2.point = allTriangle[j].centerPoint; 38 | c2.index = voronoiCornerList.Count; 39 | voronoiCornerList.Add(allTriangle[j].centerPoint, c2); 40 | } 41 | Edge voronoiEdge = new Edge(allTriangle[i].centerPoint, allTriangle[j].centerPoint,c1,c2); 42 | if (!voronoiEdgeList.Contains(voronoiEdge)) 43 | { 44 | voronoiEdgeList.Add(voronoiEdge); 45 | 46 | //c1的touches添加 47 | try 48 | { 49 | c1.touches.Add(neighborEdge.ca.index, neighborEdge.ca); 50 | } 51 | catch(ArgumentException) 52 | { 53 | 54 | } 55 | try 56 | { 57 | c1.touches.Add(neighborEdge.cb.index, neighborEdge.cb); 58 | } 59 | catch (ArgumentException) 60 | { 61 | 62 | } 63 | 64 | //c2的touches添加 65 | try 66 | { 67 | c2.touches.Add(neighborEdge.ca.index, neighborEdge.ca); 68 | } 69 | catch (ArgumentException) 70 | { 71 | 72 | } 73 | try 74 | { 75 | c2.touches.Add(neighborEdge.cb.index, neighborEdge.cb); 76 | } 77 | catch (ArgumentException) 78 | { 79 | 80 | } 81 | 82 | //c1的protrudes添加 83 | try 84 | { 85 | c1.protrudes.Add(voronoiEdge, voronoiEdge); 86 | } 87 | catch (ArgumentException) 88 | { 89 | 90 | } 91 | 92 | //c2的protrudes添加 93 | try 94 | { 95 | c2.protrudes.Add(voronoiEdge, voronoiEdge); 96 | } 97 | catch (ArgumentException) 98 | { 99 | 100 | } 101 | 102 | //c1的adjacent添加 103 | try 104 | { 105 | c1.adjacent.Add(c2.index, c2); 106 | } 107 | catch (ArgumentException) 108 | { 109 | 110 | } 111 | 112 | //c2的adjacent添加 113 | try 114 | { 115 | c2.adjacent.Add(c1.index, c1); 116 | } 117 | catch (ArgumentException) 118 | { 119 | 120 | } 121 | 122 | //A的corners添加 123 | try 124 | { 125 | neighborEdge.ca.corners.Add(c1.point, c1); 126 | } 127 | catch (ArgumentException) 128 | { 129 | 130 | } 131 | try 132 | { 133 | neighborEdge.ca.corners.Add(c2.point, c2); 134 | } 135 | catch (ArgumentException) 136 | { 137 | 138 | } 139 | 140 | //B的corners添加 141 | try 142 | { 143 | neighborEdge.cb.corners.Add(c1.point, c1); 144 | } 145 | catch (ArgumentException) 146 | { 147 | 148 | } 149 | try 150 | { 151 | neighborEdge.cb.corners.Add(c2.point, c2); 152 | } 153 | catch (ArgumentException) 154 | { 155 | 156 | } 157 | 158 | //A的borders添加 159 | try 160 | { 161 | neighborEdge.ca.borders.Add(voronoiEdge, voronoiEdge); 162 | } 163 | catch (ArgumentException) 164 | { 165 | 166 | } 167 | 168 | //B的borders添加 169 | try 170 | { 171 | neighborEdge.cb.borders.Add(voronoiEdge, voronoiEdge); 172 | } 173 | catch (ArgumentException) 174 | { 175 | 176 | } 177 | 178 | } 179 | } 180 | } 181 | } 182 | if (neighborEdgeList.Count== 2)//表示此三角形是外围三角形,Voronoi边需要射线 183 | { 184 | Site midpoint; 185 | Edge rayEdge = null; 186 | Corner c1, c2 = null; 187 | Center a=null, b=null; 188 | 189 | if (!voronoiCornerList.TryGetValue(allTriangle[i].centerPoint, out c1)) 190 | { 191 | c1 = new Corner(); 192 | c1.point = allTriangle[i].centerPoint; 193 | c1.index = voronoiCornerList.Count; 194 | voronoiCornerList.Add(allTriangle[i].centerPoint, c1); 195 | } 196 | //找出最外边并寻找中点构造Voronoi射线边 197 | if (isPointOnEdge(neighborEdgeList[0], allTriangle[i].site1) && isPointOnEdge(neighborEdgeList[1], allTriangle[i].site1)) 198 | { 199 | midpoint = findMidPoint(allTriangle[i].site2, allTriangle[i].site3); 200 | rayEdge = produceRayEdge(allTriangle[i].centerPoint, midpoint);//产生较长的射线,原理实现还是线段画出的线 201 | voronoiRayEdgeList.Add(rayEdge); 202 | a = allTriangle[i].center2; 203 | b = allTriangle[i].center3; 204 | 205 | } 206 | if (isPointOnEdge(neighborEdgeList[0], allTriangle[i].site2) && isPointOnEdge(neighborEdgeList[1], allTriangle[i].site2)) 207 | { 208 | midpoint = findMidPoint(allTriangle[i].site1, allTriangle[i].site3); 209 | rayEdge = produceRayEdge(allTriangle[i].centerPoint, midpoint); 210 | voronoiRayEdgeList.Add(rayEdge); 211 | a = allTriangle[i].center1; 212 | b = allTriangle[i].center3; 213 | 214 | } 215 | if (isPointOnEdge(neighborEdgeList[0], allTriangle[i].site3) && isPointOnEdge(neighborEdgeList[1], allTriangle[i].site3)) 216 | { 217 | midpoint = findMidPoint(allTriangle[i].site1, allTriangle[i].site2); 218 | rayEdge = produceRayEdge(allTriangle[i].centerPoint, midpoint); 219 | voronoiRayEdgeList.Add(rayEdge); 220 | a = allTriangle[i].center1; 221 | b = allTriangle[i].center2; 222 | 223 | } 224 | 225 | if (rayEdge != null && !voronoiCornerList.TryGetValue(rayEdge.b, out c2)) 226 | { 227 | c2 = new Corner(); 228 | c2.point = rayEdge.b; 229 | c2.index = voronoiCornerList.Count; 230 | 231 | voronoiCornerList.Add(rayEdge.b, c2); 232 | } 233 | 234 | 235 | 236 | //c2的touches添加 237 | try 238 | { 239 | c2.touches.Add(a.index, a); 240 | } 241 | catch (ArgumentException) 242 | { 243 | 244 | } 245 | try 246 | { 247 | c2.touches.Add(b.index, b); 248 | } 249 | catch (ArgumentException) 250 | { 251 | 252 | } 253 | Edge borderEdge = new Edge(a.point, b.point, a, b); 254 | //c1的protrudes添加 255 | try 256 | { 257 | c1.protrudes.Add(borderEdge, borderEdge); 258 | } 259 | catch (ArgumentException) 260 | { 261 | 262 | } 263 | 264 | //c2的protrudes添加 265 | 266 | try 267 | { 268 | 269 | c2.protrudes.Add(borderEdge, borderEdge); 270 | } 271 | catch (ArgumentException) 272 | { 273 | 274 | } 275 | 276 | //c1的adjacent添加 277 | try 278 | { 279 | c1.adjacent.Add(c2.index, c2); 280 | } 281 | catch (ArgumentException) 282 | { 283 | 284 | } 285 | 286 | //c2的adjacent添加 287 | try 288 | { 289 | c2.adjacent.Add(c1.index, c1); 290 | } 291 | catch (ArgumentException) 292 | { 293 | 294 | } 295 | 296 | //A的corners添加 297 | try 298 | { 299 | a.corners.Add(c2.point, c2); 300 | } 301 | catch (ArgumentException) 302 | { 303 | 304 | } 305 | 306 | 307 | //B的corners添加 308 | try 309 | { 310 | b.corners.Add(c2.point, c2); 311 | } 312 | catch (ArgumentException) 313 | { 314 | 315 | } 316 | 317 | 318 | //A的borders添加 319 | try 320 | { 321 | a.borders.Add(borderEdge, borderEdge); 322 | } 323 | catch (ArgumentException) 324 | { 325 | 326 | } 327 | 328 | //B的borders添加 329 | try 330 | { 331 | b.borders.Add(borderEdge, borderEdge); 332 | } 333 | catch (ArgumentException) 334 | { 335 | 336 | } 337 | } 338 | } 339 | return voronoiEdgeList; 340 | } 341 | 342 | //根据三角形链表返回三角形所有的边 343 | public List returnEdgesofTriangleList(List allTriangle) 344 | { 345 | List commonEdges = new List(); 346 | for (int i = 0; i < allTriangle.Count; i++) 347 | { 348 | Edge edge1 = new Edge(allTriangle[i].site1, allTriangle[i].site2,allTriangle[i].center1,allTriangle[i].center2); 349 | Edge edge2 = new Edge(allTriangle[i].site1, allTriangle[i].site3, allTriangle[i].center1, allTriangle[i].center3); 350 | Edge edge3 = new Edge(allTriangle[i].site2, allTriangle[i].site3, allTriangle[i].center2, allTriangle[i].center3); 351 | if (!commonEdges.Contains(edge1)) 352 | commonEdges.Add(edge1); 353 | if (!commonEdges.Contains(edge2)) 354 | commonEdges.Add(edge2); 355 | if (!commonEdges.Contains(edge3)) 356 | commonEdges.Add(edge3); 357 | } 358 | return commonEdges; 359 | } 360 | 361 | //根据点集构造Delaunay三角形网 362 | public void setDelaunayTriangle(List allTriangle, List sites,List
centers) 363 | { 364 | 365 | for (int i = 0; i < sites.Count; i++) 366 | { 367 | List tmpTriList = new List(); 368 | //拷贝所有三角形 369 | for (int j = 0; j < allTriangle.Count; j++) 370 | { 371 | tmpTriList.Add(allTriangle[j]); 372 | } 373 | 374 | //受影响的三角形链表 375 | List influenedTriangles = new List(); 376 | //新形成的三角形链表 377 | List newTriangles = new List(); 378 | //受影响三角形的公共边 379 | List commonEdges = new List(); 380 | 381 | for (int j = 0; j < tmpTriList.Count; j++) 382 | { 383 | double lengthToCenter;//该点到圆心距离 384 | lengthToCenter = distance2Point(tmpTriList[j].centerPoint, sites[i]); 385 | if (lengthToCenter < tmpTriList[j].radius) 386 | { 387 | influenedTriangles.Add(tmpTriList[j]);//添加到受影响的三角形链表 388 | allTriangle.Remove(tmpTriList[j]);//移除当前三角形 389 | } 390 | } 391 | 392 | //从受影响的三角形链表中,形成新的三角形链表 393 | for(int k=0;k 1) 400 | { 401 | commonEdges = findCommonEdges(influenedTriangles); 402 | } 403 | //将受影响三角形中的公共边所在的新形成的三角形排除 404 | if (commonEdges.Count>0) 405 | { 406 | remmoveTrianglesByEdges(newTriangles, commonEdges); 407 | } 408 | //对新形成的三角形进行局部优化 409 | LOP(newTriangles); 410 | //将优化后的新形成的三角形添加到三角形链表中 411 | for (int k = 0; k < newTriangles.Count; k++) 412 | { 413 | allTriangle.Add(newTriangles[k]); 414 | } 415 | } 416 | } 417 | 418 | //移除所有边边所在的三角形 419 | public void remmoveTrianglesByEdges(List allTriangles, List edges) 420 | { 421 | 422 | List tmpTriList=new List(); 423 | //拷贝所有三角形 424 | for (int i = 0; i < allTriangles.Count; i++) 425 | { 426 | tmpTriList.Add(allTriangles[i]); 427 | } 428 | 429 | for (int i = 0; i < tmpTriList.Count; i++) 430 | { 431 | for (int j = 0; j < edges.Count; j++) 432 | { 433 | if (isEdgeOnTriangle(tmpTriList[i], edges[j])) 434 | { 435 | allTriangles.Remove(tmpTriList[i]); 436 | } 437 | } 438 | } 439 | } 440 | 441 | //移除一条边所在的三角形 442 | public void remmoveTrianglesByOneEdge(List allTriangles, Edge edge) 443 | { 444 | List tmpTriList = new List(); 445 | //拷贝所有三角形 446 | for (int i = 0; i < allTriangles.Count; i++) 447 | { 448 | tmpTriList.Add(allTriangles[i]); 449 | } 450 | for (int i = 0; i < tmpTriList.Count; i++) 451 | { 452 | if (isEdgeOnTriangle(tmpTriList[i], edge)) 453 | allTriangles.Remove(tmpTriList[i]); 454 | } 455 | } 456 | 457 | //移除点所在的三角形 458 | public void remmoveTrianglesByOnePoint(List allTriangles, Site site) 459 | { 460 | List tmpTriList = new List(); 461 | //拷贝所有三角形 462 | for (int i = 0; i < allTriangles.Count; i++) 463 | { 464 | tmpTriList.Add(allTriangles[i]); 465 | } 466 | for (int i = 0; i < tmpTriList.Count; i++) 467 | { 468 | if (isPointOnTriangle(tmpTriList[i], site)) 469 | allTriangles.Remove(tmpTriList[i]); 470 | } 471 | } 472 | 473 | //判断边是否属于三角形 474 | public bool isEdgeOnTriangle(DelaunayTriangle triangel,Edge edge) 475 | { 476 | int samePointNum = 0; 477 | if (siteIsEqual(edge.a, triangel.site1) || siteIsEqual(edge.a, triangel.site2) || siteIsEqual(edge.a, triangel.site3)) 478 | samePointNum++; 479 | if (siteIsEqual(edge.b, triangel.site1) || siteIsEqual(edge.b, triangel.site2) || siteIsEqual(edge.b, triangel.site3)) 480 | samePointNum++; 481 | if(samePointNum==2) 482 | return true; 483 | return false; 484 | } 485 | 486 | //判断点是否属于三角形 487 | public bool isPointOnTriangle(DelaunayTriangle triangle, Site site) 488 | { 489 | if (siteIsEqual(site, triangle.site1) || siteIsEqual(site, triangle.site2) || siteIsEqual(site, triangle.site3)) 490 | return true; 491 | return false; 492 | } 493 | 494 | //判断点是否在边上 495 | public bool isPointOnEdge(Edge edge, Site site) 496 | { 497 | if (siteIsEqual(site, edge.a) || siteIsEqual(site, edge.b)) 498 | return true; 499 | return false; 500 | } 501 | 502 | //将点与受影响的三角形三点连接,形成新的三个三角形添加到三角形链中 503 | public void addNewDelaunayTriangle(List allTriangles, DelaunayTriangle influenedTri, Site point, Center centerPoint) 504 | { 505 | allTriangles.Add(new DelaunayTriangle(influenedTri.site1, influenedTri.site2, point, influenedTri.center1, influenedTri.center2, centerPoint)); 506 | allTriangles.Add(new DelaunayTriangle(influenedTri.site1, influenedTri.site3, point, influenedTri.center1, influenedTri.center3, centerPoint)); 507 | allTriangles.Add(new DelaunayTriangle(influenedTri.site2, influenedTri.site3, point, influenedTri.center2, influenedTri.center3, centerPoint)); 508 | } 509 | 510 | 511 | //对新形成的三角形进行局部优化 512 | public List LOP(List newTriList) 513 | { 514 | List resultTriList=new List(); 515 | //拷贝新形成的三角 516 | for (int i = 0; i < newTriList.Count; i++) 517 | { 518 | resultTriList.Add(newTriList[i]); 519 | } 520 | 521 | for (int i = 0; i < newTriList.Count; i++) 522 | { 523 | for (int j = i + 1; j < newTriList.Count; j++) 524 | { 525 | Edge commonEdge;//需要调整对角线的的三角形的公共边 526 | Site anotherPoint=new Site();//新对角线的另一点 527 | Center anotherCenter = new Center(); 528 | if (isInCircle(newTriList[j], newTriList[i].site1))//三角形点在外接圆内 529 | { 530 | //找出两个三角形的公共边 531 | commonEdge=findCommonEdge(newTriList[i],newTriList[j]); 532 | if(commonEdge!=null) 533 | { 534 | //移除需要调整的三角形 535 | resultTriList.Remove(newTriList[i]); 536 | resultTriList.Remove(newTriList[j]); 537 | //找出对角线的另一点 538 | if (siteIsEqual(newTriList[j].site1, commonEdge.a) == false && siteIsEqual(newTriList[j].site1, commonEdge.b) == false) 539 | { 540 | anotherPoint = newTriList[j].site1; 541 | anotherCenter = newTriList[j].center1; 542 | } 543 | if (siteIsEqual(newTriList[j].site2, commonEdge.a) == false && siteIsEqual(newTriList[j].site2, commonEdge.b) == false) 544 | { 545 | anotherPoint = newTriList[j].site2; 546 | anotherCenter = newTriList[j].center2; 547 | } 548 | if (siteIsEqual(newTriList[j].site3, commonEdge.a) == false && siteIsEqual(newTriList[j].site3, commonEdge.b) == false) 549 | { 550 | anotherPoint = newTriList[j].site3; 551 | anotherCenter = newTriList[j].center3; 552 | } 553 | //形成两个新的三角形 554 | resultTriList.Add(new DelaunayTriangle(newTriList[i].site1,anotherPoint,commonEdge.a,newTriList[i].center1,anotherCenter,commonEdge.ca)); 555 | resultTriList.Add(new DelaunayTriangle(newTriList[i].site1,anotherPoint,commonEdge.b,newTriList[i].center1,anotherCenter,commonEdge.cb)); 556 | } 557 | } 558 | 559 | if (isInCircle(newTriList[j], newTriList[i].site2))//三角形点在外接圆内 560 | { 561 | //找出两个三角形的公共边 562 | commonEdge = findCommonEdge(newTriList[i], newTriList[j]); 563 | if(commonEdge!=null) 564 | { 565 | //移除需要调整的三角形 566 | resultTriList.Remove(newTriList[i]); 567 | resultTriList.Remove(newTriList[j]); 568 | //找出对角线的另一点 569 | if (siteIsEqual(newTriList[j].site1, commonEdge.a) == false && siteIsEqual(newTriList[j].site1, commonEdge.b) == false) 570 | anotherPoint = newTriList[j].site1; 571 | if (siteIsEqual(newTriList[j].site2, commonEdge.a) == false && siteIsEqual(newTriList[j].site2, commonEdge.b) == false) 572 | anotherPoint = newTriList[j].site2; 573 | if (siteIsEqual(newTriList[j].site3, commonEdge.a) == false && siteIsEqual(newTriList[j].site3, commonEdge.b) == false) 574 | anotherPoint = newTriList[j].site3; 575 | //形成两个新的三角形 576 | resultTriList.Add(new DelaunayTriangle(newTriList[i].site2, anotherPoint, commonEdge.a, newTriList[i].center2, anotherCenter, commonEdge.ca)); 577 | resultTriList.Add(new DelaunayTriangle(newTriList[i].site2, anotherPoint, commonEdge.a, newTriList[i].center2, anotherCenter, commonEdge.cb)); 578 | } 579 | } 580 | 581 | if (isInCircle(newTriList[j], newTriList[i].site3))//三角形点在外接圆内 582 | { 583 | //找出两个三角形的公共边 584 | commonEdge = findCommonEdge(newTriList[i], newTriList[j]); 585 | if(commonEdge!=null) 586 | { 587 | //移除需要调整的三角形 588 | resultTriList.Remove(newTriList[i]); 589 | resultTriList.Remove(newTriList[j]); 590 | //找出对角线的另一点 591 | if (siteIsEqual(newTriList[j].site1, commonEdge.a) == false && siteIsEqual(newTriList[j].site1, commonEdge.b) == false) 592 | anotherPoint = newTriList[j].site1; 593 | if (siteIsEqual(newTriList[j].site2, commonEdge.a) == false && siteIsEqual(newTriList[j].site2, commonEdge.b) == false) 594 | anotherPoint = newTriList[j].site2; 595 | if (siteIsEqual(newTriList[j].site3, commonEdge.a) == false && siteIsEqual(newTriList[j].site3, commonEdge.b) == false) 596 | anotherPoint = newTriList[j].site3; 597 | //形成两个新的三角形 598 | resultTriList.Add(new DelaunayTriangle(newTriList[i].site3, anotherPoint, commonEdge.a, newTriList[i].center3, anotherCenter, commonEdge.ca)); 599 | resultTriList.Add(new DelaunayTriangle(newTriList[i].site3, anotherPoint, commonEdge.a, newTriList[i].center3, anotherCenter, commonEdge.cb)); 600 | } 601 | } 602 | } 603 | } 604 | newTriList = resultTriList; 605 | return resultTriList;//返回优化后的新形成的三角形 606 | } 607 | 608 | 609 | 610 | //找出受影响的三角形的公共边 611 | public List findCommonEdges(List influenedTriangles) 612 | { 613 | List coomonEdges=new List(); 614 | Edge tmpEdge; 615 | for (int i = 0; i < influenedTriangles.Count; i++) 616 | { 617 | for (int j = i + 1; j < influenedTriangles.Count; j++) 618 | { 619 | tmpEdge = findCommonEdge(influenedTriangles[i], influenedTriangles[j]); 620 | if (tmpEdge!= null) 621 | { 622 | coomonEdges.Add(tmpEdge); 623 | } 624 | } 625 | } 626 | return coomonEdges; 627 | } 628 | 629 | //找出两个三角形的公共边 630 | public Edge findCommonEdge(DelaunayTriangle chgTri1, DelaunayTriangle chgTri2) 631 | { 632 | Edge edge; 633 | List commonSites=new List(); 634 | List
commonCenters = new List
(); 635 | if (siteIsEqual(chgTri1.site1, chgTri2.site1) || siteIsEqual(chgTri1.site1, chgTri2.site2) || siteIsEqual(chgTri1.site1, chgTri2.site3)) 636 | { 637 | commonSites.Add(chgTri1.site1); 638 | commonCenters.Add(chgTri1.center1); 639 | } 640 | if (siteIsEqual(chgTri1.site2, chgTri2.site1) || siteIsEqual(chgTri1.site2, chgTri2.site2) || siteIsEqual(chgTri1.site2, chgTri2.site3)) 641 | { 642 | commonSites.Add(chgTri1.site2); 643 | commonCenters.Add(chgTri1.center2); 644 | } 645 | if (siteIsEqual(chgTri1.site3, chgTri2.site1) || siteIsEqual(chgTri1.site3, chgTri2.site2) || siteIsEqual(chgTri1.site3, chgTri2.site3)) 646 | { 647 | commonSites.Add(chgTri1.site3); 648 | commonCenters.Add(chgTri1.center3); 649 | } 650 | if (commonSites.Count == 2) 651 | { 652 | edge = new Edge(commonSites[0], commonSites[1],commonCenters[0],commonCenters[1]); 653 | return edge; 654 | } 655 | return null; 656 | } 657 | 658 | //判断两点是否相同 659 | public bool siteIsEqual(Site a,Site b) 660 | { 661 | if (a.x == b.x && a.y == b.y) 662 | return true; 663 | return false; 664 | } 665 | 666 | //找出亮点的中点 667 | public Site findMidPoint(Site a,Site b) 668 | { 669 | Site midpoint=new Site((a.x+b.x)/2.0,(a.y+b.y)/2.0); 670 | return midpoint; 671 | 672 | } 673 | 674 | //判断插入点是否在三角形边上 675 | public Site[] isOnEdges(DelaunayTriangle triangle,Site site) 676 | { 677 | Site[] edges=new Site[2]; 678 | Site a=triangle.site1; 679 | Site b=triangle.site2; 680 | Site c=triangle.site3; 681 | 682 | if((site.y-a.y)*(site.x-b.x)==(site.y-b.y)*(site.x-a.x))//点在ab边上 683 | { 684 | edges[0]=a; 685 | edges[1]=b; 686 | } 687 | 688 | if ((site.y - a.y) * (site.x - c.x) == (site.y - c.y) * (site.x - a.x))//点在ac边上 689 | { 690 | edges[0] = a; 691 | edges[1] = c; 692 | } 693 | 694 | if ((site.y - b.y) * (site.x - c.x) == (site.y - c.y) * (site.x - b.x))//点在bc边上 695 | { 696 | edges[0] = b; 697 | edges[1] = c; 698 | } 699 | return edges; 700 | } 701 | 702 | //判断点是否在三角形外接圆的内部 703 | public bool isInCircle(DelaunayTriangle triangle, Site site) 704 | { 705 | double lengthToCenter;//该点到圆心距离 706 | lengthToCenter=distance2Point(triangle.centerPoint,site); 707 | if (lengthToCenter < triangle.radius) 708 | { 709 | return true; 710 | } 711 | return false; 712 | } 713 | 714 | //根据两点求以第一个点为起点的射线边 715 | public Edge produceRayEdge(Site start, Site direction) 716 | { 717 | Site end = new Site(); 718 | Center centerEnd = new Center(); 719 | Edge longEdge; 720 | end.x = 100 * (direction.x - start.x) + start.x;//找出射线方向的较大的x终点 721 | end.y = (direction.y - start.y) * (end.x - start.x) / (direction.x - start.x) + start.y; 722 | longEdge = new Edge(start,end,new Corner(),new Corner()); 723 | return longEdge; 724 | } 725 | 726 | 727 | //求两点之间距离 728 | public double distance2Point(Site p,Site p2) 729 | { 730 | double value=Math.Sqrt(Math.Abs(p.x-p2.x)*Math.Abs(p.x-p2.x)+Math.Abs(p.y-p2.y)*Math.Abs(p.y-p2.y)); 731 | return value; 732 | } 733 | 734 | //求三角形的外接圆心 735 | public void circle_center(Site center, Site sites0, Site sites1, Site sites2, ref double radius) 736 | { 737 | double x1,x2,x3,y1,y2,y3; 738 | double x = 0; 739 | double y = 0; 740 | 741 | x1 = sites0.x; 742 | x2 = sites1.x; 743 | x3 = sites2.x; 744 | y1 = sites0.y; 745 | y2 = sites1.y; 746 | y3 = sites2.y; 747 | x=((y2-y1)*(y3*y3-y1*y1+x3*x3-x1*x1)-(y3-y1)*(y2*y2-y1*y1+x2*x2-x1*x1))/(2*(x3-x1)*(y2-y1)-2*((x2-x1)*(y3-y1))); 748 | y=((x2-x1)*(x3*x3-x1*x1+y3*y3-y1*y1)-(x3-x1)*(x2*x2-x1*x1+y2*y2-y1*y1))/(2*(y3-y1)*(x2-x1)-2*((y2-y1)*(x3-x1))); 749 | 750 | center.x = x ; 751 | center.y = y ; 752 | radius = Math.Sqrt(Math.Abs(sites0.x - x)*Math.Abs(sites0.x - x) + Math.Abs(sites0.y - y) * Math.Abs(sites0.y - y)); 753 | } 754 | 755 | 756 | 757 | } 758 | } 759 | --------------------------------------------------------------------------------