├── .gitignore
├── README.txt
└── UnitySimpleMapGenerator
├── AssemblyInfo.cs
├── BraveNewWorld
├── AssemblyInfo.cs
├── BraveNewWorld.csproj
├── Helpers
│ └── MapPointToPointConverter.cs
├── Models
│ ├── Center.cs
│ ├── Corner.cs
│ ├── Edge.cs
│ ├── Factory.cs
│ ├── IMapItem.cs
│ ├── Map.cs
│ └── Triangle.cs
└── Services
│ ├── IslandService.cs
│ └── MapService.cs
├── FortuneVoronoi
├── AssemblyInfo.cs
├── Fortune.cs
├── FortuneVoronoi.csproj
├── GlobalSuppressions.cs
├── ToolBox.cs
├── VCircleEvent.cs
├── VDataEvent.cs
├── VDataNode.cs
├── VEdgeNode.cs
├── VEvent.cs
├── VNode.cs
├── VoronoiEdge.cs
├── VoronoiGraph.cs
└── lib
│ ├── NGenerics.dll
│ ├── NGenerics.pdb
│ └── NGenerics.xml
├── UnitySimpleMapGenerator.csproj
└── UnitySimpleMapGenerator.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pidb
2 | *.userprefs
3 | .DS_Store
4 | bin
5 | obj
6 | *.suo
7 | UnitySimpleMapGenerator/obj/Debug/ResolveAssemblyReference.cache
8 | UnitySimpleMapGenerator/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
9 | UnitySimpleMapGenerator/obj/Debug/UnitySimpleMapGenerator.csproj.FileListAbsolute.txt
--------------------------------------------------------------------------------
/README.txt:
--------------------------------------------------------------------------------
1 | This is a port of Baran Kahyaoglu's Simple Map Generator, which you can find
2 | here:
3 |
4 | http://www.barankahyaoglu.com/blog/post/2011/07/27/Simple-Map-Generator-Part-1.aspx
5 |
6 | Source Origins:
7 |
8 | The Simple Map Generator is based on an article and some code by Amit Patel:
9 |
10 | http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/
11 |
12 | Baran's code makes use of Fortune's Voronoi code by BenDi on CodeProject:
13 |
14 | http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
15 |
16 | Unity3D Port:
17 |
18 | This port brings the Simple Map Generator code into Unity3D and produces a
19 | 3D mesh suitable for characters to walk around on.
20 |
21 | - Chris Herborth
22 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // -----------------------------------------------------------------------
2 | //
3 | // Use this code for whatever you want, just don't blame me if it breaks.
4 | //
5 | // -----------------------------------------------------------------------
6 |
7 | using System;
8 | using System.Reflection;
9 | using System.Runtime.CompilerServices;
10 |
11 | // Information about this assembly is defined by the following attributes.
12 | // Change them to the values specific to your project.
13 |
14 | [assembly: AssemblyTitle("UnitySimpleMapGenerator")]
15 | [assembly: AssemblyDescription("A Unity3D port of Baran Kahyaoglu's Map Generator - http://www.barankahyaoglu.com/blog/page/MapGenerator.aspx")]
16 | [assembly: AssemblyConfiguration("")]
17 | [assembly: AssemblyCompany("Taffer")]
18 | [assembly: AssemblyProduct("")]
19 | [assembly: AssemblyCopyright("Free to use, copy, fork, etc. but don't blame me if it breaks.")]
20 | [assembly: AssemblyTrademark("")]
21 | [assembly: AssemblyCulture("")]
22 |
23 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
24 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
25 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
26 |
27 | [assembly: AssemblyVersion("1.0.*")]
28 |
29 | // The following attributes are used to specify the signing key for the assembly,
30 | // if desired. See the Mono documentation for more information about signing.
31 |
32 | //[assembly: AssemblyDelaySign(false)]
33 | //[assembly: AssemblyKeyFile("")]
34 |
35 | // Must be false due to UnityEngine.
36 | [assembly: CLSCompliant(false)]
37 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // -----------------------------------------------------------------------
2 | //
3 | // Use this code for whatever you want, just don't blame me if it breaks.
4 | //
5 | // -----------------------------------------------------------------------
6 | using System.Reflection;
7 | using System.Runtime.CompilerServices;
8 |
9 | // Information about this assembly is defined by the following attributes.
10 | // Change them to the values specific to your project.
11 |
12 | [assembly: AssemblyTitle("BraveNewWorld")]
13 | [assembly: AssemblyDescription("")]
14 | [assembly: AssemblyConfiguration("")]
15 | [assembly: AssemblyCompany("")]
16 | [assembly: AssemblyProduct("")]
17 | [assembly: AssemblyCopyright("Chris Herborth (chrish@pobox.com)")]
18 | [assembly: AssemblyTrademark("")]
19 | [assembly: AssemblyCulture("")]
20 |
21 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
22 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
23 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
24 |
25 | [assembly: AssemblyVersion("1.0.*")]
26 |
27 | // The following attributes are used to specify the signing key for the assembly,
28 | // if desired. See the Mono documentation for more information about signing.
29 |
30 | //[assembly: AssemblyDelaySign(false)]
31 | //[assembly: AssemblyKeyFile("")]
32 |
33 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/BraveNewWorld.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 10.0.0
7 | 2.0
8 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}
9 | Library
10 | BraveNewWorld
11 | BraveNewWorld
12 |
13 |
14 | true
15 | full
16 | false
17 | bin\Debug
18 | DEBUG;
19 | prompt
20 | 4
21 | false
22 |
23 |
24 | none
25 | false
26 | bin\Release
27 | prompt
28 | 4
29 | false
30 |
31 |
32 |
33 |
34 | ..\..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}
54 | FortuneVoronoi
55 |
56 |
57 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Helpers/MapPointToPointConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Data;
3 | using System.Windows.Media;
4 | using BraveNewWorld.Models;
5 |
6 | namespace BraveNewWorld.Helpers
7 | {
8 | public class MapPointToPointConverter : IValueConverter
9 | {
10 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
11 | {
12 | var ps = (Center)value;
13 |
14 | PointCollection polygonPoints = new PointCollection();
15 |
16 | foreach (Corner mp in ps.Corners)
17 | {
18 | polygonPoints.Add(new System.Windows.Point(mp.Point.X - ps.Point.X, mp.Point.Y - ps.Point.Y));
19 | }
20 |
21 | return polygonPoints;
22 | }
23 |
24 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
25 | {
26 | return null;
27 | }
28 | }
29 |
30 | }
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/Center.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Windows;
6 | using System.Windows.Media;
7 | using System.Windows.Media.Media3D;
8 |
9 | namespace BraveNewWorld.Models
10 | {
11 | public class Center : DependencyObject, IEquatable
, IMapItem
12 | {
13 | public int Index { get; set; }
14 |
15 | public int Key { get; set; }
16 | public Point Point { get; set; } // location
17 | public Boolean Water { get; set; } // lake or ocean
18 | public Boolean Land { get { return !Water; } set { Water = !value; } } // lake or ocean
19 | public Boolean Ocean { get; set; } // ocean
20 | public Boolean Coast { get; set; } // land polygon touching an ocean
21 | public Boolean Border { get; set; } // at the edge of the map
22 | public Vector3D polyNorm { get; set; }
23 |
24 | private string _biome;
25 | public string Biome
26 | {
27 | get
28 | {
29 | return _biome;
30 | }
31 | set
32 | {
33 | if (value == "Ocean")
34 | PolygonBrush = new SolidColorBrush(new Color() { R = 54, G = 54, B = 97, A = 255 });
35 | if (value == "ShallowWater")
36 | PolygonBrush = new SolidColorBrush(new Color() { R = 74, G = 74, B = 117, A = 255 });
37 | else if (value == "Marsh")
38 | PolygonBrush = new SolidColorBrush(new Color() { R = 196, G = 204, B = 187 , A=255 });
39 | else if (value == "Lake")
40 | PolygonBrush = new SolidColorBrush(new Color() { R = 54, G = 54, B = 97, A = 255 });
41 | else if (value == "Beach")
42 | PolygonBrush = new SolidColorBrush(new Color() { R = 173, G = 161, B = 139, A = 255 });
43 | else if (value == "Snow")
44 | PolygonBrush = new SolidColorBrush(Colors.White);
45 | else if (value == "Tundra")
46 | PolygonBrush = new SolidColorBrush(new Color() { R = 196, G = 204, B = 187, A = 255 });
47 | else if (value == "Bare")
48 | PolygonBrush = new SolidColorBrush(new Color() { R = 187, G = 187, B = 187, A = 255 });
49 | else if (value == "Scorched")
50 | PolygonBrush = new SolidColorBrush(new Color() { R = 153, G = 153, B = 153, A = 255 });
51 | else if (value == "Taiga")
52 | PolygonBrush = new SolidColorBrush(new Color() { R = 204, G = 212, B = 187, A = 255 });
53 | else if (value == "Shrubland")
54 | PolygonBrush = new SolidColorBrush(new Color() { R = 153, G = 166, B = 139, A = 255 });
55 | else if (value == "TemperateDesert")
56 | PolygonBrush = new SolidColorBrush(new Color() { R = 228, G = 232, B = 202, A = 255 });
57 | else if (value == "TemperateRainForest")
58 | PolygonBrush = new SolidColorBrush(new Color() { R = 84, G = 116, B = 88, A = 255 });
59 | else if (value == "TemperateDeciduousForest")
60 | PolygonBrush = new SolidColorBrush(new Color() { R = 119, G = 139, B = 85, A = 255 });
61 | else if (value == "Grassland")
62 | PolygonBrush = new SolidColorBrush(new Color() { R = 153, G = 180, B = 112, A = 255 });
63 | else if (value == "TropicalRainForest")
64 | PolygonBrush = new SolidColorBrush(new Color() { R = 112, G = 139, B = 85, A = 255 });
65 | else if (value == "TropicalSeasonalForest")
66 | PolygonBrush = new SolidColorBrush(new Color() { R = 85, G = 139, B = 85, A = 255 });
67 | else if (value == "SubtropicalDesert")
68 | PolygonBrush = new SolidColorBrush(new Color() { R = 172, G = 159, B = 139, A = 255 });
69 |
70 | _biome = value;
71 | }
72 | }
73 |
74 | public SolidColorBrush PolygonBrush { get; set; }
75 |
76 | //public string Biome { get; set; } // biome type (see article)
77 | public double Elevation { get; set; } // 0.0-1.0
78 | public double Moisture { get; set; } // 0.0-1.0
79 |
80 | public HashSet Neighbours { get; set; }
81 | public HashSet Borders { get; set; }
82 | public HashSet Corners { get; set; }
83 |
84 | public Center(double x , double y)
85 | {
86 | polyNorm = new Vector3D(0, 0, 0);
87 | Point = new Point(x,y);
88 | Key = Point.GetHashCode();
89 | Index = Point.GetHashCode();
90 |
91 | Water = Coast = Ocean = Border = false;
92 | Elevation = Moisture = 0.0d;
93 |
94 | Neighbours = new HashSet(new CenterComparer());
95 | Borders = new HashSet(new EdgeComparer());
96 | Corners = new HashSet(new CornerComparer());
97 | }
98 |
99 | #region Methods
100 | public bool Equals(Center other)
101 | {
102 | return this.Point == other.Point;
103 | }
104 |
105 | public void OrderCorners()
106 | {
107 | Corner CurrentCorner = Corners.First();
108 | List Ordered = new List();
109 | Corner newdot;
110 | Edge ed;
111 |
112 | Ordered.Add(CurrentCorner);
113 | do
114 | {
115 | ed = CurrentCorner.Protrudes.FirstOrDefault(x => Borders.Contains(x) && !(Ordered.Contains(x.VoronoiStart) && (Ordered.Contains(x.VoronoiEnd))));
116 |
117 | if (ed != null)
118 | {
119 | newdot = ed.Corners.FirstOrDefault(x => !Ordered.Contains(x));
120 | Ordered.Add(newdot);
121 | CurrentCorner = newdot;
122 | }
123 | } while (ed != null);
124 |
125 | Corners.Clear();
126 |
127 | foreach (var corner in Ordered)
128 | {
129 | Corners.Add(corner);
130 | }
131 | }
132 |
133 | public void FixBorders()
134 | {
135 | var ms = from p in Borders.SelectMany(x => x.Corners)
136 | group p by p.Point
137 | into grouped
138 | select new {point = grouped.Key, count = grouped.Count()};
139 |
140 | var fpoint = ms.FirstOrDefault(x => x.count == 1);
141 | var spoint = ms.LastOrDefault(x => x.count == 1);
142 |
143 | if(fpoint != null & spoint != null)
144 | {
145 | Corner p1 = Corners.FirstOrDefault(x => x.Point == fpoint.point);
146 | Corner p2 = Corners.FirstOrDefault(x => x.Point == spoint.point);
147 |
148 | if (p1 == null || p2 == null)
149 | return;
150 |
151 | IFactory fact = new MapItemFactory();
152 | Edge e = fact.EdgeFactory(
153 | p1,
154 | p2,
155 | this, null);
156 |
157 | e.MapEdge = true;
158 |
159 | p1.Protrudes.Add(e);
160 | p2.Protrudes.Add(e);
161 |
162 | this.Border = this.Ocean = this.Water = true;
163 | e.VoronoiStart.Border = e.VoronoiEnd.Border = true;
164 | e.VoronoiStart.Elevation = e.VoronoiEnd.Elevation = 0.0d;
165 |
166 | this.Borders.Add(e);
167 | }
168 | }
169 |
170 |
171 | #endregion
172 |
173 | public void SetBiome()
174 | {
175 | if (Ocean && Elevation < -0.1d)
176 | {
177 | Biome = "Ocean";
178 | }
179 | else
180 | if (Ocean && Elevation > -0.1d)
181 | {
182 | Biome = "ShallowWater";
183 | }
184 | else if (Water)
185 | {
186 | if (Elevation < 0.1) Biome = "Marsh";
187 | if (Elevation > 0.8) Biome = "Ice";
188 | Biome = "Lake";
189 | }
190 | else if (Coast)
191 | {
192 | Biome = "Beach";
193 | }
194 | else if (Elevation > 0.8)
195 | {
196 | if (Moisture > 0.50) Biome = "Snow";
197 | else if (Moisture > 0.33) Biome = "Tundra";
198 | else if (Moisture > 0.16) Biome = "Bare";
199 | else Biome = "Scorched";
200 | }
201 | else if (Elevation > 0.6)
202 | {
203 | if (Moisture > 0.66) Biome = "Taiga";
204 | else if (Moisture > 0.33) Biome = "Shrubland";
205 | else Biome = "TemperateDesert";
206 | }
207 | else if (Elevation > 0.3)
208 | {
209 | if (Moisture > 0.83) Biome = "TemperateRainForest";
210 | else if (Moisture > 0.50) Biome = "TemperateDeciduousForest";
211 | else if (Moisture > 0.16) Biome = "Grassland";
212 | else Biome = "TemperateDesert";
213 | }
214 | else
215 | {
216 | if (Moisture > 0.66) Biome = "TropicalRainForest";
217 | else if (Moisture > 0.33) Biome = "TropicalSeasonalForest";
218 | else if (Moisture > 0.16) Biome = "Grassland";
219 | else Biome = "SubtropicalDesert";
220 | }
221 | }
222 |
223 |
224 |
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/Corner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows;
4 |
5 | namespace BraveNewWorld.Models
6 | {
7 | public class Corner : IEquatable , IMapItem
8 | {
9 | public Corner(double ax, double ay)
10 | {
11 | Point = new Point(ax,ay);
12 | Key = Point.GetHashCode();
13 | Index = Point.GetHashCode();
14 | Ocean = Water = Coast = Border = false;
15 | Moisture = 0.0d;
16 | Elevation = 100.0d;
17 |
18 | Touches = new HashSet(new CenterComparer());
19 | Protrudes = new HashSet(new EdgeComparer());
20 | Adjacents = new HashSet(new CornerComparer());
21 |
22 | River = WatershedSize = 0;
23 | }
24 |
25 | public int Index { get; set; }
26 |
27 | public int Key { get; set; }
28 | public Point Point { get; set; } // location
29 | public Boolean Ocean { get; set; } // ocean
30 | public Boolean Water { get; set; } // lake or ocean
31 | public Boolean Land { get { return !Water; } set { Water = !value; } } // lake or ocean
32 | public Boolean Coast { get; set; } // touches ocean and land polygons
33 | public Boolean Border { get; set; } // at the edge of the map
34 | public double Elevation { get; set; } // 0.0-1.0
35 | public double Moisture { get; set; } // 0.0-1.0
36 |
37 | public HashSet Touches { get; set; }
38 | public HashSet Protrudes { get; set; }
39 | public HashSet Adjacents { get; set; }
40 |
41 | public int River { get; set; } // 0 if no river, or volume of water in river
42 | public Corner Downslope { get; set; } // pointer to adjacent corner most downhill
43 | public Corner Watershed { get; set; } // pointer to coastal corner, or null
44 | public int WatershedSize { get; set; }
45 |
46 | public bool Equals(Corner other)
47 | {
48 | return this.Point.Equals(other.Point);
49 | }
50 |
51 | public void AddProtrudes(Edge edge)
52 | {
53 | Protrudes.Add(edge);
54 | }
55 |
56 | public void AddAdjacent(Corner corner)
57 | {
58 | Adjacents.Add(corner);
59 | }
60 |
61 | public void AddTouches(Center center)
62 | {
63 | Touches.Add(center);
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/Edge.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 |
4 | namespace BraveNewWorld.Models
5 | {
6 | public class Edge : IEquatable , IMapItem
7 | {
8 | public Edge(Corner begin, Corner end, Center left, Center right)
9 | {
10 | River = 0;
11 | VoronoiStart = begin;
12 | VoronoiEnd = end;
13 |
14 | DelaunayStart = left;
15 | DelaunayEnd = right;
16 |
17 | Midpoint = new Point((VoronoiStart.Point.X + VoronoiEnd.Point.X) / 2, (VoronoiStart.Point.Y + VoronoiEnd.Point.Y) / 2);
18 | Key = Midpoint.GetHashCode();
19 | Index = Midpoint.GetHashCode();
20 | }
21 |
22 | public Edge(int index, Corner begin, Corner end)
23 | {
24 | Index = index;
25 | River = 0;
26 | VoronoiStart = begin;
27 | VoronoiEnd = end;
28 | Midpoint = new Point((VoronoiStart.Point.X + VoronoiEnd.Point.X) / 2, (VoronoiStart.Point.Y + VoronoiEnd.Point.Y) / 2);
29 | Key = Midpoint.GetHashCode();
30 | }
31 |
32 | public int Index { get; set; }
33 |
34 | public int Key { get; set; }
35 | public Center DelaunayStart { get; set; }
36 | public Center DelaunayEnd { get; set; }// Delaunay edge
37 | public Corner VoronoiStart { get; set; }
38 | public Corner VoronoiEnd { get; set; }// Voronoi edge
39 | public Point Midpoint { get; set; } // halfway between v0,v1
40 | public int River { get; set; } // volume of water, or 0
41 | public bool MapEdge = false;
42 | public Point Point { get { return VoronoiStart.Point; } }
43 |
44 | public bool Coast
45 | {
46 | get
47 | {
48 | if (DelaunayStart != null && DelaunayEnd != null)
49 | return ((VoronoiStart.Coast) && (VoronoiEnd.Coast)
50 | && !(DelaunayStart.Water && DelaunayEnd.Water)
51 | && !(DelaunayStart.Land && DelaunayEnd.Land));
52 | return false;
53 | }
54 |
55 | set { }
56 | }
57 |
58 | public Corner[] Corners { get { return new Corner[] {VoronoiStart, VoronoiEnd}; } }
59 |
60 | public double DiffX { get { return VoronoiEnd.Point.X - VoronoiStart.Point.X; } }
61 | public double DiffY { get { return VoronoiEnd.Point.Y - VoronoiStart.Point.Y; } }
62 |
63 | public bool Equals(Edge other)
64 | {
65 | return this.VoronoiStart.Equals(other.VoronoiStart) &&
66 | this.VoronoiEnd.Equals(other.VoronoiEnd);
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/Factory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows;
4 |
5 | namespace BraveNewWorld.Models
6 | {
7 | class CenterComparer : IEqualityComparer
8 | {
9 | public CenterComparer() { }
10 | public bool Equals(Center x, Center y)
11 | {
12 | //return (x.Point.X == y.Point.X) && (x.Point.Y == y.Point.Y);
13 | return GetHashCode(x) == GetHashCode(y);
14 | }
15 |
16 | public int GetHashCode(Center obj)
17 | {
18 | return obj.Point.GetHashCode();
19 | }
20 | }
21 |
22 | class CornerComparer : IEqualityComparer
23 | {
24 | public CornerComparer() { }
25 | public bool Equals(Corner x, Corner y)
26 | {
27 | return x.Point.Equals(y.Point);
28 | }
29 |
30 | public int GetHashCode(Corner obj)
31 | {
32 | return obj.Point.GetHashCode();
33 | }
34 | }
35 |
36 | class EdgeComparer : IEqualityComparer
37 | {
38 | public EdgeComparer() { }
39 | public bool Equals(Edge x, Edge y)
40 | {
41 | return x.Midpoint == y.Midpoint;
42 | }
43 |
44 | public int GetHashCode(Edge obj)
45 | {
46 | return obj.Midpoint.GetHashCode();
47 | }
48 | }
49 |
50 | public interface IFactory
51 | {
52 | Center CenterFactory(double ax, double ay);
53 | Edge EdgeFactory(Corner begin, Corner end, Center Left, Center Right);
54 | Corner CornerFactory(double ax, double ay);
55 | }
56 |
57 | public class MapItemFactory : IFactory
58 | {
59 | #region Implementation of IFactory
60 |
61 | public Center CenterFactory(double ax, double ay)
62 | {
63 | Point p = new Point(ax, ay);
64 | int hash = p.GetHashCode();
65 | if(App.AppMap.Centers.ContainsKey(hash))
66 | {
67 | return App.AppMap.Centers[hash];
68 | }
69 | else
70 | {
71 | var nc = new Center(ax, ay);
72 | App.AppMap.Centers.Add(nc.Key, nc);
73 | return nc;
74 | }
75 | }
76 |
77 | public Edge EdgeFactory(Corner begin, Corner end, Center Left, Center Right)
78 | {
79 | Point p = new Point((begin.Point.X + end.Point.X) / 2, (begin.Point.Y + end.Point.Y) / 2);
80 | int hash = p.GetHashCode();
81 | if (App.AppMap.Edges.ContainsKey(hash))
82 | {
83 | return App.AppMap.Edges[hash];
84 | }
85 | else
86 | {
87 | var nc = new Edge(begin,end,Left,Right);
88 | App.AppMap.Edges.Add(nc.Key, nc);
89 | return nc;
90 | }
91 | }
92 |
93 | public Corner CornerFactory(double ax, double ay)
94 | {
95 | Point p = new Point(ax, ay);
96 | int hash = p.GetHashCode();
97 | if (App.AppMap.Corners.ContainsKey(hash))
98 | {
99 | return App.AppMap.Corners[hash];
100 | }
101 | else
102 | {
103 | var nc = new Corner(ax, ay);
104 | App.AppMap.Corners.Add(nc.Key, nc);
105 | return nc;
106 | }
107 | }
108 |
109 | #endregion
110 |
111 | public void RemoveEdge(Edge edge)
112 | {
113 | App.AppMap.Edges.Remove(edge.Midpoint.GetHashCode());
114 | }
115 |
116 | public void RemoveCorner(Corner corner)
117 | {
118 | App.AppMap.Corners.Remove(corner.Point.GetHashCode());
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/IMapItem.cs:
--------------------------------------------------------------------------------
1 | namespace BraveNewWorld.Models
2 | {
3 | public interface IMapItem
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/Map.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace BraveNewWorld.Models
4 | {
5 | public class Map
6 | {
7 | public Dictionary Centers { get; set; }
8 | public Dictionary Corners { get; set; }
9 | public Dictionary Edges { get; set; }
10 |
11 | public Map()
12 | {
13 | Centers = new Dictionary();
14 | Corners = new Dictionary();
15 | Edges = new Dictionary();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Models/Triangle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows;
6 |
7 | namespace BraveNewWorld.Models
8 | {
9 | public class Triangle
10 | {
11 | public List Corners { get; set; }
12 | public List Edges { get; set; }
13 | public List Neightbours { get; set; }
14 | public Point Point { get; set; }
15 | public Center Parent { get; set; }
16 |
17 | public Triangle()
18 | {
19 | Corners = new List();
20 | Edges = new List();
21 | Neightbours = new List();
22 |
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Services/IslandService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows;
6 | using System.Windows.Media.Media3D;
7 | using BraveNewWorld.Models;
8 |
9 | namespace BraveNewWorld.Services
10 | {
11 | public interface IIslandService
12 | {
13 | void CreateIsland();
14 | }
15 |
16 | public class IslandService : IIslandService
17 | {
18 | private double MapMaxHeight = 0.0d;
19 | private double MapDeepest = 1.0d;
20 | private int MapX, MapY;
21 |
22 |
23 | public IslandService(int mapX, int mapY)
24 | {
25 | MapX = mapX;
26 | MapY = mapY;
27 | }
28 |
29 | public void CreateIsland()
30 | {
31 | foreach (var c in App.AppMap.Corners.Values)
32 | {
33 | c.Water = !InLand(c.Point); // calculate land&water corners
34 | }
35 |
36 | FixCentersFloodFillOceans();
37 |
38 | foreach (var c in App.AppMap.Corners.Values)
39 | {
40 | c.Coast = (c.Touches.Any(x => x.Water) && c.Touches.Any(x => x.Land)) ? true : false;
41 |
42 | c.Water = (c.Touches.Any(x => x.Land)) ? false : true;
43 |
44 | c.Ocean = (c.Touches.All(x => x.Ocean)) ? true : false;
45 | }
46 |
47 | CalculateElevation();
48 |
49 | RedistributeElevation();
50 |
51 | CalculateDownslopes();
52 |
53 | CalculateWatersheds();
54 |
55 | CreateRivers();
56 |
57 | CalculateCornerMoisture();
58 |
59 | //RedistributeMoisture();
60 |
61 |
62 |
63 | //Smooth1();
64 |
65 |
66 | foreach (Center c in App.AppMap.Centers.Values)
67 | {
68 | c.Moisture = c.Corners.Sum(x => x.Moisture) / c.Corners.Count();
69 |
70 | c.OrderCorners();
71 |
72 | c.Elevation = c.Corners.Sum(x => x.Elevation) / c.Corners.Count;
73 |
74 | c.SetBiome();
75 | }
76 | }
77 |
78 | private void RedistributeMoisture()
79 | {
80 | var locations = App.AppMap.Corners.Values.OrderBy(x => x.Moisture).ToArray();
81 |
82 | for (int i = 0; i < locations.Count(); i++)
83 | {
84 | locations[i].Moisture = (float) i/(locations.Count() - 1);
85 | }
86 | }
87 |
88 | private void CalculateCornerMoisture()
89 | {
90 | var queue = new Queue();
91 |
92 | foreach (var q in App.AppMap.Corners.Values)
93 | {
94 | if ((q.Water || q.River > 0) && !q.Ocean)
95 | {
96 | q.Moisture = q.River > 0 ? Math.Min(3.0, (0.2 * q.River)) : 1.0;
97 | queue.Enqueue(q);
98 | }
99 | else
100 | {
101 | q.Moisture = 0.0;
102 | }
103 | }
104 |
105 | while (queue.Count > 0)
106 | {
107 | var q = queue.Dequeue();
108 |
109 | foreach (var r in q.Adjacents)
110 | {
111 | var newMoisture = q.Moisture * 0.9;
112 | if (newMoisture > r.Moisture)
113 | {
114 | r.Moisture = newMoisture;
115 | queue.Enqueue(r);
116 | }
117 | }
118 | }
119 |
120 | foreach (var q in App.AppMap.Corners.Values)
121 | {
122 | if (q.Ocean || q.Coast)
123 | {
124 | q.Moisture = 1.0;
125 | }
126 | }
127 | }
128 |
129 | private void CreateRivers()
130 | {
131 | for (int i = 0; i < MapX / 2; i++)
132 | {
133 | Corner q = App.AppMap.Corners.Values.ElementAt(App.Random.Next(0, App.AppMap.Corners.Values.Count - 1));
134 |
135 | if (q.Ocean || q.Elevation < 0.3 || q.Elevation > 0.9) continue;
136 |
137 | while (!q.Coast)
138 | {
139 | if (q == q.Downslope)
140 | {
141 | break;
142 | }
143 |
144 | Edge edge = q.Protrudes.FirstOrDefault(ed => ed.VoronoiStart == q.Downslope || ed.VoronoiEnd == q.Downslope);
145 | edge.River = edge.River + 1;
146 | q.River = q.River + 1;
147 | q.Downslope.River = q.Downslope.River + 1;
148 | q = q.Downslope;
149 | }
150 | }
151 | }
152 |
153 | private void CalculateWatersheds()
154 | {
155 |
156 | foreach (var q in App.AppMap.Corners.Values)
157 | {
158 | q.Watershed = q;
159 |
160 | if (!q.Ocean && !q.Coast)
161 | {
162 | q.Watershed = q.Downslope;
163 | }
164 | }
165 |
166 | for (int i = 0; i < 100; i++)
167 | {
168 | var changed = false;
169 |
170 | foreach (var q in App.AppMap.Corners.Values)
171 | {
172 | if (!q.Ocean && !q.Coast && !q.Watershed.Coast)
173 | {
174 | var r = q.Downslope.Watershed;
175 |
176 | if (!r.Ocean)
177 | q.Watershed = r;
178 |
179 | changed = true;
180 | }
181 | }
182 |
183 | if (!changed)
184 | break;
185 | }
186 |
187 | foreach (var q in App.AppMap.Corners.Values)
188 | {
189 | var r = q.Watershed;
190 | r.WatershedSize = 1 + r.WatershedSize;
191 | }
192 |
193 | }
194 |
195 | private void CalculateDownslopes()
196 | {
197 | foreach (Corner corner in App.AppMap.Corners.Values)
198 | {
199 | var buf = corner;
200 |
201 | foreach (var adj in corner.Adjacents)
202 | {
203 | if (adj.Elevation <= buf.Elevation)
204 | {
205 | buf = adj;
206 | }
207 | }
208 |
209 | corner.Downslope = buf;
210 | }
211 | }
212 |
213 | private void RedistributeElevation()
214 | {
215 | double scaleFactor = 1.1;
216 | var locations = App.AppMap.Corners.Values.Where(x => !x.Ocean).OrderBy(x => x.Elevation).ToArray();
217 |
218 | for (int i = 0; i < locations.Count(); i++)
219 | {
220 | double y = (double)i / (locations.Count() - 1);
221 |
222 | var x = 1.04880885 - Math.Sqrt(scaleFactor * (1 - y));
223 | if (x > 1.0)
224 | x = 1.0;
225 | locations[i].Elevation = x;
226 | }
227 | }
228 |
229 | private void CalculateElevation()
230 | {
231 | var queue = new Queue();
232 |
233 | foreach (var q in App.AppMap.Corners.Values)
234 | {
235 | if (q.Border)
236 | {
237 | q.Elevation = 0.0;
238 | queue.Enqueue(q);
239 | }
240 | else
241 | {
242 | q.Elevation = double.MaxValue;
243 | }
244 | }
245 |
246 | while (queue.Count > 0)
247 | {
248 | var corner = queue.Dequeue();
249 |
250 | foreach (var adj in corner.Adjacents)
251 | {
252 | double newElevation = 0.01 + corner.Elevation;
253 |
254 | if (!corner.Water && !adj.Water)
255 | {
256 | newElevation += 1;
257 | }
258 |
259 | if (newElevation < adj.Elevation)
260 | {
261 | adj.Elevation = newElevation;
262 | queue.Enqueue(adj);
263 | }
264 | }
265 | }
266 |
267 |
268 | }
269 |
270 |
271 | private void Smooth1()
272 | {
273 | var ordered = new List();
274 | var first = App.AppMap.Corners.Values.First(x => x.Coast && x.Touches.Any(z=>z.Ocean));
275 | var start = first;
276 | ordered.Add(first);
277 | var next = first.Adjacents.First(x => x.Coast);
278 |
279 | while (next != start)
280 | {
281 | var nexte = next.Protrudes.FirstOrDefault(x => x.Coast && (x.VoronoiStart != ordered.Last() && x.VoronoiEnd != ordered.Last()));
282 | ordered.Add(next);
283 | next = nexte.VoronoiStart == next ? nexte.VoronoiEnd : nexte.VoronoiStart;
284 | }
285 |
286 | for (int a = 0; a < 2; a++)
287 | {
288 | for (int i = 2; i < ordered.Count - 2; i++)
289 | {
290 | ordered[i].Point = PointOnCurve(ordered[i - 2].Point, ordered[i - 1].Point, ordered[i + 1].Point,
291 | ordered[i + 2].Point, 0.5f);
292 | }
293 | }
294 | }
295 |
296 | public Point PointOnCurve(Point p0, Point p1, Point p2, Point p3, float t)
297 | {
298 | Point ret = new Point();
299 |
300 | float t2 = t * t;
301 | float t3 = t2 * t;
302 |
303 | ret.X = 0.5f * ((2.0f * p1.X) +
304 | (-p0.X + p2.X) * t +
305 | (2.0f * p0.X - 5.0f * p1.X + 4 * p2.X - p3.X) * t2 +
306 | (-p0.X + 3.0f * p1.X - 3.0f * p2.X + p3.X) * t3);
307 |
308 | ret.Y = 0.5f * ((2.0f * p1.Y) +
309 | (-p0.Y + p2.Y) * t +
310 | (2.0f * p0.Y - 5.0f * p1.Y + 4 * p2.Y - p3.Y) * t2 +
311 | (-p0.Y + 3.0f * p1.Y - 3.0f * p2.Y + p3.Y) * t3);
312 |
313 | return ret;
314 | }
315 |
316 | private void FixCentersFloodFillOceans()
317 | {
318 | foreach (var ct in App.AppMap.Centers.Values)
319 | {
320 | ct.FixBorders(); //Fix edges at map border , set "border" and "ocean" values
321 | ct.OrderCorners(); //Order corners clockwise as we'Ll need it for polygons and 3d stuff
322 |
323 | //if it touches any water corner , it's water ; there will be leftovers tho
324 | ct.Water = (ct.Corners.Any(x => x.Water)) ? true : false;
325 | }
326 |
327 | var Oceans = new Queue();
328 | //start with oceans at the borders
329 | foreach (Center c in App.AppMap.Centers.Values.Where(c => c.Ocean))
330 | {
331 | Oceans.Enqueue(c);
332 | }
333 |
334 | //floodfill oceans
335 | while (Oceans.Count > 0)
336 | {
337 | Center c = Oceans.Dequeue();
338 |
339 | foreach (Center n in c.Neighbours.Where(x => !x.Ocean))
340 | {
341 | if (n.Corners.Any(x => x.Water))
342 | {
343 | n.Ocean = true;
344 | if (!Oceans.Contains(n))
345 | Oceans.Enqueue(n);
346 | }
347 | else
348 | {
349 | n.Coast = true;
350 | }
351 | }
352 | }
353 | }
354 |
355 | private bool InLand(Point p)
356 | {
357 | return IsLandShape(new Point(2 * (p.X / MapX - 0.5), 2 * (p.Y / MapY - 0.5)));
358 | }
359 |
360 | private bool IsLandShape(Point point)
361 | {
362 | double ISLAND_FACTOR = 1.07;
363 | Random islandRandom = new Random();
364 | int bumps = islandRandom.Next(1, 6);
365 | double startAngle = islandRandom.NextDouble() * 2 * Math.PI;
366 | double dipAngle = islandRandom.NextDouble() * 2 * Math.PI;
367 | double dipWidth = islandRandom.Next(2, 7) / 10;
368 |
369 | double angle = Math.Atan2(point.Y, point.X);
370 | double length = 0.5 * (Math.Max(Math.Abs(point.X), Math.Abs(point.Y)) + GetPointLength(point));
371 |
372 | double r1 = 0.5 + 0.40 * Math.Sin(startAngle + bumps * angle + Math.Cos((bumps + 3) * angle));
373 | double r2 = 0.7 - 0.20 * Math.Sin(startAngle + bumps * angle - Math.Sin((bumps + 2) * angle));
374 | if (Math.Abs(angle - dipAngle) < dipWidth
375 | || Math.Abs(angle - dipAngle + 2 * Math.PI) < dipWidth
376 | || Math.Abs(angle - dipAngle - 2 * Math.PI) < dipWidth)
377 | {
378 | r1 = r2 = 0.2;
379 | }
380 | return (length < r1 || (length > r1 * ISLAND_FACTOR && length < r2));
381 | }
382 |
383 | private double GetPointLength(Point point)
384 | {
385 | return Math.Sqrt((Math.Pow(point.X, 2)) + (Math.Pow(point.Y, 2)));
386 | }
387 |
388 | }
389 | }
390 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/BraveNewWorld/Services/MapService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows;
6 | using BenTools.Mathematics;
7 | using BraveNewWorld.Models;
8 | using Vector = BenTools.Mathematics.Vector;
9 |
10 | namespace BraveNewWorld.Services
11 | {
12 | //do I need this? meh
13 | public class LoadMapParams
14 | {
15 | public IEnumerable Points;
16 | public bool Fix;
17 | public int MapX;
18 | public int MapY;
19 |
20 | public LoadMapParams(IEnumerable points, bool fix = false)
21 | {
22 | Points = points;
23 | Fix = fix;
24 | }
25 |
26 | public LoadMapParams(IEnumerable points, bool fix, int mapX, int mapY)
27 | {
28 | Points = points;
29 | Fix = fix;
30 | MapX = mapX;
31 | MapY = mapY;
32 | }
33 | }
34 |
35 | public interface IMapService
36 | {
37 | void LoadMap(LoadMapParams loadMapParams);
38 | }
39 |
40 | public class MapService : IMapService
41 | {
42 | private int MapX, MapY;
43 | private IIslandService IslandHandler;
44 |
45 | public void LoadMap(LoadMapParams loadMapParams)
46 | {
47 | MapX = loadMapParams.MapX;
48 | MapY = loadMapParams.MapY;
49 | IslandHandler = new IslandService(MapX, MapY);
50 |
51 | VoronoiGraph voronoiMap = null;
52 | for (int i = 0; i < 3; i++)
53 | {
54 | voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points);
55 | foreach (Vector vector in loadMapParams.Points)
56 | {
57 | double v0 = 0.0d;
58 | double v1 = 0.0d;
59 | int say = 0;
60 | foreach (VoronoiEdge edge in voronoiMap.Edges)
61 | {
62 | if (edge.LeftData == vector || edge.RightData == vector)
63 | {
64 | double p0 = (edge.VVertexA[0] + edge.VVertexB[0]) / 2;
65 | double p1 = (edge.VVertexA[1] + edge.VVertexB[1]) / 2;
66 | v0 += double.IsNaN(p0) ? 0 : p0;
67 | v1 += double.IsNaN(p1) ? 0 : p1;
68 | say++;
69 | }
70 | }
71 |
72 | if (((v0 / say) < MapX) && ((v0 / say) > 0))
73 | {
74 | vector[0] = v0 / say;
75 | }
76 |
77 | if (((v1 / say) < MapY) && ((v1 / say) > 0))
78 | {
79 | vector[1] = v1 / say;
80 | }
81 | }
82 | }
83 |
84 |
85 |
86 | voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points);
87 | ImproveMapData(voronoiMap, loadMapParams.Fix);
88 | }
89 |
90 | private void ImproveMapData(VoronoiGraph voronoiMap, bool fix = false)
91 | {
92 | IFactory fact = new MapItemFactory();
93 |
94 | foreach (VoronoiEdge edge in voronoiMap.Edges)
95 | {
96 | if (fix)
97 | {
98 | if (!FixPoints(edge))
99 | continue;
100 | }
101 |
102 | Corner c1 = fact.CornerFactory(edge.VVertexA[0], edge.VVertexA[1]);
103 | Corner c2 = fact.CornerFactory(edge.VVertexB[0], edge.VVertexB[1]);
104 | Center cntrLeft = fact.CenterFactory(edge.LeftData[0], edge.LeftData[1]);
105 | Center cntrRight = fact.CenterFactory(edge.RightData[0], edge.RightData[1]);
106 |
107 | if(c1 == null || c2 == null)
108 | {
109 |
110 | }
111 |
112 | c1.AddAdjacent(c2);
113 | c2.AddAdjacent(c1);
114 |
115 | cntrRight.Corners.Add(c1);
116 | cntrRight.Corners.Add(c2);
117 |
118 | cntrLeft.Corners.Add(c1);
119 | cntrLeft.Corners.Add(c2);
120 |
121 | Edge e = fact.EdgeFactory(c1, c2, cntrLeft, cntrRight);
122 |
123 |
124 | cntrLeft.Borders.Add(e);
125 | cntrRight.Borders.Add(e);
126 |
127 | cntrLeft.Neighbours.Add(cntrRight);
128 | cntrRight.Neighbours.Add(cntrLeft);
129 |
130 | c1.AddProtrudes(e);
131 | c2.AddProtrudes(e);
132 | c1.AddTouches(cntrLeft);
133 | c1.AddTouches(cntrRight);
134 | c2.AddTouches(cntrLeft);
135 | c2.AddTouches(cntrRight);
136 | }
137 |
138 | foreach (Corner q in App.AppMap.Corners.Values)
139 | {
140 | if (!q.Border)
141 | {
142 | var point = new Point(0, 0);
143 | foreach (Center c in q.Touches)
144 | {
145 | point.X += c.Point.X;
146 | point.Y += c.Point.Y;
147 | }
148 | point.X = point.X / q.Touches.Count;
149 | point.Y = point.Y / q.Touches.Count;
150 | q.Point = point;
151 | }
152 | }
153 |
154 | //foreach (var c in App.AppMap.Centers)
155 | //{
156 | // c.Value.FixBorders();
157 | // c.SetEdgeAreas();
158 | // c.Value.OrderCorners();
159 | //}
160 |
161 | IslandHandler.CreateIsland();
162 | }
163 |
164 | private bool FixPoints(VoronoiEdge edge)
165 | {
166 | double x1 = edge.VVertexA[0];
167 | double y1 = edge.VVertexA[1];
168 |
169 | double x2 = edge.VVertexB[0];
170 | double y2 = edge.VVertexB[1];
171 |
172 |
173 |
174 | //if both ends are in map, not much to do
175 | if ((DotInMap(x1, y1) && DotInMap(x2, y2)))
176 | return true;
177 |
178 | //if one end is out of map
179 | if ((DotInMap(x1, y1) && !DotInMap(x2, y2)) || (!DotInMap(x1, y1) && DotInMap(x2, y2)))
180 | {
181 | double b = 0.0d, slope = 0.0d;
182 |
183 | //and that point is actually a number ( not going to infinite )
184 | if (!(double.IsNaN(x2) || double.IsNaN(y2)))
185 | {
186 | slope = ((y2 - y1) / (x2 - x1));
187 |
188 | b = edge.VVertexA[1] - (slope * edge.VVertexA[0]);
189 |
190 | // y = ( slope * x ) + b
191 |
192 |
193 | if (edge.VVertexA[0] < 0)
194 | edge.VVertexA = new Vector(0, b);
195 |
196 | if (edge.VVertexA[0] > App.MapSize)
197 | edge.VVertexA = new Vector(App.MapSize, (App.MapSize * slope) + b);
198 |
199 | if (edge.VVertexA[1] < 0)
200 | edge.VVertexA = new Vector((-b / slope), 0);
201 |
202 | if (edge.VVertexA[1] > App.MapSize)
203 | edge.VVertexA = new Vector((App.MapSize - b) / slope, App.MapSize);
204 |
205 |
206 |
207 | if (edge.VVertexB[0] < 0)
208 | edge.VVertexB = new Vector(0, b);
209 |
210 | if (edge.VVertexB[0] > App.MapSize)
211 | edge.VVertexB = new Vector(App.MapSize, (App.MapSize * slope) + b);
212 |
213 | if (edge.VVertexB[1] < 0)
214 | edge.VVertexB = new Vector((-b / slope), 0);
215 |
216 | if (edge.VVertexB[1] > App.MapSize)
217 | edge.VVertexB = new Vector((App.MapSize - b) / slope, App.MapSize);
218 |
219 | }
220 | else
221 | {
222 | //and if that end is actually not a number ( going to infinite )
223 | if (double.IsNaN(x2) || double.IsNaN(y2))
224 | {
225 | var x3 = (edge.LeftData[0] + edge.RightData[0]) / 2;
226 | var y3 = (edge.LeftData[1] + edge.RightData[1]) / 2;
227 |
228 | slope = ((y3 - y1) / (x3 - x1));
229 |
230 | slope = Math.Abs(slope);
231 |
232 | b = edge.VVertexA[1] - (slope * edge.VVertexA[0]);
233 |
234 | // y = ( slope * x ) + b
235 | var i = 0.0d;
236 |
237 | if(x3 < y3)
238 | {
239 | if(App.MapSize - x3 > y3)
240 | {
241 | i = b;
242 | if (i > 0 && i < MapY)
243 | edge.VVertexB = new Vector(0, i);
244 |
245 | }
246 | else
247 | {
248 | i = (MapX - b) / slope;
249 | if (i > 0 && i < MapY)
250 | edge.VVertexB = new Vector(i, MapY);
251 |
252 | }
253 | }
254 | else
255 | {
256 | if (MapX - x3 > y3)
257 | {
258 | i = (-b / slope);
259 | if (i > 0 && i < MapX)
260 | edge.VVertexB = new BenTools.Mathematics.Vector(i, 0);
261 | }
262 | else
263 | {
264 | i = (MapY * slope) + b;
265 | if (i > 0 && i < MapX)
266 | edge.VVertexB = new BenTools.Mathematics.Vector(MapX, i);
267 |
268 | }
269 | }
270 | }
271 | }
272 | return true;
273 | }
274 | return false;
275 | }
276 |
277 | private bool DotInMap(double x, double y)
278 | {
279 | if (x == double.NaN || y == double.NaN)
280 | return false;
281 |
282 | return (x > 0 && x < MapX) && (y > 0 && y < MapY);
283 | }
284 |
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | using System;
10 | using System.Reflection;
11 | using System.Runtime.CompilerServices;
12 | using System.Runtime.InteropServices;
13 |
14 | // Information about this assembly is defined by the following attributes.
15 | // Change them to the values specific to your project.
16 |
17 | [assembly: AssemblyTitle("FortuneVoronoi")]
18 | [assembly: AssemblyDescription("")]
19 | [assembly: AssemblyConfiguration("")]
20 | [assembly: AssemblyCompany("Taffer")]
21 | [assembly: AssemblyProduct("")]
22 | [assembly: AssemblyCopyright("Free to use, copy, fork, etc. but don't blame me if it breaks.")]
23 | [assembly: AssemblyTrademark("")]
24 | [assembly: AssemblyCulture("")]
25 |
26 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
27 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
28 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
29 |
30 | [assembly: AssemblyVersion("1.0.*")]
31 |
32 | // The following attributes are used to specify the signing key for the assembly,
33 | // if desired. See the Mono documentation for more information about signing.
34 |
35 | //[assembly: AssemblyDelaySign(false)]
36 | //[assembly: AssemblyKeyFile("")]
37 |
38 | // Must be false due to UnityEngine.
39 | [assembly: CLSCompliant(false)]
40 | [assembly: ComVisible(false)]
41 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/Fortune.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 | using System.Collections;
13 |
14 | using NGenerics.DataStructures.Mathematical;
15 | using NGenerics.DataStructures.Queues;
16 |
17 | // VoronoiVertex or VoronoiDataPoint are represented as Vector
18 |
19 | public abstract class Fortune
20 | {
21 | ///
22 | /// The VV infinite.
23 | ///
24 | public static readonly Vector2D VVInfinite = new Vector2D(double.PositiveInfinity, double.PositiveInfinity);
25 | ///
26 | /// The VV unkown.
27 | ///
28 | public static readonly Vector2D VVUnkown = new Vector2D(double.NaN, double.NaN);
29 |
30 | internal static double ParabolicCut(double x1, double y1, double x2, double y2, double ys)
31 | {
32 | if(Math.Abs(x1-x2)<1e-10 && Math.Abs(y1-y2)<1e-10)
33 | {
34 | throw new Exception("Identical datapoints are not allowed!");
35 | }
36 |
37 | if(Math.Abs(y1-ys)<1e-10 && Math.Abs(y2-ys)<1e-10) {
38 | return (x1+x2)/2;
39 | }
40 |
41 | if(Math.Abs(y1-ys)<1e-10) {
42 | return x1;
43 | }
44 |
45 | if(Math.Abs(y2-ys)<1e-10) {
46 | return x2;
47 | }
48 |
49 | double a1 = 1/(2*(y1-ys));
50 | double a2 = 1/(2*(y2-ys));
51 | if(Math.Abs(a1-a2)<1e-10) {
52 | return (x1+x2)/2;
53 | }
54 |
55 | double xs1 = (double)(0.5/(2*a1-2*a2)*(4*a1*x1-4*a2*x2+2*Math.Sqrt(-8*a1*x1*a2*x2-2*a1*y1+2*a1*y2+4*a1*a2*x2*x2+2*a2*y1+4*a2*a1*x1*x1-2*a2*y2)));
56 | double xs2 = (double)(0.5/(2*a1-2*a2)*(4*a1*x1-4*a2*x2-2*Math.Sqrt(-8*a1*x1*a2*x2-2*a1*y1+2*a1*y2+4*a1*a2*x2*x2+2*a2*y1+4*a2*a1*x1*x1-2*a2*y2)));
57 | xs1=(double)Math.Round(xs1,10);
58 | xs2=(double)Math.Round(xs2,10);
59 | if(xs1>xs2)
60 | {
61 | double h = xs1;
62 | xs1=xs2;
63 | xs2=h;
64 | }
65 |
66 | if(y1>=y2) {
67 | return xs2;
68 | }
69 |
70 | return xs1;
71 | }
72 |
73 | internal static Vector2D CircumCircleCenter(Vector2D A, Vector2D B, Vector2D C)
74 | {
75 | if(A==B || B==C || A==C) {
76 | throw new Exception("Need three different points!");
77 | }
78 |
79 | double tx = (A.X + C.X)/2;
80 | double ty = (A.Y + C.Y)/2;
81 |
82 | double vx = (B.X + C.X)/2;
83 | double vy = (B.Y + C.Y)/2;
84 |
85 | double ux,uy,wx,wy;
86 |
87 | if(A.X == C.X)
88 | {
89 | ux = 1;
90 | uy = 0;
91 | }
92 | else
93 | {
94 | ux = (C.Y - A.Y)/(A.X - C.X);
95 | uy = 1;
96 | }
97 |
98 | if(B.X == C.X)
99 | {
100 | wx = -1;
101 | wy = 0;
102 | }
103 | else
104 | {
105 | wx = (B.Y - C.Y)/(B.X - C.X);
106 | wy = -1;
107 | }
108 |
109 | double alpha = (wy*(vx-tx)-wx*(vy - ty))/(ux*wy-wx*uy);
110 |
111 | return new Vector2D(tx+alpha*ux,ty+alpha*uy);
112 | }
113 |
114 | ///
115 | /// Computes the voronoi graph.
116 | ///
117 | ///
118 | /// The voronoi graph.
119 | ///
120 | ///
121 | /// Datapoints.
122 | ///
123 | ///
124 | /// Represents errors that occur during application execution.
125 | ///
126 | public static VoronoiGraph ComputeVoronoiGraph(IEnumerable Datapoints)
127 | {
128 | PriorityQueue PQ = new PriorityQueue(PriorityQueueType.Minimum);
129 | Hashtable CurrentCircles = new Hashtable();
130 | VoronoiGraph VG = new VoronoiGraph();
131 | VNode RootNode = null;
132 |
133 | foreach(Vector2D V in Datapoints)
134 | {
135 | PQ.Enqueue(new VDataEvent(V));
136 | }
137 |
138 | while(PQ.Count>0)
139 | {
140 | VEvent VE = PQ.Dequeue() as VEvent;
141 | VDataNode[] CircleCheckList;
142 |
143 | if(VE is VDataEvent)
144 | {
145 | RootNode = VNode.ProcessDataEvent(VE as VDataEvent,RootNode,VG,VE.Y,out CircleCheckList);
146 | }
147 | else if(VE is VCircleEvent)
148 | {
149 | CurrentCircles.Remove(((VCircleEvent)VE).NodeN);
150 | if(!((VCircleEvent)VE).Valid)
151 | continue;
152 | RootNode = VNode.ProcessCircleEvent(VE as VCircleEvent,RootNode,VG,VE.Y,out CircleCheckList);
153 | }
154 | else {
155 | throw new Exception("Got event of type "+VE.GetType().ToString()+"!");
156 | }
157 |
158 | foreach(VDataNode VD in CircleCheckList)
159 | {
160 | if(CurrentCircles.ContainsKey(VD))
161 | {
162 | ((VCircleEvent)CurrentCircles[VD]).Valid=false;
163 | CurrentCircles.Remove(VD);
164 | }
165 |
166 | VCircleEvent VCE = VNode.CircleCheckDataNode(VD,VE.Y);
167 | if(VCE!=null)
168 | {
169 | PQ.Enqueue(VCE);
170 | CurrentCircles[VD]=VCE;
171 | }
172 | }
173 |
174 | if(VE is VDataEvent)
175 | {
176 | Vector2D DP = ((VDataEvent)VE).DataPoint;
177 | foreach(VCircleEvent VCE in CurrentCircles.Values)
178 | {
179 | if(MathTools.Dist(DP.X,DP.Y,VCE.Center.X,VCE.Center.Y)1e-10) {
180 | VCE.Valid = false;
181 | }
182 | }
183 | }
184 | }
185 |
186 | return VG;
187 | }
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/FortuneVoronoi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 10.0.0
7 | 2.0
8 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}
9 | Library
10 | BenDi.FortuneVoronoi
11 | BenDi.FortuneVoronoi
12 | Fortune's Voronoi algorithm, based on code by BenDi on Code Project:
13 | http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug
21 | DEBUG;
22 | prompt
23 | 4
24 | false
25 | true
26 | AllRules.ruleset
27 | true
28 |
29 |
30 | none
31 | false
32 | bin\Release
33 | prompt
34 | 4
35 | false
36 |
37 |
38 |
39 |
40 |
41 |
42 | lib\NGenerics.dll
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | // This file is used by Code Analysis to maintain SuppressMessage
2 | // attributes that are applied to this project.
3 | // Project-level suppressions either have no target or are given
4 | // a specific target and scoped to a namespace, type, member, etc.
5 | //
6 | // To add a suppression to this file, right-click the message in the
7 | // Error List, point to "Suppress Message(s)", and click
8 | // "In Project Suppression File".
9 | // You do not need to add suppressions to this file manually.
10 |
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Di", Scope = "namespace", Target = "BenDi.FortuneVoronoi", Justification="Original author's handle." )]
12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Voronoi", Scope = "namespace", Target = "BenDi.FortuneVoronoi", Justification="That's the correct spelling." )]
13 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification="It's not mine, I'm not signing it." )]
14 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Di", Justification="Original author's handle." )]
15 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Voronoi", Justification="That's the correct spelling." )]
16 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Scope = "type", Target = "BenDi.FortuneVoronoi.BinaryPriorityQueue", Justification="A queue is a collection." )]
17 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Scope = "type", Target = "BenDi.FortuneVoronoi.BinaryPriorityQueue", Justification="A queue is a collection." )]
18 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/ToolBox.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 | using System.Collections;
13 | using System.IO;
14 | using System.Text;
15 | using System.Drawing;
16 |
17 | public abstract class MathTools
18 | {
19 | ///
20 | /// Dist the specified x1, y1, x2 and y2.
21 | ///
22 | ///
23 | /// X1.
24 | ///
25 | ///
26 | /// Y1.
27 | ///
28 | ///
29 | /// X2.
30 | ///
31 | ///
32 | /// Y2.
33 | ///
34 | public static double Dist(double x1, double y1, double x2, double y2)
35 | {
36 | return (double)Math.Sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
37 | }
38 |
39 | ///
40 | /// Ccw the specified P0x, P0y, P1x, P1y, P2x, P2y and PlusOneOnZeroDegrees.
41 | ///
42 | ///
43 | /// P0x.
44 | ///
45 | ///
46 | /// P0y.
47 | ///
48 | ///
49 | /// P1x.
50 | ///
51 | ///
52 | /// P1y.
53 | ///
54 | ///
55 | /// P2x.
56 | ///
57 | ///
58 | /// P2y.
59 | ///
60 | ///
61 | /// Plus one on zero degrees.
62 | ///
63 | public static int ccw(double P0x, double P0y, double P1x, double P1y, double P2x, double P2y, bool PlusOneOnZeroDegrees)
64 | {
65 | double dx1, dx2, dy1, dy2;
66 |
67 | dx1 = P1x - P0x;
68 | dy1 = P1y - P0y;
69 | dx2 = P2x - P0x;
70 | dy2 = P2y - P0y;
71 |
72 | if (dx1*dy2 > dy1*dx2) {
73 | return +1;
74 | }
75 |
76 | if (dx1*dy2 < dy1*dx2) {
77 | return -1;
78 | }
79 |
80 | if ((dx1*dx2 < 0) || (dy1*dy2 < 0)) {
81 | return -1;
82 | }
83 |
84 | if ((dx1*dx1+dy1*dy1) < (dx2*dx2+dy2*dy2) && PlusOneOnZeroDegrees) {
85 | return +1;
86 | }
87 |
88 | return 0;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VCircleEvent.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | using NGenerics.DataStructures.Mathematical;
14 |
15 | internal class VCircleEvent : VEvent
16 | {
17 | ///
18 | /// The node n.
19 | ///
20 | public VDataNode NodeN;
21 |
22 | ///
23 | /// The node l.
24 | ///
25 | public VDataNode NodeL;
26 |
27 | ///
28 | /// The node r.
29 | ///
30 | public VDataNode NodeR;
31 |
32 | ///
33 | /// The center.
34 | ///
35 | public Vector2D Center;
36 |
37 | ///
38 | /// The valid.
39 | ///
40 | public bool Valid = true;
41 |
42 | ///
43 | /// Gets the y.
44 | ///
45 | ///
46 | /// The y.
47 | ///
48 | public override double Y {
49 | get {
50 | return Math.Round( Center.Y + MathTools.Dist( NodeN.DataPoint.X, NodeN.DataPoint.Y, Center.X, Center.Y ), 10 );
51 | }
52 | }
53 |
54 | ///
55 | /// Gets the x.
56 | ///
57 | ///
58 | /// The x.
59 | ///
60 | public override double X {
61 | get {
62 | return Center.X;
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VDataEvent.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | using NGenerics.DataStructures.Mathematical;
14 |
15 | internal class VDataEvent : VEvent
16 | {
17 | ///
18 | /// The data point.
19 | ///
20 | public Vector2D DataPoint;
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | ///
26 | /// D.
27 | ///
28 | public VDataEvent( Vector2D DP )
29 | {
30 | this.DataPoint = DP;
31 | }
32 |
33 | ///
34 | /// Gets the y.
35 | ///
36 | ///
37 | /// The y.
38 | ///
39 | public override double Y {
40 | get {
41 | return DataPoint.Y;
42 | }
43 | }
44 |
45 | ///
46 | /// Gets the x.
47 | ///
48 | ///
49 | /// The x.
50 | ///
51 | public override double X {
52 | get {
53 | return DataPoint.X;
54 | }
55 | }
56 |
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VDataNode.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | using NGenerics.DataStructures.Mathematical;
14 |
15 | internal class VDataNode : VNode
16 | {
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | ///
21 | /// D.
22 | ///
23 | public VDataNode( Vector2D DP )
24 | {
25 | this.DataPoint = DP;
26 | }
27 |
28 | ///
29 | /// The data point.
30 | ///
31 | public Vector2D DataPoint;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VEdgeNode.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | internal class VEdgeNode : VNode
14 | {
15 | ///
16 | /// Initializes a new instance of the class.
17 | ///
18 | ///
19 | /// E.
20 | ///
21 | ///
22 | /// Flipped.
23 | ///
24 | public VEdgeNode( VoronoiEdge E, bool Flipped )
25 | {
26 | this.Edge = E;
27 | this.Flipped = Flipped;
28 | }
29 |
30 | ///
31 | /// The edge.
32 | ///
33 | public VoronoiEdge Edge;
34 |
35 | ///
36 | /// The flipped.
37 | ///
38 | public bool Flipped;
39 |
40 | ///
41 | /// Cut the specified ys and x.
42 | ///
43 | ///
44 | /// Ys.
45 | ///
46 | ///
47 | /// X.
48 | ///
49 | public double Cut( double ys, double x )
50 | {
51 | if( !Flipped ) {
52 | return (double)Math.Round( x - Fortune.ParabolicCut( Edge.LeftData.X, Edge.LeftData.Y, Edge.RightData.X, Edge.RightData.Y, ys ) );
53 | }
54 |
55 | return (double)Math.Round( x - Fortune.ParabolicCut( Edge.RightData.X, Edge.RightData.Y, Edge.LeftData.X, Edge.LeftData.Y, ys ) );
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VEvent.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | internal abstract class VEvent : IComparable
14 | {
15 | ///
16 | /// Gets the y.
17 | ///
18 | ///
19 | /// The y.
20 | ///
21 | public abstract double Y { get; }
22 |
23 | ///
24 | /// Gets the x.
25 | ///
26 | ///
27 | /// The x.
28 | ///
29 | public abstract double X { get; }
30 |
31 | #region IComparable Members
32 |
33 | ///
34 | /// Compares to a VEvent.
35 | ///
36 | ///
37 | /// The to.
38 | ///
39 | ///
40 | /// Object.
41 | ///
42 | ///
43 | /// Is thrown when an argument passed to a method is invalid.
44 | ///
45 | public int CompareTo( object obj )
46 | {
47 | VEvent vObj = obj as VEvent;
48 |
49 | if( vObj == null ) {
50 | throw new ArgumentException( "obj not VEvent!" );
51 | }
52 |
53 | int i = Y.CompareTo( vObj.Y );
54 | if( i != 0 ) {
55 | return i;
56 | }
57 |
58 | return X.CompareTo( vObj.X );
59 | }
60 |
61 | #endregion
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VNode.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | using NGenerics.DataStructures.Mathematical;
14 |
15 | internal abstract class VNode
16 | {
17 | private VNode _Parent = null;
18 |
19 | private VNode _Left = null;
20 |
21 | private VNode _Right = null;
22 |
23 | ///
24 | /// Gets or sets the left.
25 | ///
26 | ///
27 | /// The left.
28 | ///
29 | public VNode Left {
30 | get {
31 | return _Left;
32 | }
33 |
34 | set {
35 | _Left = value;
36 | value.Parent = this;
37 | }
38 | }
39 |
40 | ///
41 | /// Gets or sets the right.
42 | ///
43 | ///
44 | /// The right.
45 | ///
46 | public VNode Right {
47 | get {
48 | return _Right;
49 | }
50 |
51 | set {
52 | _Right = value;
53 | value.Parent = this;
54 | }
55 | }
56 |
57 | ///
58 | /// Gets or sets the parent.
59 | ///
60 | ///
61 | /// The parent.
62 | ///
63 | public VNode Parent {
64 | get {
65 | return _Parent;
66 | }
67 |
68 | set {
69 | _Parent = value;
70 | }
71 | }
72 |
73 | ///
74 | /// Replace the specified ChildOld and ChildNew.
75 | ///
76 | ///
77 | /// Child old.
78 | ///
79 | ///
80 | /// Child new.
81 | ///
82 | ///
83 | /// Represents errors that occur during application execution.
84 | ///
85 | public void Replace( VNode ChildOld, VNode ChildNew )
86 | {
87 | if( Left == ChildOld ) {
88 | Left = ChildNew;
89 | }
90 | else if( Right == ChildOld ) {
91 | Right = ChildNew;
92 | }
93 | else {
94 | throw new Exception( "Child not found!" );
95 | }
96 |
97 | ChildOld.Parent = null;
98 | }
99 |
100 | ///
101 | /// Firsts the data node.
102 | ///
103 | ///
104 | /// The data node.
105 | ///
106 | ///
107 | /// Root.
108 | ///
109 | public static VDataNode FirstDataNode( VNode Root )
110 | {
111 | VNode C = Root;
112 | while( C.Left!=null ) {
113 | C = C.Left;
114 | }
115 |
116 | return C as VDataNode;
117 | }
118 |
119 | ///
120 | /// Lefts the data node.
121 | ///
122 | ///
123 | /// The data node.
124 | ///
125 | ///
126 | /// Current.
127 | ///
128 | public static VDataNode LeftDataNode( VDataNode Current )
129 | {
130 | VNode C = Current;
131 |
132 | //1. Up
133 | do {
134 | if( C.Parent == null ) {
135 | return null;
136 | }
137 | if( C.Parent.Left == C ) {
138 | C = C.Parent;
139 | continue;
140 | } else {
141 | C = C.Parent;
142 | break;
143 | }
144 | } while(true);
145 |
146 | //2. One Left
147 | C = C.Left;
148 |
149 | //3. Down
150 | while( C.Right != null ) {
151 | C = C.Right;
152 | }
153 |
154 | return C as VDataNode; // Cast statt 'as' damit eine Exception kommt
155 | }
156 |
157 | ///
158 | /// Rights the data node.
159 | ///
160 | ///
161 | /// The data node.
162 | ///
163 | ///
164 | /// Current.
165 | ///
166 | public static VDataNode RightDataNode( VDataNode Current )
167 | {
168 | VNode C = Current;
169 |
170 | //1. Up
171 | do {
172 | if( C.Parent == null ) {
173 | return null;
174 | }
175 | if( C.Parent.Right == C ) {
176 | C = C.Parent;
177 | continue;
178 | } else {
179 | C = C.Parent;
180 | break;
181 | }
182 | } while(true);
183 |
184 | //2. One Right
185 | C = C.Right;
186 |
187 | //3. Down
188 | while( C.Left != null ) {
189 | C = C.Left;
190 | }
191 |
192 | return C as VDataNode; // Cast statt 'as' damit eine Exception kommt
193 | }
194 |
195 | ///
196 | /// Edges to right data node.
197 | ///
198 | ///
199 | /// The to right data node.
200 | ///
201 | ///
202 | /// Current.
203 | ///
204 | ///
205 | /// Represents errors that occur during application execution.
206 | ///
207 | public static VEdgeNode EdgeToRightDataNode( VDataNode Current )
208 | {
209 | VNode C = Current;
210 |
211 | //1. Up
212 | do {
213 | if( C.Parent == null ) {
214 | throw new Exception( "No Left Leaf found!" );
215 | }
216 | if( C.Parent.Right == C ) {
217 | C = C.Parent;
218 | continue;
219 | } else {
220 | C = C.Parent;
221 | break;
222 | }
223 | } while(true);
224 |
225 | return C as VEdgeNode;
226 | }
227 |
228 | ///
229 | /// Finds the data node.
230 | ///
231 | ///
232 | /// The data node.
233 | ///
234 | ///
235 | /// Root.
236 | ///
237 | ///
238 | /// Ys.
239 | ///
240 | ///
241 | /// X.
242 | ///
243 | ///
244 | /// Represents errors that occur during application execution.
245 | ///
246 | public static VDataNode FindDataNode( VNode Root, double ys, double x )
247 | {
248 | VNode C = Root;
249 |
250 | do {
251 | if( C is VDataNode ) {
252 | return C as VDataNode;
253 | }
254 |
255 | VEdgeNode cEdge = C as VEdgeNode;
256 | if( cEdge == null ) {
257 | throw new Exception( "Can't cast to edge node" );
258 | }
259 | if( cEdge.Cut( ys, x ) < 0 ) {
260 | C = C.Left;
261 | }
262 | else {
263 | C = C.Right;
264 | }
265 | } while(true);
266 | }
267 |
268 | ///
269 | /// Will return the new root (unchanged except in start-up)
270 | ///
271 | ///
272 | /// Processes the data event.
273 | ///
274 | ///
275 | /// The data event.
276 | ///
277 | ///
278 | /// E.
279 | ///
280 | ///
281 | /// Root.
282 | ///
283 | ///
284 | /// V.
285 | ///
286 | ///
287 | /// Ys.
288 | ///
289 | ///
290 | /// Circle check list.
291 | ///
292 | ///
293 | /// Represents errors that occur during application execution.
294 | ///
295 | public static VNode ProcessDataEvent( VDataEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList )
296 | {
297 | if( Root == null ) {
298 | Root = new VDataNode( e.DataPoint );
299 | CircleCheckList = new VDataNode[] {Root as VDataNode};
300 | return Root;
301 | }
302 |
303 | //1. Find the node to be replaced
304 | VNode C = VNode.FindDataNode( Root, ys, e.DataPoint.X );
305 | VDataNode cData = C as VDataNode;
306 |
307 | if( cData == null ) {
308 | throw new Exception( "Can't cast to data node" );
309 | }
310 |
311 | //2. Create the subtree (ONE Edge, but two VEdgeNodes)
312 | VoronoiEdge VE = new VoronoiEdge();
313 | VE.LeftData = cData.DataPoint;
314 | VE.RightData = e.DataPoint;
315 | VE.VVertexA = Fortune.VVUnkown;
316 | VE.VVertexB = Fortune.VVUnkown;
317 | VG.Edges.Add( VE );
318 |
319 | VNode SubRoot;
320 | if( Math.Abs( VE.LeftData.Y - VE.RightData.Y ) < 1e-10 ) {
321 | if( VE.LeftData.X < VE.RightData.X ) {
322 | SubRoot = new VEdgeNode( VE, false );
323 | SubRoot.Left = new VDataNode( VE.LeftData );
324 | SubRoot.Right = new VDataNode( VE.RightData );
325 | } else {
326 | SubRoot = new VEdgeNode( VE, true );
327 | SubRoot.Left = new VDataNode( VE.RightData );
328 | SubRoot.Right = new VDataNode( VE.LeftData );
329 | }
330 |
331 | CircleCheckList = new VDataNode[] {SubRoot.Left as VDataNode, SubRoot.Right as VDataNode};
332 | } else {
333 | SubRoot = new VEdgeNode( VE, false );
334 | SubRoot.Left = new VDataNode( VE.LeftData );
335 | SubRoot.Right = new VEdgeNode( VE, true );
336 | SubRoot.Right.Left = new VDataNode( VE.RightData );
337 | SubRoot.Right.Right = new VDataNode( VE.LeftData );
338 | CircleCheckList = new VDataNode[] {SubRoot.Left as VDataNode, SubRoot.Right.Left as VDataNode, SubRoot.Right.Right as VDataNode};
339 | }
340 |
341 | //3. Apply subtree
342 | if( C.Parent == null ) {
343 | return SubRoot;
344 | }
345 |
346 | C.Parent.Replace( C, SubRoot );
347 |
348 | return Root;
349 | }
350 |
351 | ///
352 | /// Processes the circle event.
353 | ///
354 | ///
355 | /// The circle event.
356 | ///
357 | ///
358 | /// E.
359 | ///
360 | ///
361 | /// Root.
362 | ///
363 | ///
364 | /// V.
365 | ///
366 | ///
367 | /// Ys.
368 | ///
369 | ///
370 | /// Circle check list.
371 | ///
372 | public static VNode ProcessCircleEvent( VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList )
373 | {
374 | VDataNode a;
375 | VDataNode b;
376 | VDataNode c;
377 | VEdgeNode eu;
378 | VEdgeNode eo;
379 |
380 | b = e.NodeN;
381 | a = VNode.LeftDataNode( b );
382 | c = VNode.RightDataNode( b );
383 | if( a == null || b.Parent == null || c == null || !a.DataPoint.Equals( e.NodeL.DataPoint ) || !c.DataPoint.Equals( e.NodeR.DataPoint ) ) {
384 | CircleCheckList = new VDataNode[]{};
385 |
386 | return Root; // Abbruch da sich der Graph ver 0/00ndert hat
387 | }
388 |
389 | eu = b.Parent as VEdgeNode;
390 | CircleCheckList = new VDataNode[] {a,c};
391 |
392 | //1. Create the new Vertex
393 | Vector2D VNew = new Vector2D( e.Center.X, e.Center.Y );
394 |
395 | VG.Vertizes.Add( VNew );
396 |
397 | //2. Find out if a or c are in a distand part of the tree (the other is then b's sibling) and assign the new vertex
398 | if( eu.Left == b ) { // c is sibling
399 | eo = VNode.EdgeToRightDataNode( a );
400 |
401 | // replace eu by eu's Right
402 | eu.Parent.Replace( eu, eu.Right );
403 | } else { // a is sibling
404 | eo = VNode.EdgeToRightDataNode( b );
405 |
406 | // replace eu by eu's Left
407 | eu.Parent.Replace( eu, eu.Left );
408 | }
409 |
410 | eu.Edge.AddVertex( VNew );
411 | eo.Edge.AddVertex( VNew );
412 |
413 | //2. Replace eo by new Edge
414 | VoronoiEdge VE = new VoronoiEdge();
415 | VE.LeftData = a.DataPoint;
416 | VE.RightData = c.DataPoint;
417 | VE.AddVertex( VNew );
418 | VG.Edges.Add( VE );
419 |
420 | VEdgeNode VEN = new VEdgeNode( VE, false );
421 | VEN.Left = eo.Left;
422 | VEN.Right = eo.Right;
423 | if( eo.Parent == null ) {
424 | return VEN;
425 | }
426 |
427 | eo.Parent.Replace( eo, VEN );
428 |
429 | return Root;
430 | }
431 |
432 | ///
433 | /// Circles the check data node.
434 | ///
435 | ///
436 | /// The check data node.
437 | ///
438 | ///
439 | /// N.
440 | ///
441 | ///
442 | /// Ys.
443 | ///
444 | public static VCircleEvent CircleCheckDataNode( VDataNode n, double ys )
445 | {
446 | VDataNode l = VNode.LeftDataNode( n );
447 | VDataNode r = VNode.RightDataNode( n );
448 | if( l == null || r == null || l.DataPoint == r.DataPoint || l.DataPoint == n.DataPoint || n.DataPoint == r.DataPoint ) {
449 | return null;
450 | }
451 |
452 | if( MathTools.ccw( l.DataPoint.X, l.DataPoint.Y, n.DataPoint.X, n.DataPoint.Y, r.DataPoint.X, r.DataPoint.Y, false ) <= 0 ) {
453 | return null;
454 | }
455 |
456 | Vector2D Center = Fortune.CircumCircleCenter( l.DataPoint, n.DataPoint, r.DataPoint );
457 | VCircleEvent VC = new VCircleEvent();
458 | VC.NodeN = n;
459 | VC.NodeL = l;
460 | VC.NodeR = r;
461 | VC.Center = Center;
462 | VC.Valid = true;
463 | if( VC.Y >= ys ) {
464 | return VC;
465 | }
466 |
467 | return null;
468 | }
469 | }
470 | }
471 |
472 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VoronoiEdge.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 |
13 | using NGenerics.DataStructures.Mathematical;
14 |
15 | public class VoronoiEdge
16 | {
17 | ///
18 | /// The right data.
19 | ///
20 | public Vector2D RightData;
21 |
22 | ///
23 | /// The left data.
24 | ///
25 | public Vector2D LeftData;
26 |
27 | ///
28 | /// The V vertex a.
29 | ///
30 | public Vector2D VVertexA = Fortune.VVUnkown;
31 |
32 | ///
33 | /// The V vertex b.
34 | ///
35 | public Vector2D VVertexB = Fortune.VVUnkown;
36 |
37 | ///
38 | /// Adds the vertex.
39 | ///
40 | ///
41 | /// V.
42 | ///
43 | ///
44 | /// Represents errors that occur during application execution.
45 | ///
46 | public void AddVertex( Vector2D V )
47 | {
48 | if( VVertexA == Fortune.VVUnkown ) {
49 | VVertexA = V;
50 | }
51 | else if( VVertexB == Fortune.VVUnkown ) {
52 | VVertexB = V;
53 | }
54 | else {
55 | throw new Exception( "Tried to add third vertex!" );
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/VoronoiGraph.cs:
--------------------------------------------------------------------------------
1 | // Original code by BenDi on CodeProject:
2 | //
3 | // http://www.codeproject.com/KB/recipes/fortunevoronoi.aspx
4 | //
5 | // Cleaned up and adapted by Taffer for UnitySimpleMapGenerator on Github:
6 | //
7 | // https://github.com/Taffer/UnitySimpleMapGenerator
8 |
9 | namespace BenDi.FortuneVoronoi
10 | {
11 | using System;
12 | using System.Collections.Generic;
13 |
14 | using NGenerics.DataStructures.Mathematical;
15 |
16 | public class VoronoiGraph
17 | {
18 | ///
19 | /// The vertizes.
20 | ///
21 | public HashSet Vertizes = new HashSet();
22 |
23 | ///
24 | /// The edges.
25 | ///
26 | public HashSet Edges = new HashSet();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abhimir/UnitySimpleMapGenerator/6eefde5a7ccd84503b7dc8cfb574650c1d4feaa2/UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.dll
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.pdb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/abhimir/UnitySimpleMapGenerator/6eefde5a7ccd84503b7dc8cfb574650c1d4feaa2/UnitySimpleMapGenerator/FortuneVoronoi/lib/NGenerics.pdb
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/UnitySimpleMapGenerator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 10.0.0
7 | 2.0
8 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}
9 | Library
10 | Taffer.UnitySimpleMapGenerator
11 | Taffer.UnitySimpleMapGenerator
12 | This is a port of Baran Kahyaoglu's Simple Map Generator, which you can find
13 | here:
14 |
15 | http://www.barankahyaoglu.com/blog/post/2011/07/27/Simple-Map-Generator-Part-1.aspx
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug
22 | DEBUG;
23 | prompt
24 | 4
25 | false
26 |
27 |
28 | none
29 | false
30 | bin\Release
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 |
38 | ..\..\..\..\..\Applications\Unity\Unity.app\Contents\Frameworks\Managed\UnityEngine.dll
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}
48 | FortuneVoronoi
49 |
50 |
51 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}
52 | BraveNewWorld
53 |
54 |
55 |
--------------------------------------------------------------------------------
/UnitySimpleMapGenerator/UnitySimpleMapGenerator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitySimpleMapGenerator", "UnitySimpleMapGenerator.csproj", "{0BC32450-0FF3-4799-A091-3BD5FE66AB35}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FortuneVoronoi", "FortuneVoronoi\FortuneVoronoi.csproj", "{21803548-A68A-473A-BF1B-0AE5F63F9F1A}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BraveNewWorld", "BraveNewWorld\BraveNewWorld.csproj", "{5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {0BC32450-0FF3-4799-A091-3BD5FE66AB35}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {21803548-A68A-473A-BF1B-0AE5F63F9F1A}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {5ACF382B-10CE-4C85-A9AB-8B27CBD5FD76}.Release|Any CPU.Build.0 = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(MonoDevelopProperties) = preSolution
30 | StartupItem = UnitySimpleMapGenerator.csproj
31 | Policies = $0
32 | $0.DotNetNamingPolicy = $1
33 | $1.DirectoryNamespaceAssociation = Flat
34 | $1.ResourceNamePolicy = MSBuild
35 | $0.TextStylePolicy = $2
36 | $2.RemoveTrailingWhitespace = True
37 | $2.inheritsSet = VisualStudio
38 | $2.inheritsScope = text/plain
39 | $2.scope = text/x-csharp
40 | $0.CSharpFormattingPolicy = $3
41 | $3.BeforeMethodDeclarationParentheses = False
42 | $3.WithinMethodDeclarationParentheses = True
43 | $3.BeforeMethodCallParentheses = False
44 | $3.WithinMethodCallParentheses = True
45 | $3.BeforeConstructorDeclarationParentheses = False
46 | $3.WithinConstructorDeclarationParentheses = True
47 | $3.BeforeDelegateDeclarationParentheses = False
48 | $3.AfterDelegateDeclarationParameterComma = True
49 | $3.WithinDelegateDeclarationParentheses = True
50 | $3.NewParentheses = False
51 | $3.IfParentheses = False
52 | $3.WhileParentheses = False
53 | $3.ForParentheses = False
54 | $3.ForeachParentheses = False
55 | $3.CatchParentheses = False
56 | $3.SwitchParentheses = False
57 | $3.LockParentheses = False
58 | $3.UsingParentheses = False
59 | $3.WithinParentheses = True
60 | $3.WithinIfParentheses = True
61 | $3.WithinWhileParentheses = True
62 | $3.WithinForParentheses = True
63 | $3.WithinForEachParentheses = True
64 | $3.WithinCatchParentheses = True
65 | $3.WithinSwitchParentheses = True
66 | $3.WithinLockParentheses = True
67 | $3.WithinUsingParentheses = True
68 | $3.WithinNewParentheses = True
69 | $3.SpacesBeforeBrackets = False
70 | $3.inheritsSet = Mono
71 | $3.inheritsScope = text/x-csharp
72 | $3.scope = text/x-csharp
73 | $0.TextStylePolicy = $4
74 | $4.RemoveTrailingWhitespace = True
75 | $4.inheritsSet = Mono
76 | $4.inheritsScope = text/plain
77 | $4.scope = text/plain
78 | $0.StandardHeader = $5
79 | $5.Text = @-----------------------------------------------------------------------\n\nUse this code for whatever you want, just don't blame me if it breaks.\n\n-----------------------------------------------------------------------
80 | $5.IncludeInNewFiles = True
81 | $0.VersionControlPolicy = $6
82 | $6.inheritsSet = Mono
83 | $0.ChangeLogPolicy = $7
84 | $7.UpdateMode = None
85 | $7.MessageStyle = $8
86 | $8.LineAlign = 0
87 | $7.inheritsSet = Mono
88 | description = A Unity3D port of Baran Kahyaoglu's Map Generator - http://www.barankahyaoglu.com/blog/page/MapGenerator.aspx
89 | EndGlobalSection
90 | EndGlobal
91 |
--------------------------------------------------------------------------------