private void LoadPointClass(string file) { _dataList = DataManager.LoadPointCloudFromCsv(file); if (_dataList != null) { _tips.Clear(); _nodes.Clear(); _vVNodes.Clear(); _edges.Clear(); _erosionDilatationValue = 0; tbErosionDilatation.Text = $"{_erosionDilatationValue}"; _openingClosingValue = 0; tbOpeningClosing.Text = $"{_openingClosingValue}"; _fileName = System.IO.Path.GetFileName(file); Title = $"Pattern Analyser - Voronoi Diagramm ({_fileName}) - Status: wird berechnet..."; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); _voronoiGraph = Fortune.ComputeVoronoiGraph(_dataList.ToIEnumerableVectorList()); _voronoiGraphCopy = _voronoiGraph; stopWatch.Stop(); _nodes = _dataList.ToIEnumerableNodeList(ref _boundingBox).ToList(); _vVNodes = _nodes; _scaled = true; _edges = _voronoiGraph.Edges.MapEdgeHashSetToEdgeList(ActualHeight, true, _scaled).ToList(); this.MyDotViewer.LoadPlain(_nodes, _edges, _fileName, _boundingBox); _tips.Clear(); _tips = _dataList.GetOneKeyValues(); Title = $"Pattern Analyser - Voronoi Diagramm ({_fileName}) - Dauer: {stopWatch.ElapsedMilliseconds.ToString()} ms"; _frame = null; } }
public void Evaluate(int SpreadMax) { if (this.FPinInY.PinIsChanged || this.FPinInX.PinIsChanged) { IList <Vector> vectors = new List <Vector>(); #region Initialize List int ix = 0; int iy = 0; for (int i = 0; i < SpreadMax; i++) { double x, y; this.FPinInX.GetValue(ix, out x); this.FPinInY.GetValue(iy, out y); vectors.Add(new Vector(x, y)); ix++; iy++; if (ix >= this.FPinInX.SliceCount) { ix = 0; } if (iy >= this.FPinInY.SliceCount) { iy = 0; } } #endregion VoronoiGraph graph = Fortune.ComputeVoronoiGraph(vectors); //Outputs vertices this.FPinOutVertX.SliceCount = graph.Vertizes.Count; this.FPinOutVertY.SliceCount = graph.Vertizes.Count; for (int i = 0; i < graph.Vertizes.Count; i++) { this.FPinOutVertX.SetValue(i, graph.Vertizes[i][0]); this.FPinOutVertY.SetValue(i, graph.Vertizes[i][1]); } //Outputs the edges this.FPinOutEdgesX1.SliceCount = graph.Edges.Count; this.FPinOutEdgesY1.SliceCount = graph.Edges.Count; this.FPinOutEdgesX2.SliceCount = graph.Edges.Count; this.FPinOutEdgesY2.SliceCount = graph.Edges.Count; for (int i = 0; i < graph.Edges.Count; i++) { this.FPinOutEdgesX1.SetValue(i, graph.Edges[i].VVertexA[0]); this.FPinOutEdgesY1.SetValue(i, graph.Edges[i].VVertexA[1]); this.FPinOutEdgesX2.SetValue(i, graph.Edges[i].VVertexB[0]); this.FPinOutEdgesY2.SetValue(i, graph.Edges[i].VVertexB[1]); } } }
private void LoadTifImages(string file) { _fileName = System.IO.Path.GetFileName(file); _frame = BitmapDecoder.Create(new Uri(file), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad).Frames.First(); int pixelSize = _frame.Format.BitsPerPixel / 8; int stride = _frame.PixelWidth * pixelSize; int size = _frame.PixelHeight * stride; _imagePixels = new byte[size]; _frame.CopyPixels(_imagePixels, stride, 0); _tips.Clear(); _nodes.Clear(); _vVNodes.Clear(); _edges.Clear(); _erosionDilatationValue = 0; tbErosionDilatation.Text = $"{_erosionDilatationValue}"; _openingClosingValue = 0; tbOpeningClosing.Text = $"{_openingClosingValue}"; int NodeCounter = 0; // Take every four pixel of the image for (int x = 0; x < _frame.PixelWidth; x = x + 12) { for (int y = 0; y < _frame.PixelHeight; y = y + 12) { int pixelIndex = y * stride + pixelSize * x; int pixelGrayScale = (int)((_imagePixels[pixelIndex] * .21) + (_imagePixels[pixelIndex + 1] * .71) + (_imagePixels[pixelIndex + 2] * .071)); if (pixelGrayScale <= _grayScaleValue) { _nodes.Add(new Node("", x, y, 1)); _tips.Add($"Node_{NodeCounter}", NodeCounter); NodeCounter++; } else if (pixelGrayScale > _grayScaleValue && pixelGrayScale < 220) { _nodes.Add(new Node("", x, y, 0)); _tips.Add($"Node_{NodeCounter}", NodeCounter); NodeCounter++; } } } _vVNodes = _nodes; _boundingBox = new double[] { -50, -20, _frame.PixelWidth + 50, _frame.PixelHeight + 20 }; Title = $"Pattern Analyser - Voronoi Diagramm ({_fileName}) - Status: wird berechnet..."; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); _voronoiGraph = Fortune.ComputeVoronoiGraph(_nodes.MapNodeToVector()); _voronoiGraphCopy = _voronoiGraph; stopWatch.Stop(); _edges = _voronoiGraph.Edges.MapEdgeHashSetToEdgeList(ActualHeight, true, _scaled).ToList(); this.MyDotViewer.LoadPlain(_nodes, _edges, _fileName, _boundingBox, _frame, 1); Title = $"Pattern Analyser - Voronoi Diagramm ({_fileName}) - Dauer: {stopWatch.ElapsedMilliseconds.ToString()} ms"; //this.MyDotViewer.LoadSourceImage(_frame, System.IO.Path.GetFileName(file)); }
/// <summary> /// Creates the voronoi graph. /// </summary> static void CreateVoronoiGraph() { //Set map sizes WorldGen.MapX = WorldGen.width; WorldGen.MapY = WorldGen.height; //Create the IslandHandler WorldGen.IslandHandler = new IslandService(WorldGen.MapX, WorldGen.MapY); //init the points hash var points = new HashSet <BenTools.Mathematics.Vector>(); //for each dot in the complexity setting create random dots that are within the map and add them to the points list for (int i = 0; i < WorldGen.DotCount; i++) { points.Add(new BenTools.Mathematics.Vector(Random.Range(0, WorldGen.MapX), Random.Range(0, WorldGen.MapY))); } //init the map WorldGen.voronoiMap = null; //iterate on the graph 3 times (more is square, less is chaotic) for (int i = 0; i < 3; i++) { //set the map to the points by computing the graph WorldGen.voronoiMap = Fortune.ComputeVoronoiGraph(points); //for each point in the list, do some error checking and reprocessing foreach (BenTools.Mathematics.Vector vector in points) { double v0 = 0.0d; double v1 = 0.0d; int say = 0; foreach (VoronoiEdge edge in WorldGen.voronoiMap.Edges) { if (edge.LeftData == vector || edge.RightData == vector) { double p0 = (edge.VVertexA[0] + edge.VVertexB[0]) / 2; double p1 = (edge.VVertexA[1] + edge.VVertexB[1]) / 2; v0 += double.IsNaN(p0) ? 0 : p0; v1 += double.IsNaN(p1) ? 0 : p1; say++; } } if (((v0 / say) < WorldGen.MapX) && ((v0 / say) > 0)) { vector[0] = v0 / say; } if (((v1 / say) < WorldGen.MapY) && ((v1 / say) > 0)) { vector[1] = v1 / say; } } } //after 3 runs our grid should be good and we can save the final map WorldGen.voronoiMap = Fortune.ComputeVoronoiGraph(points); }
public Generator(int size) { _size = size; GenerateSquareGrid(size); _voronoiGraph = Fortune.ComputeVoronoiGraph(_points); BuildGraph(); ImproveCorners(); }
private void Button_Click(object sender, RoutedEventArgs e) { MainCanvas.Children.Clear(); var cells = new Dictionary <FortuneVoronoi.Common.Point, VoronoiCell>(); const int internalSitesCnt = 1600; const int horBorderSitesCnt = 50; const int vertBorderSitesCnt = 50; const int resolution = 16; const double realWidth = 1000.0; const double realHeight = 700.0; var dx = realWidth / horBorderSitesCnt / resolution; var dy = realHeight / vertBorderSitesCnt / resolution; var borderSites = SitesGridGenerator.GenerateTileBorder(horBorderSitesCnt, vertBorderSitesCnt, resolution); var internalSites = SitesGridGenerator.GenerateInternalSites(horBorderSitesCnt, vertBorderSitesCnt, resolution, internalSitesCnt); foreach (var site in borderSites.Concat(internalSites)) { var x = site.X * dx; var y = site.Y * dy; var v = new FortuneVoronoi.Common.Point(x, y); if (cells.ContainsKey(v)) { continue; } cells.Add(v, new VoronoiCell { IsVisible = !site.IsBorder, Site = new FortuneVoronoi.Common.Point(x, y) }); } var graph = Fortune.ComputeVoronoiGraph(cells); foreach (var cell in cells.Values.Where(c => c.IsVisible && c.IsClosed)) { var rgbFill = new byte[3]; _rnd.NextBytes(rgbFill); var fill = new SolidColorBrush(System.Windows.Media.Color.FromRgb(rgbFill[0], rgbFill[1], rgbFill[2])); var triangles = cell.CreateTriangles(); foreach (var triangle in triangles) { triangle.Fill = fill; Canvas.SetLeft(triangle, MainCanvas.ActualWidth * 0.5); Canvas.SetTop(triangle, MainCanvas.ActualHeight * 0.5); MainCanvas.Children.Add(triangle); } } }
public VoronoiTemparature(List <TemperatureLocation> temp) { temperature = temp; List <Vector> vectors = new List <Vector>(); foreach (TemperatureLocation t in temperature) { vectors.Add(new Vector(t.X, t.Y)); } maxTemperature = GetMaxTemperature(); minTemperature = GetMinTemperature(); graph = Fortune.ComputeVoronoiGraph(vectors); }
public Image ComputeVoronoiMap(Image image, bool drawEdges) { if (image == null || this.points.Count <= 0) { return(null); } this.progress = 5; VoronoiGraph graph = Fortune.ComputeVoronoiGraph(this.points); Color[,] colors = Sampler.BitmapToColorArray((Bitmap)image); int width = colors.GetLength(0) - 1; int height = colors.GetLength(1) - 1; image = (Image) new Bitmap(width + 1, height + 1); Graphics g = Graphics.FromImage(image); this.progress = 30; polygons = GetRegions(graph); this.progress = 92; foreach (scg.KeyValuePair <Vector, scg.List <PointF> > region in polygons) { Vector v = region.Key; int ix = Math.Min(Math.Max((int)Math.Round(v[0]), 0), width); int iy = Math.Min(Math.Max((int)Math.Round(v[1]), 0), height); PointF[] ps = region.Value.ToArray(); g.FillPolygon(new SolidBrush(colors[ix, iy]), ps, FillMode.Alternate); } g.Flush(); this.image = image; this.progress = 95; if (drawEdges) { DrawEdges(image); } this.progress = 100; return(image); }
public void TestMethod1() { var shape = new Vector2[] { new Vector2(200, 100), new Vector2(200, -200), new Vector2(100, -200), new Vector2(100, -100), new Vector2(-100, -100), new Vector2(-100, 100), }; var result = Fortune.ComputeVoronoiGraph(shape); //Display result StringBuilder pathVoronoiEdges = new StringBuilder(); var min = new Vector2(float.MaxValue); foreach (var voronoiEdge in result.Edges) { min = Vector2.Min(voronoiEdge.LeftData, min); min = Vector2.Min(voronoiEdge.RightData, min); float length = voronoiEdge.Length; if (float.IsPositiveInfinity(length)) { length = 1000; } var b = voronoiEdge.FixedPoint + voronoiEdge.DirectionVector * length; pathVoronoiEdges.Append($"<path d=\"M {voronoiEdge.FixedPoint.X} {voronoiEdge.FixedPoint.Y} L {b.X} {b.Y} \" stroke=\"black\"></path>"); } StringBuilder shapeData = new StringBuilder(); shapeData.Append($"M {shape.First().X} {shape.First().Y}"); foreach (var point in shape.Skip(1)) { shapeData.Append($"L {point.X} {point.Y} "); } shapeData.Append("Z"); Console.WriteLine( "<svg width=\"500px\" height=\"500px\"><g transform=\"translate({2} {3})\">{0}<path d=\"{1}\" fill=\"none\" stroke=\"green\"></path></g></svg>", pathVoronoiEdges, shapeData, -min.X + 1, -min.Y + 1 ); }
/// <summary> /// The Voronoi Graph calculation creates a delaunay tesselation where /// each point is effectively converted into triangles. /// </summary> /// <param name="points">The points to use for creating the tesselation.</param> /// <returns>The generated line featureset.</returns> public static IFeatureSet DelaunayLines(IFeatureSet points) { double[] vertices = points.Vertex; VoronoiGraph gp = Fortune.ComputeVoronoiGraph(vertices); FeatureSet result = new FeatureSet(); foreach (VoronoiEdge edge in gp.Edges) { Coordinate c1 = edge.RightData.ToCoordinate(); Coordinate c2 = edge.LeftData.ToCoordinate(); LineString ls = new LineString(new [] { c1, c2 }); result.AddFeature(ls); } return(result); }
public void LoadMap(LoadMapParams loadMapParams) { MapX = loadMapParams.MapX; MapY = loadMapParams.MapY; IslandHandler = new IslandService(MapX, MapY); VoronoiGraph voronoiMap = null; for (int i = 0; i < 3; i++) { voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points); foreach (Vector vector in loadMapParams.Points) { double v0 = 0.0d; double v1 = 0.0d; int say = 0; foreach (VoronoiEdge edge in voronoiMap.Edges) { if (edge.LeftData == vector || edge.RightData == vector) { double p0 = (edge.VVertexA[0] + edge.VVertexB[0]) / 2; double p1 = (edge.VVertexA[1] + edge.VVertexB[1]) / 2; v0 += double.IsNaN(p0) ? 0 : p0; v1 += double.IsNaN(p1) ? 0 : p1; say++; } } if (((v0 / say) < MapX) && ((v0 / say) > 0)) { vector[0] = v0 / say; } if (((v1 / say) < MapY) && ((v1 / say) > 0)) { vector[1] = v1 / say; } } } voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points); ImproveMapData(voronoiMap, loadMapParams.Fix); }
/// <summary> /// The Voronoi Graph calculation creates the lines that form a voronoi diagram. /// </summary> /// <param name="points">The points to use for creating the tesselation.</param> /// <returns>An IFeatureSet that is the resulting set of lines in the diagram.</returns> public static IFeatureSet VoronoiLines(IFeatureSet points) { double[] vertices = points.Vertex; VoronoiGraph gp = Fortune.ComputeVoronoiGraph(vertices); HandleBoundaries(gp, points.Extent.ToEnvelope()); FeatureSet result = new FeatureSet(); foreach (VoronoiEdge edge in gp.Edges) { Coordinate c1 = edge.VVertexA.ToCoordinate(); Coordinate c2 = edge.VVertexB.ToCoordinate(); LineString ls = new LineString(new [] { c1, c2 }); result.AddFeature(ls); } return(result); }
private static List <VoronoiSite> CalculateVoronoiGraph(Dictionary <Vector, VoronoiSite> points, int width, int height) { VoronoiGraph result = Fortune.ComputeVoronoiGraph(points.Keys.ToList()); foreach (VoronoiEdge edge in result.Edges) { VoronoiSite a = points[edge.LeftData]; VoronoiSite b = points[edge.RightData]; a.Neighbourgs.Add(b); b.Neighbourgs.Add(a); a.Edges.Add(edge); b.Edges.Add(edge); } foreach (VoronoiSite site in points.Values) { site.Reorder(width, height); } return(points.Values.ToList()); }
//Generate the voronoi diagram using an external library public VoronoiDiagram GetVoronoi(List <Point> points) { _siteCells = new Dictionary <Point, Cell>(); var nrPoints = points.Count; var dataPoints = new Vector[nrPoints]; for (int i = 0; i < nrPoints; i++) { var point = points[i]; if (_siteCells.ContainsKey(point)) { continue; } dataPoints[i] = new Vector(point.X, point.Y); var cell = new Cell { SitePoint = point }; _siteCells.Add(point, cell); } //Create Voronoi Data using library var data = Fortune.ComputeVoronoiGraph(dataPoints); //data = BenTools.Mathematics.Fortune.FilterVG(data, 15); //Create Diagram _voronoi = new VoronoiDiagram(); _voronoi.HalfEdges = GenerateLines(data); _voronoi.VoronoiCells = GenerateCells(data); _voronoi.Sites = points; return(_voronoi); }
// Voronoi methods private void makeVoronoiGraph() { List <Vector> VoronoiVectors = new List <Vector>(); foreach (TraversableNode node in boarderMap) { VoronoiVectors.Add(new Vector(node.getCoordinate().x, node.getCoordinate().y)); } VoronoiGraph nonPrunedGraph = Fortune.ComputeVoronoiGraph(VoronoiVectors); List <VoronoiEdge> toPrune = new List <VoronoiEdge>(); VoronoiGraph voronoiGraph = nonPrunedGraph; foreach (VoronoiEdge edge in voronoiGraph.Edges) { VEdgeList.Add(new VEdge( new Vector3((float)edge.VVertexA[0] * gridXSpacing + gridXSpacing / 2, 0, (float)edge.VVertexA[1] * gridYSpacing + gridYSpacing / 2), new Vector3((float)edge.VVertexB[0] * gridXSpacing + gridXSpacing / 2, 0, (float)edge.VVertexB[1] * gridYSpacing + gridYSpacing / 2))); } }
public VoronoiCell[] GenerateTileCells(int internalCellsCount) { var mapWidth = TilesSize.x; var mapHeight = TilesSize.y; var cells = new Dictionary <FortuneVoronoi.Common.Point, VoronoiCell>(); var dx = mapWidth / HorBorderSitesCnt / Resolution; var dy = mapHeight / VertBorderSitesCnt / Resolution; var internalSites = SitesGridGenerator.GenerateInternalSites(HorBorderSitesCnt, VertBorderSitesCnt, Resolution, internalCellsCount, (min, max) => new IntPoint(Random.Range(min, max), Random.Range(min, max))); if (!CachedBorders.ContainsKey(TilesSize)) { var borderSites = SitesGridGenerator.GenerateTileBorder(HorBorderSitesCnt, VertBorderSitesCnt, Resolution, (min, max) => new IntPoint(Random.Range(min, max), Random.Range(min, max))); // (int)((min + max) * 0.5f) CachedBorders.Add(TilesSize, borderSites); } foreach (var site in internalSites.Concat(CachedBorders[TilesSize]).Distinct()) { var x = site.X * dx; var y = site.Y * dy; var v = new FortuneVoronoi.Common.Point(x, y); cells.Add(v, new VoronoiCell { IsVisible = !site.IsBorder, Site = v }); } var graph = Fortune.ComputeVoronoiGraph(cells); return(cells.Values.Where(c => c.IsVisible && c.IsClosed).ToArray()); }
public World(string countriesFile, string citiesFolder) { var bordersTemp = new Dictionary <string, string[]>(); var missing = new List <string>(); using (var s = File.OpenText(countriesFile)) { while (!s.EndOfStream) { var l = s.ReadLine(); var sections = l?.Split('\t'); var c = new Country(); if (sections == null) { continue; } c.Name = sections[0]; var stats = sections[1].Split(','); c.Population = int.Parse(stats[0]); c.Density = double.Parse(stats[1]); c.GdpPerCapita = double.Parse(stats[2]); stats = sections[2].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (bordersTemp.ContainsKey(c.Name)) { Console.WriteLine($"Possible Duplicate: {c.Name}."); } else if (stats.Any()) { bordersTemp.Add(c.Name, stats); } c.Ocean = bool.Parse(sections[3]); _countries.Add(c); } } foreach (var country in _countries) { var highwaysTemp = new Dictionary <City, string[]>(); //Load cities if (File.Exists($".\\{citiesFolder}\\{country.Name}.dat")) { using (var s = File.OpenText($".\\{citiesFolder}\\{country.Name}.dat")) { while (!s.EndOfStream) { var str = s.ReadLine()?.Split('\t'); if (country.Cities.Any(o => o.Name == str?[0])) { continue; } var coor = str?[1].Split(',').Select(double.Parse).ToArray() ?? new[] { 0.0, 0.0 }; var c = new City(str?[0], country, coor[0], coor[1]); highwaysTemp.Add(c, str?[2].Split(',')); country.Cities.Add(c); } } foreach (var city in country.Cities) { if (!highwaysTemp.ContainsKey(city)) { continue; } foreach (var s in highwaysTemp[city].Where(s => s != city.Name)) { if (country.Cities.Count(o => o.Name == s) == 0) { Console.WriteLine($"Missing city: '{s}'."); } else { city.BorderCities.Add(country.Cities.First(o => o.Name == s)); } } } } else { Console.WriteLine($"Missing city file {country.Name}.dat"); } _countries.AsParallel().Where(o => o.Cities.Count > 0).SelectMany(o => ConvexHull.Create(o.Cities).Points).ForEach(o => o.IsHull = true); //Load borders if (!bordersTemp.ContainsKey(country.Name)) { continue; } foreach (var s in bordersTemp[country.Name]) { if (_countries.Count(o => o.Name == s) == 0) { if (!missing.Contains(s)) { missing.Add(s); } country.BorderCountries.Add(new Country { Name = s }); } else { country.BorderCountries.AddRange(_countries.Where(o => o.Name == s)); } } } // Outbound foreach (var source in _countries.Where(o => o.Cities.Count != 0 && o.BorderCountries.Count != 0)) { foreach (var source1 in source.BorderCountries.Where(o => o.Cities.Count != 0 && !source.Outbound.ContainsKey(o))) { var graph = Fortune.ComputeVoronoiGraph(source.Cities.Union(source1.Cities).Where(o => o.IsHull).Select(o => new Vector(o.Position) { Tag = o })); var voronoiEdge = graph.Edges.Where(o => ((City)o.LeftData.Tag).Country != ((City)o.RightData.Tag).Country) .MinBy(o => Connection <City> .Distance((City)o.LeftData.Tag, (City)o.RightData.Tag)); var rightCity = (City)voronoiEdge.RightData.Tag; var leftCity = (City)voronoiEdge.LeftData.Tag; source.Outbound[source1] = leftCity.Country != source ? rightCity : leftCity; source1.Outbound[source] = rightCity.Country != source1 ? leftCity : rightCity; } } }
// Create a basic set of public List <TectonicPlate> GeneratePlates() { // Spawn some random cell centers within a grid. // Add one row and column outside of the map so no cells inside the map are border cells. List <TectonicPlate> plates = new List <TectonicPlate>(); for (int left = -PlateSize; left < MapSize.x + PlateSize; left += PlateSize) { for (int bottom = -PlateSize; bottom < MapSize.y + PlateSize; bottom += PlateSize) { int right = left + PlateSize; int top = bottom + PlateSize; plates.Add(new TectonicPlate { Center = new ivec2(rand.Next(left, right), rand.Next(bottom, top)), AngularVelocity = (float)rand.NextDouble() * maxPlateAngluarVelocity, LinearVelocity = new vec2((float)rand.NextDouble() * maxPlateLinearVelocity, (float)rand.NextDouble() * maxPlateLinearVelocity), BaseHeight = (float)rand.NextDouble() + 1f }); } } // Compute voronoi triangulation for plate edges var plateVectors = new Dictionary <Vector, TectonicPlate>(); foreach (var tectonicPlate in plates) { var center = new Vector(tectonicPlate.Center.x, tectonicPlate.Center.y); plateVectors[center] = tectonicPlate; } VoronoiGraph graph = Fortune.ComputeVoronoiGraph(plateVectors.Keys); foreach (var edge in graph.Edges) { ivec2 a = new ivec2((int)edge.VVertexA[0], (int)edge.VVertexA[1]); ivec2 b = new ivec2((int)edge.VVertexB[0], (int)edge.VVertexB[1]); // Ignore edges into infinity. We generate cells outside of the map so we have only finite edges in the mep if (a.x == Int32.MaxValue || a.x == Int32.MinValue || a.y == Int32.MaxValue || a.y == Int32.MinValue || b.x == Int32.MaxValue || b.x == Int32.MinValue || b.y == Int32.MaxValue || b.y == Int32.MinValue) { continue; } a.x = Math.Min(Math.Max(-200, a.x), MapSize.x + 200); a.y = Math.Min(Math.Max(-200, a.y), MapSize.y + 200); b.x = Math.Min(Math.Max(-200, b.x), MapSize.x + 200); b.y = Math.Min(Math.Max(-200, b.y), MapSize.y + 200); // left and right cells of the edges given by the fortune voronoi implementation are incorrect, compute the correct cells again ivec2 middle = (a + b) / 2; // Find the two plate centers closest to the edge middle point List <TectonicPlate> neighborCells = new List <TectonicPlate>(); neighborCells.AddRange(plates.OrderBy(p => (p.Center - middle).Length).Take(2)); TectonicPlate left = neighborCells[0]; TectonicPlate right = neighborCells[1]; // left/right correct? if (EdgeAngle(neighborCells[0].Center, a, b) > 0) { right = neighborCells[0]; left = neighborCells[1]; } float mountainFactor = rand.NextFloat(-1f, 1f); var tectonicEdge = new TectonicEdge { A = a, B = b, LeftPlate = left, RightPlate = right, MountainFactor = mountainFactor }; left.Edges.Add(tectonicEdge); right.Edges.Add(tectonicEdge); } SavePlateImage(plates, "plates.svg"); return(plates); }
private void Canvas1_OnMouseDown(object sender, MouseButtonEventArgs e) { var rand = new Random(); var result = new List <int>(); var check = new HashSet <int>(); for (int i = 0; i < 2000; i++) { Int32 curValue = rand.Next(0, 4000); while (check.Contains(curValue)) { curValue = rand.Next(0, 4000); } result.Add(curValue); check.Add(curValue); } //generate points inside our rectangle for our voronoi generator var datapointlist = new List <Vector>(); for (int i = 0; i < 1000; i++) { datapointlist.Add(new Vector(result[i], result[i + 1000])); } IEnumerable <Vector> datapoints = datapointlist; var vgraph = new VoronoiGraph(); vgraph = Fortune.ComputeVoronoiGraph(datapoints); foreach (var vertex in vgraph.Vertizes) { } var R = 0; var G = 0; var B = 0; foreach (var edge in vgraph.Edges) { if (R < 255) { R++; } if (R == 255 && G < 255) { G++; } if (R == 255 && G == 255 && B < 255) { B++; } var brush = new SolidColorBrush(Color.FromArgb(255, (byte)R, (byte)G, (byte)B)); var poly = new Line() { X1 = edge.LeftData[0], Y1 = edge.LeftData[1], X2 = edge.RightData[0], Y2 = edge.RightData[1], Stroke = brush, StrokeThickness = 1 }; canvas1.Children.Add(poly); canvas1.InvalidateVisual(); canvas1.UpdateLayout(); } }
/// <summary> /// Get the position with the largest view cone on a specific target and with respect to an input radius /// </summary> public static void GetOptimalPosition(float[] target, float radius) { List <float[]> neighbor_coords = new List <float[]>(); ArrayList neighbor_theta_phi = new ArrayList(); ArrayList neighbor_correspondance = new ArrayList(); float min_theta = 1000.0f; float max_theta = 0.0f; float min_phi = 1000.0f; float max_phi = 0.0f; // Get all the atoms inside the sphere centered on the target and of the input radius, translate them into polar coordinates for (int i = 0; i < MoleculeModel.atomsLocationlist.Count; i++) { double dist = Distance3f(MoleculeModel.atomsLocationlist[i], target); if (dist < radius) { neighbor_coords.Add(MoleculeModel.atomsLocationlist[i]); float[] atom = new float[3]; atom[0] = MoleculeModel.atomsLocationlist[i][0] - target[0]; atom[1] = MoleculeModel.atomsLocationlist[i][1] - target[1]; atom[2] = MoleculeModel.atomsLocationlist[i][2] - target[2]; float theta = (float)Math.Acos(atom[2] / dist); float phi = (float)Math.Atan2(atom[1], atom[0]); Vector theta_phi = new Vector(2); theta_phi[0] = theta; theta_phi[1] = phi; neighbor_theta_phi.Add(theta_phi); neighbor_correspondance.Add(i); // Debug.Log (theta_phi); theta_phi = new Vector(2); theta_phi[0] = theta + (float)Math.PI / 2; theta_phi[1] = phi + (float)Math.PI; neighbor_theta_phi.Add(theta_phi); // Debug.Log (theta_phi); theta_phi = new Vector(2); theta_phi[0] = theta + (float)Math.PI / 2; theta_phi[1] = phi; neighbor_theta_phi.Add(theta_phi); // Debug.Log (theta_phi); theta_phi = new Vector(2); theta_phi[0] = theta; theta_phi[1] = phi + (float)Math.PI; neighbor_theta_phi.Add(theta_phi); // Debug.Log (theta_phi); if (theta + (float)Math.PI / 2 > max_theta) { max_theta = theta + (float)Math.PI / 2; } if (theta < min_theta) { min_theta = theta; } if (phi + (float)Math.PI > max_phi) { max_phi = phi + (float)Math.PI; } if (phi < min_phi) { min_phi = phi; } } } // Debug.Log (neighbor_theta_phi.GetEnumerator().Current[0]+" "+neighbor_theta_phi.GetEnumerator().Current[1]); // Debug.Log (neighbor_theta_phi[1][0]+" "+neighbor_theta_phi[1][1]); // Debug.Log (neighbor_theta_phi[2][0]+" "+neighbor_theta_phi[2][1]); // Debug.Log (neighbor_theta_phi[3][0]+" "+neighbor_theta_phi[3][1]); StreamWriter sw = new StreamWriter(@"/Users/trellet/Dev/UnityMol_svn/trunk/Assets/neighbors.txt"); foreach (Vector neighbor in neighbor_theta_phi) { sw.WriteLine("" + neighbor[0] + " " + neighbor[1]); } sw.Close(); // int length = neighbor_theta_phi.Count; // for(int i=0; i<length; i++) // { // Vector theta_phi = new Vector(2); // theta_phi[0] = neighbor_theta_phi[i][0]+ (float) Math.PI; // theta_phi[1] = neighbor_theta_phi[i][1]+2*(float) Math.PI; // neighbor_theta_phi.Add (theta_phi); // theta_phi[0] = neighbor_theta_phi[i][0]+(float) Math.PI; // theta_phi[1] = neighbor_theta_phi[i][1]; // neighbor_theta_phi.Add (theta_phi); // theta_phi[0] = neighbor_theta_phi[i][0]; // theta_phi[1] = neighbor_theta_phi[i][1]+2*(float) Math.PI; // neighbor_theta_phi.Add (theta_phi); // } Debug.Log("Nb of neighbors: " + neighbor_theta_phi.Count); Debug.Log("Min/max theta/phi: " + min_theta + " " + max_theta + " " + min_phi + " " + max_phi); // Compute the Voronoi graph from the neighbors polar coordinates VoronoiGraph result = Fortune.ComputeVoronoiGraph(neighbor_theta_phi); MoleculeModel.atomsLocationlist.OrderBy(x => x[0]); Debug.Log(result.Vertizes.Count); StreamWriter sw2 = new StreamWriter(@"/Users/trellet/Dev/UnityMol_svn/trunk/Assets/vertices.txt"); BenTools.Data.HashSet temp = new BenTools.Data.HashSet(); foreach (Vector vert in result.Vertizes) { if (vert[0] > min_theta && vert[0] < max_theta && vert[1] < max_phi && vert[1] > min_phi) { sw2.WriteLine("" + vert[0] + " " + vert[1]); temp.Add(vert); } } sw2.Close(); result.Vertizes = temp; //double min_dist = 1000.0; double max_dist = 0.0; float[] best_pos = new float[2]; //float[] best_point = new float[2]; //float[] vertex = new float[2]; //float[] point = new float[2]; // Vector vert = new Vector(); //int c = 0; double distance = 0.0; Dictionary <double, float[]> vertices = new Dictionary <double, float[]>(); // Find the largest distance between each vertex and the closest point to each of them //// 1st METHOD (faster, use the edges that contain point information) foreach (VoronoiEdge edge in result.Edges) { //min_dist = 1000.0; if (edge.VVertexA[0] > min_theta && edge.VVertexA[0] < max_theta && edge.VVertexA[1] < max_phi && edge.VVertexA[1] > min_phi) { distance = Distance2f(edge.VVertexA, edge.LeftData); float[] t = new float[2]; t[0] = (float)edge.VVertexA[0]; t[1] = (float)edge.VVertexA[1]; vertices[distance] = t; if (distance > max_dist) { max_dist = distance; best_pos[0] = (float)edge.VVertexA[0]; best_pos[1] = (float)edge.VVertexA[1]; } } if (edge.VVertexB[0] > min_theta && edge.VVertexB[0] < max_theta && edge.VVertexB[1] < max_phi && edge.VVertexB[1] > min_phi) { distance = Distance2f(edge.VVertexB, edge.LeftData); float[] t = new float[2]; t[0] = (float)edge.VVertexA[0]; t[1] = (float)edge.VVertexA[1]; vertices[distance] = t; if (distance > max_dist) { max_dist = distance; best_pos[0] = (float)edge.VVertexB[0]; best_pos[1] = (float)edge.VVertexB[1]; } } } var list = vertices.Keys.ToList(); list.Sort(); float[] cartesian = new float[3]; for (int i = list.Count - 1; i > list.Count - 8; i--) { //Debug.Log(list[i]+": "+vertices[list[i]][0]+" "+vertices[list[i]][1]); cartesian[0] = (radius * (float)Math.Sin(vertices[list[i]][0]) * (float)Math.Cos(vertices[list[i]][1])) + target[0]; cartesian[1] = (radius * (float)Math.Sin(vertices[list[i]][0]) * (float)Math.Sin(vertices[list[i]][1])) + target[1]; cartesian[2] = (radius * (float)Math.Cos(vertices[list[i]][0])) + target[2]; Debug.Log(list[i] + ": " + cartesian[0] + " " + cartesian[1] + " " + cartesian[2]); } ////// 2nd METHOD (slower, all vertices vs all points) // foreach (Vector vert in result.Vertizes) // { // min_dist = 1000.0; // // foreach (Vector neighbor in neighbor_theta_phi) // { //// vertices[0] = (float) vert[0]; //// vertices[1] = (float) vert[1]; // // double dist = Distance2f(vert, neighbor); // // if (dist < min_dist) // { // min_dist = dist; // point[0] = (float) neighbor[0]; // point[1] = (float) neighbor[1]; // } // } // if (min_dist > max_dist) // { // max_dist = min_dist; // best_pos[0] = (float) vert[0]; // best_pos[1] = (float) vert[1]; // best_point[0] = point[0]; // best_point[1] = point[1]; // } // // } Debug.Log("Maximum distance: " + max_dist); Debug.Log("Theta and phi: " + best_pos[0] + " " + best_pos[1]); float[] best_pos_cart = new float[3]; //float[] best_pos_cart2 = new float[3]; //float[] best_pos_cart3 = new float[3]; //float[] best_pos_cart4 = new float[3]; // Convert polar coordinates of the best position to cartesian ones + shift to molecule system coordinates best_pos_cart[0] = (radius * (float)Math.Sin(best_pos[0]) * (float)Math.Cos(best_pos[1])) + target[0]; best_pos_cart[1] = (radius * (float)Math.Sin(best_pos[0]) * (float)Math.Sin(best_pos[1])) + target[1]; best_pos_cart[2] = (radius * (float)Math.Cos(best_pos[0])) + target[2]; Debug.Log("Best position: " + best_pos_cart[0] + " " + best_pos_cart[1] + " " + best_pos_cart[2]); // best_pos_cart2[0] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Cos(best_pos[1])) + target[0]; // best_pos_cart2[1] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Sin(best_pos[1])) + target[1]; // best_pos_cart2[2] = (radius * (float) Math.Cos(best_pos[0]-Math.PI)) + target[2]; // best_pos_cart3[0] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Cos(best_pos[1]-2*Math.PI)) + target[0]; // best_pos_cart3[1] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Sin(best_pos[1]-2*Math.PI)) + target[1]; // best_pos_cart3[2] = (radius * (float) Math.Cos(best_pos[0]-Math.PI)) + target[2]; // best_pos_cart4[0] = (radius * (float) Math.Sin(best_pos[0]) * (float) Math.Cos(best_pos[1]-2*Math.PI)) + target[0]; // best_pos_cart4[1] = (radius * (float) Math.Sin(best_pos[0]) * (float) Math.Sin(best_pos[1]-2*Math.PI)) + target[1]; // best_pos_cart4[2] = (radius * (float) Math.Cos(best_pos[0])) + target[2]; // Debug.Log("Best position2: "+best_pos_cart2[0]+" "+best_pos_cart2[1]+" "+best_pos_cart2[2]); // Debug.Log("Best position3: "+best_pos_cart3[0]+" "+best_pos_cart3[1]+" "+best_pos_cart3[2]); // Debug.Log("Best position4: "+best_pos_cart4[0]+" "+best_pos_cart4[1]+" "+best_pos_cart4[2]); // Place the camera at the new best position and make it face the target UIData.optim_view = true; maxCamera.optim_target = new Vector3(target[0], target[1], target[2]); maxCamera.optim_cam_position = new Vector3(best_pos_cart[0], best_pos_cart[1], best_pos_cart[2]); GameObject camera = GameObject.Find("LoadBox"); UIData.optim_view_start_point = camera.transform.position; UIData.start_time = Time.time; //camera.transform.position = new Vector3(best_pos_cart[0], best_pos_cart[1], best_pos_cart[2]); // Wait(); // camera.transform.position = new Vector3(best_pos_cart2[0], best_pos_cart2[1], best_pos_cart2[2]); // Wait(); // camera.transform.position = new Vector3(best_pos_cart3[0], best_pos_cart3[1], best_pos_cart3[2]); // Wait(); // camera.transform.position = new Vector3(best_pos_cart4[0], best_pos_cart4[1], best_pos_cart4[2]); //maxCamera.ghost_target = GameObject.Find("Target"); // camera.transform.LookAt(ghost_target.transform); //result.Vertizes }
public void Reset() { GL.Enable(EnableCap.LineSmooth); GL.Enable(EnableCap.PolygonSmooth); // GL.Enable(EnableCap.DepthTest); Matrix4 modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref modelview); int seeds = 1280; int extraSeeds = 512; Vector[] points = new Vector[seeds + extraSeeds]; double thetaOffset = Tau / 4; for (int i = 0; i < seeds + extraSeeds; i++) { double theta = (double)(i + 1) * Tau / Phi; double r = Math.Sqrt(i + 1); double x = (r) * Math.Cos(theta + thetaOffset); double y = (r) * Math.Sin(theta + thetaOffset); points[i] = new Vector(new double[] { x, y }); } VoronoiGraph graph = Fortune.ComputeVoronoiGraph(points); cells = new SortedDictionary <Vector, List <VoronoiEdge> >(); foreach (VoronoiEdge edge in graph.Edges) { if (double.IsNaN(edge.VVertexA.X) || double.IsNaN(edge.VVertexA.Y) || double.IsNaN(edge.VVertexB.X) || double.IsNaN(edge.VVertexB.Y) ) { continue; } if (!cells.ContainsKey(edge.LeftData)) { cells[edge.LeftData] = new List <VoronoiEdge>(); } cells[edge.LeftData].Add(edge); if (!cells.ContainsKey(edge.RightData)) { cells[edge.RightData] = new List <VoronoiEdge>(); } cells[edge.RightData].Add(edge); Complex pA = new Complex(edge.VVertexA.X, edge.VVertexA.Y); Complex pB = new Complex(edge.VVertexB.X, edge.VVertexB.Y); int sampleCount = 2; Complex[] samples = new Complex[sampleCount]; samples[0] = pA; samples[sampleCount - 1] = pB; for (int i = 1; i < sampleCount - 1; i++) { double ratio = (double)i / sampleCount; samples[i] = pA * (1 - ratio) + pB * ratio; } } for (int i = 0; i < seeds; i++) { Queue <VoronoiEdge> edges = new Queue <VoronoiEdge>(cells.Values.ElementAt(i)); var firstEdge = edges.Dequeue(); List <Complex> polygonPoints = new List <Complex>(); polygonPoints.Add(new Complex(firstEdge.VVertexA.X * scale, firstEdge.VVertexA.Y * scale)); polygonPoints.Add(new Complex(firstEdge.VVertexB.X * scale, firstEdge.VVertexB.Y * scale)); while (edges.Count > 0) { var edge = edges.Dequeue(); Complex pA = new Complex(edge.VVertexA.X * scale, edge.VVertexA.Y * scale); Complex pB = new Complex(edge.VVertexB.X * scale, edge.VVertexB.Y * scale); if (polygonPoints[0] == pA) { polygonPoints.Insert(0, pB); continue; } if (polygonPoints[0] == pB) { polygonPoints.Insert(0, pA); continue; } if (polygonPoints[polygonPoints.Count - 1] == pA) { polygonPoints.Add(pB); continue; } if (polygonPoints[polygonPoints.Count - 1] == pB) { polygonPoints.Add(pA); continue; } edges.Enqueue(edge); } polygons.Add(polygonPoints); } for (int i = 0; i <= ModuloActor.MaxMod; i++) { ModuloActor.Maps[i] = CreateIndexMap(i, cells); } actors[0] = new ModuloActor(21, 0 / 3, new Color4(1f, 0.5f, 0.5f, 1f)); actors[1] = new ModuloActor(13, 1 / 3, new Color4(0.5f, 1f, 0.5f, 1f)); actors[2] = new ModuloActor(0, 2 / 3, new Color4(0.5f, 0.5f, 1f, 1f)); ModuloActor.AnnounceFibonaccis(); }
public static VoronoiGraph Voronoi(List <Vector> vectors) { return(Fortune.ComputeVoronoiGraph(vectors)); }
/// <summary> /// Starts plan generation process /// </summary> public void Generate() { var datapoints = new List <Vector>(Parameters.PolygonsCount); var r = new Random(Parameters.GridSeed); for (int i = 0; i < Parameters.PolygonsCount; i++) { datapoints.Add(new Vector(r.Next(0, Parameters.MapSize.X), r.Next(0, Parameters.MapSize.Y))); } var graph = Fortune.ComputeVoronoiGraph(datapoints); for (int i = 0; i < Parameters.RelaxCount; i++) { Relax(graph, datapoints); graph = Fortune.ComputeVoronoiGraph(datapoints); } FillMap(graph); { // adding elevation data var elevationNoise = new SimplexNoise(new Random(Parameters.ElevationSeed)); elevationNoise.SetParameters(0.0008, SimplexNoise.InflectionMode.NoInflections, SimplexNoise.ResultScale.ZeroToOne); foreach (var poly in this) { var noiseVal = elevationNoise.GetNoise2DValue(poly.Center.X, poly.Center.Y, 4, 0.8); var col = 255 / noiseVal.MaxValue * noiseVal.Value; poly.Elevation = (int)col; } //// elevate each corner //if (!Parameters.CenterElevation) // ElevateCorners(); } if (Parameters.CenterElevation) { var poly = GetAtPoint(new Point(Parameters.MapSize.X / 2, Parameters.MapSize.Y / 2)); poly.Elevation = 200; StartPropagation(poly, 15); } // making island { //r = new Random((int)voronoiSeedNumeric.Value); var borderElevation = 80; var step = 20; for (int x = 0; x < Parameters.MapSize.X; x += 5) { var poly = GetAtPoint(new Point(x, 0)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); poly = GetAtPoint(new Point(x, Parameters.MapSize.Y)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); } for (int y = 0; y < Parameters.MapSize.Y; y += 5) { var poly = GetAtPoint(new Point(0, y)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); poly = GetAtPoint(new Point(Parameters.MapSize.X, y)); poly.Elevation = borderElevation;// r.Next(0, 100); StartPropagation(poly, step); } } ElevateCorners(); #region Moisturizing { var noise = new SimplexNoise(new Random(Parameters.ElevationSeed)); noise.SetParameters(0.0008d, SimplexNoise.InflectionMode.NoInflections, SimplexNoise.ResultScale.ZeroToOne); foreach (var poly in this) { var noiseVal = noise.GetNoise2DValue(poly.Center.X, poly.Center.Y, 2, 0.8); var col = 100 / noiseVal.MaxValue * noiseVal.Value; poly.Moisture = (int)col; foreach (var corner in poly.Corners) { noiseVal = noise.GetNoise2DValue(corner.Point.X, corner.Point.Y, 2, 0.8); col = 2 / noiseVal.MaxValue * noiseVal.Value; corner.WaterFlow = (int)col; } } // fix heights foreach (var poly in this) { foreach (var neighbor in poly.Neighbors) { if (poly.Elevation == neighbor.Elevation) { neighbor.Elevation = (int)neighbor.Neighbors.Average(n => n.Elevation); } } } // calculate rivers _corners1 = new HashSet <Corner>(); // get unique corners foreach (var poly in this) { foreach (var corner in poly.Corners) { if (!_corners1.Contains(corner) && corner.Polygons.Find(p => p.Elevation <= 127) == null) { _corners1.Add(corner); } } } var list = new List <Corner>(_corners1); list.Sort(new CornerHeightComparer()); // propagate flow foreach (var corner in list) { // find lowest edge Edge lowestEdge = corner.Edges[0]; int height = lowestEdge.GetOpposite(corner).Elevation; for (int i = 0; i < corner.Edges.Count; i++) { var tmp = corner.Edges[i].GetOpposite(corner).Elevation; if (tmp < height) { height = tmp; lowestEdge = corner.Edges[i]; } } lowestEdge.WaterFlow += corner.WaterFlow; lowestEdge.GetOpposite(corner).WaterFlow += corner.WaterFlow; } // remove rivers that not going to oceans _waterCorners = new List <Corner>(); foreach (var poly in this) { foreach (var corner in poly.Corners) { int solid = corner.Polygons.Count(p => p.Elevation > 127); if (solid == 2) { _waterCorners.Add(corner); } } } // collect all correct edges _rivers.Clear(); foreach (var waterCorner in _waterCorners) { var root = new RiverBranch(); CollectRiver(waterCorner, root); if (!root.Final) { _riverRoots.Add(root); } } // fix river flows // stage 1: remove all flows foreach (var riverBranch in _riverRoots) { EnumerateTree(riverBranch, b => { if (b.Edge != null) { b.Edge.WaterFlow = 0; } }); } // stage 2: reflow it foreach (var riverBranch in _riverRoots) { FillRiver(riverBranch); } // remove all non-river foreach (var poly in this) { foreach (var edge in poly.Edges) { if (edge.WaterFlow > 0 && !_rivers.Contains(edge)) { edge.WaterFlow = 0; } } } // update moisture for polygons foreach (var poly in this) { if (poly.Elevation > 127) { poly.Moisture = poly.Neighbors.Sum(p => { var v = p.Neighbors.Sum(n => n.Edges.Sum(ed => ed.WaterFlow > 0 ? 1 : 0)); v = v + p.Neighbors.Sum(n => n.Elevation < 127 && !n.Ocean ? 3 : 0); return(p.Edges.Sum(ed => ed.WaterFlow > 0 ? 1 : 0) + v); }); } } } #endregion // detect ocean { SetOcean(GetAtPoint(new Point(0, 0))); SetOcean(GetAtPoint(new Point(Parameters.MapSize.X, 0))); SetOcean(GetAtPoint(new Point(0, Parameters.MapSize.Y))); SetOcean(GetAtPoint(new Point(Parameters.MapSize.X, Parameters.MapSize.Y))); } // set biomes { foreach (var poly in this) { if (poly.Elevation > 127) { poly.Biome = _biome.GetBiomeWith(poly.Elevation, poly.Moisture > _biome.Moisture.Maximum ? _biome.Moisture.Maximum : poly.Moisture); } } } //find coastline foreach (var polygon in this) { foreach (var edge in polygon.Edges) { Polygon poly; Polygon poly2; if (((poly = edge.Polygons.Find(p => p.Elevation > 127)) != null) && ((poly2 = edge.Polygons.Find((p => p.Elevation <= 127))) != null)) { poly.Coast = true; poly2.Coast = true; edge.Coast = true; } } } }
protected override int[] GenerateDataImpl(long x, long y, long width, long height) { int[] data = new int[width * height]; // Determine output values. int noneOutput = 0; int originalOutput = 1; int centerOutput = (this.Result == VoronoiResult.AllValues) ? 2 : 1; int edgeOutput = (this.Result == VoronoiResult.AllValues) ? 3 : (this.Result == VoronoiResult.EdgesAndOriginals) ? 2 : 1; // Scan through the size of the array, randomly creating points. List <Vector> points = new List <Vector>(); for (int i = -this.EdgeSampling; i < width + this.EdgeSampling; i++) { for (int j = -this.EdgeSampling; j < height + this.EdgeSampling; j++) { int s = this.GetRandomRange(x + i, y + j, 0, this.PointValue, this.Modifier); //long s = this.GetRandomLong(x + i, y + j) % this.PointValue; //if (s < 0) s = Math.Abs(s); //if (s < 0 || s >= this.PointValue) // throw new InvalidOperationException(); if (s == 0) { points.Add(new Vector(new double[] { i, j })); if (i >= 0 && i < width && j >= 0 && j < height) { if (this.Result == VoronoiResult.AllValues || this.Result == VoronoiResult.EdgesAndOriginals || this.Result == VoronoiResult.OriginalOnly) { data[i + j * width] = originalOutput; } } } } } // Skip computations if we are only outputting original scatter values. if (this.Result == VoronoiResult.OriginalOnly) { return(data); } // Compute the Voronoi diagram. VoronoiGraph graph = Fortune.ComputeVoronoiGraph(points); // Output the edges if needed. if (this.Result == VoronoiResult.AllValues || this.Result == VoronoiResult.EdgesAndOriginals || this.Result == VoronoiResult.EdgeOnly) { foreach (VoronoiEdge v in graph.Edges) { Vector a = v.VVertexA; Vector b = v.VVertexB; // Normalize vector between two points. double cx = 0, cy = 0; double sx = b[0] < a[0] ? b[0] : a[0]; double sy = b[0] < a[0] ? b[1] : a[1]; double mx = b[0] > a[0] ? b[0] : a[0]; double tx = b[0] > a[0] ? b[0] - a[0] : a[0] - b[0]; double ty = b[0] > a[0] ? b[1] - a[1] : a[1] - b[1]; double length = Math.Sqrt(Math.Pow(tx, 2) + Math.Pow(ty, 2)); tx /= length; ty /= length; // Iterate until we reach the target. while (sx + cx < mx)// && sy + cy < my) { if ((int)(sx + cx) >= 0 && (int)(sx + cx) < width && (int)(sy + cy) >= 0 && (int)(sy + cy) < height && data[(int)(sx + cx) + (int)(sy + cy) * width] == noneOutput) { data[(int)(sx + cx) + (int)(sy + cy) * width] = edgeOutput; } cx += tx; // b[0] > a[0] ? tx : -tx; cy += ty; // b[1] > a[1] ? ty : -ty; } } } // Output the center points if needed. if (this.Result == VoronoiResult.AllValues || this.Result == VoronoiResult.CenterOnly) { foreach (Vector v in graph.Vertizes) { if ((int)v[0] >= 0 && (int)v[0] < width && (int)v[1] >= 0 && (int)v[1] < height) { data[(int)v[0] + (int)v[1] * width] = centerOutput; } } } // Return the result. return(data); }
/// <summary> /// The Voronoi Graph calculation creates the lines that form a voronoi diagram. /// </summary> /// <param name="points">The points to use for creating the tesselation.</param> /// <param name="result">The output featureset.</param> /// <param name="cropToExtent">The normal polygons have sharp angles that extend like stars. /// Cropping will ensure that the original featureset extent plus a small extra buffer amount /// is the outer extent of the polygons. Errors seem to occur if the exact extent is used.</param> public static void VoronoiPolygons(IFeatureSet points, IFeatureSet result, bool cropToExtent) { double[] vertices = points.Vertex; VoronoiGraph gp = Fortune.ComputeVoronoiGraph(vertices); Extent ext = points.Extent; ext.ExpandBy(ext.Width / 100, ext.Height / 100); IEnvelope env = ext.ToEnvelope(); IPolygon bounds = env.ToPolygon(); // Convert undefined coordinates to a defined coordinate. HandleBoundaries(gp, env); for (int i = 0; i < vertices.Length / 2; i++) { List <VoronoiEdge> myEdges = new List <VoronoiEdge>(); Vector2 v = new Vector2(vertices, i * 2); foreach (VoronoiEdge edge in gp.Edges) { if (!v.Equals(edge.RightData) && !v.Equals(edge.LeftData)) { continue; } myEdges.Add(edge); } List <Coordinate> coords = new List <Coordinate>(); VoronoiEdge firstEdge = myEdges[0]; coords.Add(firstEdge.VVertexA.ToCoordinate()); coords.Add(firstEdge.VVertexB.ToCoordinate()); Vector2 previous = firstEdge.VVertexB; myEdges.Remove(myEdges[0]); Vector2 start = firstEdge.VVertexA; while (myEdges.Count > 0) { for (int j = 0; j < myEdges.Count; j++) { VoronoiEdge edge = myEdges[j]; if (edge.VVertexA.Equals(previous)) { previous = edge.VVertexB; Coordinate c = previous.ToCoordinate(); coords.Add(c); myEdges.Remove(edge); break; } // couldn't match by adding to the end, so try adding to the beginning if (edge.VVertexB.Equals(start)) { start = edge.VVertexA; coords.Insert(0, start.ToCoordinate()); myEdges.Remove(edge); break; } // I don't like the reverse situation, but it seems necessary. if (edge.VVertexB.Equals(previous)) { previous = edge.VVertexA; Coordinate c = previous.ToCoordinate(); coords.Add(c); myEdges.Remove(edge); break; } if (edge.VVertexA.Equals(start)) { start = edge.VVertexB; coords.Insert(0, start.ToCoordinate()); myEdges.Remove(edge); break; } } } for (int j = 0; j < coords.Count; j++) { Coordinate cA = coords[j]; // Remove NAN values if (double.IsNaN(cA.X) || double.IsNaN(cA.Y)) { coords.Remove(cA); } // Remove duplicate coordinates for (int k = j + 1; k < coords.Count; k++) { Coordinate cB = coords[k]; if (cA.Equals2D(cB)) { coords.Remove(cB); } } } foreach (Coordinate coord in coords) { if (double.IsNaN(coord.X) || double.IsNaN(coord.Y)) { coords.Remove(coord); } } if (coords.Count <= 2) { continue; } Polygon pg = new Polygon(coords); if (cropToExtent) { try { IGeometry g = pg.Intersection(bounds); IPolygon p = g as IPolygon; if (p != null) { Feature f = new Feature(p, result); f.CopyAttributes(points.Features[i]); } } catch (Exception) { Feature f = new Feature(pg, result); f.CopyAttributes(points.Features[i]); } } else { Feature f = new Feature(pg, result); f.CopyAttributes(points.Features[i]); } } return; }
public static Image CreateImage(VoronoiDiagramContext context, params IEnumerable <Point>[] inputs) { IEnumerable <IEnumerable <Vector> > dataPoints = inputs.Select( input => input.Select( point => new Vector(point.XCoordinate, point.YCoordinate) ) ); double factorX = context.Width / (context.MaxX - context.MinX); double factorY = context.Height / (context.MaxY - context.MinY); double factor = Math.Min(factorX, factorY); double minX = context.MinX - context.Width * (0.5 / factor - 0.5 / factorX); double minY = context.MinY - context.Height * (0.5 / factor - 0.5 / factorY); dataPoints = dataPoints.Select(points => points.Select(vector => new Vector( (vector[0] - minX) * factor, (vector[1] - minY) * factor ))); PointF toPoint(Vector vector) => new PointF( (float)vector[0], (float)vector[1] ); RectangleF toRectangle(Vector vector, float radius) => new RectangleF( (float)(vector[0]) - radius, (float)(vector[1]) - radius, radius * 2f, radius * 2f ); var image = new Bitmap(context.Width, context.Height); var linePen = new Pen(context.LineColor); var dataPointBrushes = context.DataPointsColors.Select(color => new SolidBrush(color)); var surface = Graphics.FromImage(image); surface.Clear(context.BackgroundColor); surface.SmoothingMode = SmoothingMode.HighQuality; try { VoronoiGraph graph = Fortune.ComputeVoronoiGraph(dataPoints.First().Distinct()); double infiniteLength = context.Width + context.Height; foreach (var edge in graph.Edges) { Vector left = edge.VVertexA; Vector right = edge.VVertexB; if (edge.IsPartlyInfinite) { Vector extension = edge.DirectionVector * infiniteLength; if (left == Fortune.VVInfinite) { left = edge.FixedPoint - extension; } if (right == Fortune.VVInfinite) { right = edge.FixedPoint + extension; } } surface.DrawLine(linePen, toPoint(left), toPoint(right)); } } catch (Exception) {} var target = dataPoints.Zip( dataPointBrushes.Zip( context.DataPointsRadii, (brush, radius) => new { brush, radius }), (points, style) => new { points, style } ).Reverse(); foreach (var data in target) { foreach (var point in data.points) { surface.FillEllipse(data.style.brush, toRectangle(point, data.style.radius)); } } return(image); }
private void ComputeVoronoi() { _graph = Fortune.ComputeVoronoiGraph(_pointList); }
private SRandom _rndGen; //random generator //class constractor public Island(int width, int height, int relaxTime, int centerNum, int riverNum, float maxElevation, float mainStreamLengthRatio, //typical: 0.02 float subStreamLengthRatio, //typical: 0.5 float riverSplitFreq, //typical: 0.2 int seed = 0) { this.width = width; this.height = height; this.relaxationTime = relaxTime; this.num_of_centers = centerNum; this.num_of_rivers = riverNum; this._maxElevation = maxElevation; if (mainStreamLengthRatio < 0f || mainStreamLengthRatio > 0.2f) { throw new ArgumentOutOfRangeException("ratio must be between 0 and 0.2"); } _mainStreamLength = (int)Math.Floor(Math.Max(width, height) * mainStreamLengthRatio); if (subStreamLengthRatio < 0f || subStreamLengthRatio > 1f) { throw new ArgumentOutOfRangeException("ratio must be between 0 and 1"); } _subStreamLength = (int)Math.Floor(_mainStreamLength * subStreamLengthRatio); if (_riverSplitFreq < 0f || _riverSplitFreq > 1f) { throw new ArgumentOutOfRangeException("frequency must be between 0 and 1"); } _riverSplitFreq = riverSplitFreq; _rndGen = new SRandom(seed); centers = random_centers(width, height, num_of_centers); VoronoiGraph vg = Fortune.ComputeVoronoiGraph(centers); //run voronoi diagram algorithm for (int i = 0; i < centers.Count; i++) //Initialize and store IslandTiles { Tiles[centers[i]] = new IslandTile(centers[i], vg, width, height); } //call improveRandomPoints function "relaxation" times for (int re = 0; re < relaxationTime; re++) { centers = improveRandomPoints(Tiles, centers); VoronoiGraph vGraph = Fortune.ComputeVoronoiGraph(centers); Tiles = new Dictionary <Vector, IslandTile>(); for (int j = 0; j < centers.Count; j++) { Tiles[centers[j]] = new IslandTile(centers[j], vGraph, width, height); } } NN = new NearestNeighbor(centers);//builded kdtree foreach (var item in Tiles.Values) { if (item.center.data[0] < (width / 10) || item.center.data[0] > (width - width / 10) || item.center.data[1] < (width / 10) || item.center.data[1] > (width - width / 10)) { item.iswater = true; item.elevation = 0; foreach (var c in item.corners) { c.elevation = 0; // totalcorners[c.position] = c; //water.Add(c); } ocean.Add(item); } else { land.Add(item); } } //spreading ocean area int waterspreadcount = 0; foreach (var item in Tiles.Values) { if (!item.iswater) { foreach (var i in item.neighbors) { if (Tiles[i].iswater) { item.iswater = true; item.elevation = 0; foreach (var c in item.corners) { c.elevation = 0; //totalcorners[c.position] = c; //water.Add(c); } ocean.Add(item); land.Remove(item); waterspreadcount++; } if (waterspreadcount > (num_of_centers / 3)) { break; } } } if (waterspreadcount > (num_of_centers / 3)) { break; } } //remove one tile island foreach (var item in Tiles.Values) { float sum_of_elevation = 0; foreach (var c in item.corners) { sum_of_elevation += c.elevation; } if (sum_of_elevation == 0) { item.iswater = true; item.elevation = 0; ocean.Add(item); land.Remove(item); } } //-----calculate coastline------------------------ foreach (var item in land) { foreach (var c in item.corners) { if (c.elevation == 0) { shore.Add(c); item.isshore = true; } } } //calculate elevation for corners foreach (var t in Tiles.Values) { if (!t.iswater) { float sum_elevation = 0; foreach (var c in t.corners) { float minDistToShore = float.MaxValue; foreach (var s in shore) { float distToShore = (float)Math.Sqrt((c.position - s.position).data[0] * (c.position - s.position).data[0] + (c.position - s.position).data[1] * (c.position - s.position).data[1]); if (minDistToShore > distToShore) { minDistToShore = distToShore; } } c.elevation = minDistToShore * minDistToShore / _maxElevation; c.elevation = Math.Min(c.elevation, _maxElevation); sum_elevation += c.elevation; // totalcorners[c.position] = c; } t.elevation = sum_elevation / t.corners.Count; } } //store total corners /*foreach(var item in Tiles.Values) * { * foreach (var c in item.corners) * totalcorners.Add(c); * }*/ //landcenters foreach (var item in land) { landcenters.Add(item.center); } rivers = GenerateRivers();//generate rivers foreach (var ri in rivers) { River.findDischarge(ri);//get discharge for every corner } //put discharge information in it's tile foreach (var kc in River.keeprivercorners) { foreach (var t in kc.touches) { t.hasriver = true; foreach (var c in t.corners) { if (c.position == kc.position) { c.discharge = kc.discharge; } break; } } } StoreBiome();//set biome type for each tile //from now on, all data of a tile are generated. }