private void Delaunay_Click(object sender, EventArgs e) { for (int i = 0; i < Array_of_vertexes.Count(); ++i) Array_of_vertexes[i].Highlighted = false; DrawEvents.Clear(); DrawEvents.Add(new Painting(Array_of_vertexes, new List<Edge>())); List<Vector> Points = new List<Vector>(AlgorithmsVisualiser.Pack_into_ListOfVector(Array_of_vertexes)); VoronoiGraph graph = new VoronoiGraph(); graph = AlgorithmsVisualiser.FortuneAlgo(Points); List<VoronoiEdge> VE = graph.Edges.ToList<VoronoiEdge>(); List<Edge> tri = AlgorithmsVisualiser.Delaunay(Array_of_vertexes, graph, DrawEvents); foreach(Edge edge in tri) edge.color = Color.Red; GL.LineWidth(1); DrawEvents.Add(new Painting(Array_of_vertexes, tri, VE)); }
/// <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()); }
public bool regenerateVoronoi(bool drawmesh) { if (GameControl.gameSession == null || (region = GameControl.gameSession.mapGenerator.getRegion()) == null) { //Debug.Log("Cannot regenerate Voronoi for Water - gameSession is not ready."); return(false); } // prepare noise int noise_seed = (useRandomSeed) ? UnityEngine.Random.Range(int.MinValue, int.MaxValue) : this.seed; Noise noise = new FastPerlinNoise(noiseResolution, noise_seed, noiseAmplitude, noisePersistance); noise.setNoiseValues(NoiseMap.adjustNoise(noise.getNoiseValues(), 5)); // get region parameters this.water_elevation = region.getWaterLevelElevation(); this.size = region.getViewableSize(); int halfSize = this.size / 2; // generate random coordinates for polygons generateXY(out this.X, out this.Y); // use voronoi generator voronoi = new Voronoi(minDist); voronoi.generateVoronoi(X, Y, 0, size, 0, size); VoronoiGraph vG = voronoi.getVoronoiGraph(); foreach (GraphEdge gE in vG.edges) { gE.x1 -= halfSize; gE.x2 -= halfSize; gE.y1 -= halfSize; gE.y2 -= halfSize; } if (drawmesh) { Meshes.WaterMesh.InitializeMesh(region, voronoi.getVoronoiGraph(), mesh, noise, maxWaterLevelDisplacement); } return(true); }
private List <Line> GenerateLines(VoronoiGraph data) { var lines = new List <Line>(); var linePoints = new List <Point>(); foreach (var edge in data.Edges) { if (edge.IsInfinite || edge.IsPartlyInfinite) { continue; } var p1 = new Point(edge.VVertexA[0], edge.VVertexA[1]); var p2 = new Point(edge.VVertexB[0], edge.VVertexB[1]); var line = new Line(p1, p2); lines.Add(line); } return(lines); }
public VoronoiGraph RefineGraph(VoronoiGraph g) { // Removes out of bound edges from a graph VoronoiGraph VGErg = new VoronoiGraph(); foreach (VoronoiEdge e in g.Edges) { if (EdgeInBounds(e)) { VGErg.Edges.Add(e); } } foreach (VoronoiEdge VE in VGErg.Edges) { VGErg.Vertizes.Add(VE.VVertexA); VGErg.Vertizes.Add(VE.VVertexB); } return(VGErg); }
public static List<Edge> Delaunay(List<Point> points, VoronoiGraph VG, List<IDrawable> visualSteps) { List<VoronoiEdge> edges = new List<VoronoiEdge>(); List<Edge> edges_to_paint = new List<Edge>(); edges = VG.Edges.ToList<VoronoiEdge>(); List<Edge> result = new List<Edge>(); for (int i = 0; i < edges.Count(); ++i) { Edge e_temp = new Edge(Pack_into_Edge(edges[i]), Color.Yellow); edges_to_paint.Add(e_temp); visualSteps.Add(new Painting(points,edges_to_paint, edges)); Point p1 = new Point((int)edges[i].LeftData[0], (int)edges[i].LeftData[1]); Point p2 = new Point((int)edges[i].RightData[0], (int)edges[i].RightData[1]); Edge e = new Edge(p1, p2, Color.Yellow); result.Add(e); edges_to_paint.Add(e); visualSteps.Add(new Painting(points,edges_to_paint, edges)); edges_to_paint.RemoveAt(edges_to_paint.Count - 2); } return result; }
// Update is called once per frame void Update() { if (Input.GetKeyDown(KeyCode.R)) { Reset(); } if (Input.GetKeyDown(KeyCode.C)) { _result = null; CreateSites(); CalculateVoronoi(); } if (Input.GetKeyDown(KeyCode.F)) { Fracture(); } if (Input.GetKeyDown(KeyCode.E)) { Explode(); } }
GenerateRelaxedGraph(List <Vector> cv, int stepsLeft) { // Implementation of Lloyd's Relaxation algorithm // http://en.wikipedia.org/wiki/Lloyd's_algorithm VoronoiGraph vg = Voronoi(cv); List <Vector> ncv = new List <Vector>(); if (stepsLeft == 0) { cellVectors = cv; return(RefineGraph(vg)); } foreach (Vector v in cv) { Vector centroid = new Vector(0, 0); HashSet <Vector> corners = new HashSet <Vector>(); foreach (VoronoiEdge e in vg.Edges) { if (e.LeftData != v && e.RightData != v) { continue; } corners.Add(e.VVertexA); corners.Add(e.VVertexB); } foreach (Vector c in corners) { centroid += c; } ncv.Add(centroid / corners.Count); } return(GenerateRelaxedGraph(ncv, stepsLeft - 1)); }
public void LoadMap(LoadMapParams loadMapParams) { 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) < 400) && ((v0 / say) > 0)) { vector[0] = v0 / say; } if (((v1 / say) < 400) && ((v1 / say) > 0)) { vector[1] = v1 / say; } } } voronoiMap = Fortune.ComputeVoronoiGraph(loadMapParams.Points); ImproveMapData(voronoiMap, loadMapParams.Fix); }
// 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))); } }
private void Delaunay_Click(object sender, EventArgs e) { for (int i = 0; i < Array_of_vertexes.Count(); ++i) { Array_of_vertexes[i].Highlighted = false; } DrawEvents.Clear(); DrawEvents.Add(new Painting(Array_of_vertexes, new List <Edge>())); List <Vector> Points = new List <Vector>(AlgorithmsVisualiser.Pack_into_ListOfVector(Array_of_vertexes)); VoronoiGraph graph = new VoronoiGraph(); graph = AlgorithmsVisualiser.FortuneAlgo(Points); List <VoronoiEdge> VE = graph.Edges.ToList <VoronoiEdge>(); List <Edge> tri = AlgorithmsVisualiser.Delaunay(Array_of_vertexes, graph, DrawEvents); foreach (Edge edge in tri) { edge.color = Color.Red; } GL.LineWidth(1); DrawEvents.Add(new Painting(Array_of_vertexes, tri, VE)); }
public static List <Cellule> Start(DraftSight.Interop.dsAutomation.ReferenceImage img, List <PointF> liste, int nbEquilibrage, out VoronoiGraph graph) { List <Cellule> listepoincon = null; try { int LgMM = (int)img.Width; int HtMM = (int)img.Height; int LgPx = LgMM + 1; int HtPx = HtMM + 1; var bmp = new Bitmap(img.GetPath()); Settings.Bmp = bmp.Redimensionner(new Size(LgPx, HtPx)); bmp.Dispose(); Settings.Dimensions = new Size(LgMM, HtMM);; //Settings.Histogram = BitmapHelper.Histogramme(Settings.Bmp); BitmapHelper.Verrouiller(Settings.Bmp); Settings.Graph = VoronoiGraph.ComputeVoronoiGraph(liste, LgMM, HtMM, false); for (int k = 0; k < nbEquilibrage; k++) { liste = Equilibrer(); Settings.Graph = VoronoiGraph.ComputeVoronoiGraph(liste, LgMM, HtMM, false); } listepoincon = CalculerCellule(); BitmapHelper.Liberer(); Settings.Bmp.Dispose(); } catch (Exception ex) { LogDebugging.Log.Message(ex); } graph = Settings.Graph; return(listepoincon); }
public static List <Edge> Delaunay(List <Point> points, VoronoiGraph VG, List <IDrawable> visualSteps) { List <VoronoiEdge> edges = new List <VoronoiEdge>(); List <Edge> edges_to_paint = new List <Edge>(); edges = VG.Edges.ToList <VoronoiEdge>(); List <Edge> result = new List <Edge>(); for (int i = 0; i < edges.Count(); ++i) { Edge e_temp = new Edge(Pack_into_Edge(edges[i]), Color.Yellow); edges_to_paint.Add(e_temp); visualSteps.Add(new Painting(points, edges_to_paint, edges)); Point p1 = new Point((int)edges[i].LeftData[0], (int)edges[i].LeftData[1]); Point p2 = new Point((int)edges[i].RightData[0], (int)edges[i].RightData[1]); Edge e = new Edge(p1, p2, Color.Yellow); result.Add(e); edges_to_paint.Add(e); visualSteps.Add(new Painting(points, edges_to_paint, edges)); edges_to_paint.RemoveAt(edges_to_paint.Count - 2); } return(result); }
private void Relax(VoronoiGraph graph, List <Vector> vectors) { foreach (var vector in vectors) { var v0 = 0.0d; var v1 = 0.0d; var edgesCount = 0; foreach (var edge in graph.Edges) { if (edge.LeftData == vector || edge.RightData == vector) { var p0 = (edge.VVertexA[0] + edge.VVertexB[0]) / 2; var p1 = (edge.VVertexA[1] + edge.VVertexB[1]) / 2; v0 += double.IsNaN(p0) ? 0 : p0; v1 += double.IsNaN(p1) ? 0 : p1; edgesCount++; } } vector[0] = v0 / edgesCount; vector[1] = v1 / edgesCount; } }
private void Fortune_Click(object sender, EventArgs e) { for (int i = 0; i < Array_of_vertexes.Count(); ++i) Array_of_vertexes[i].Highlighted = false; DrawEvents.Clear(); DrawEvents.Add(new Painting(Array_of_vertexes, new List<Edge>())); List<Vector> Points = new List<Vector>(AlgorithmsVisualiser.Pack_into_ListOfVector(Array_of_vertexes)); VoronoiGraph graph = new VoronoiGraph(); graph = AlgorithmsVisualiser.FortuneAlgo(Points); List<VoronoiEdge> VE = graph.Edges.ToList<VoronoiEdge>(); DrawEvents.Add(new Painting(Array_of_vertexes, new List<Edge>(), VE)); }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { VDataNode a, b, c; VEdgeNode eu, eo; b = e.NodeN; a = NodeHandler.LeftDataNode(b); c = NodeHandler.RightDataNode(b); if (a == null || b.Parent == null || c == null || !a.DataPoint.Equals(e.NodeL.DataPoint) || !c.DataPoint.Equals(e.NodeR.DataPoint)) { CircleCheckList = new VDataNode[] { }; return(Root); // Abbruch da sich der Graph verändert hat } eu = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //1. Create the new Vertex Vector VNew = new Vector(e.Center[0], e.Center[1]); // VNew[0] = Fortune.ParabolicCut(a.DataPoint[0],a.DataPoint[1],c.DataPoint[0],c.DataPoint[1],ys); // VNew[1] = (ys + a.DataPoint[1])/2 - 1/(2*(ys-a.DataPoint[1]))*(VNew[0]-a.DataPoint[0])*(VNew[0]-a.DataPoint[0]); VG.Vertizes.Add(VNew); //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 if (eu.Left == b) // c is sibling { eo = NodeHandler.EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu, eu.Right); } else // a is sibling { eo = NodeHandler.EdgeToRightDataNode(b); // replace eu by eu's Left eu.Parent.Replace(eu, eu.Left); } eu.Edge.AddVertex(VNew); // ///////////////////// uncertain // if(eo==eu) // return Root; // ///////////////////// eo.Edge.AddVertex(VNew); //2. Replace eo by new Edge VoronoiEdge VE = new VoronoiEdge(); VE.LeftData = a.DataPoint; VE.RightData = c.DataPoint; VE.AddVertex(VNew); VG.Edges.Add(VE); VEdgeNode VEN = new VEdgeNode(VE, false); VEN.Left = eo.Left; VEN.Right = eo.Right; if (eo.Parent == null) { return(VEN); } eo.Parent.Replace(eo, VEN); return(Root); }
void Compute(List <Point> sites) { this.sites = sites; this.graph = this.voronoi.Compute(sites, this.bounds); }
void CalculateVoronoi() { _result = _voronoi.Compute(_sites, _bounds); }
public static VoronoiGraph ComputeVoronoiGraph(IEnumerable <Vector2> datapoints) { var pq = new List <VEvent>(); var currentCircles = new Hashtable(); var vg = new VoronoiGraph(); VNode rootNode = null; foreach (var v in datapoints) { pq.Add(new VDataEvent(v)); } pq.Sort(); while (pq.Count > 0) { var ve = pq.First(); pq.Remove(ve); if (ve == null) { return(null); } VDataNode[] circleCheckList; if (ve is VDataEvent) { rootNode = VNode.ProcessDataEvent(ve as VDataEvent, rootNode, vg, ve.Y, out circleCheckList); } else if (ve is VCircleEvent) { currentCircles.Remove(((VCircleEvent)ve).NodeN); if (!((VCircleEvent)ve).Valid) { continue; } rootNode = VNode.ProcessCircleEvent(ve as VCircleEvent, rootNode, vg, out circleCheckList); } else { throw new Exception("Got event of type " + ve.GetType() + "!"); } foreach (var vd in circleCheckList) { if (currentCircles.ContainsKey(vd)) { ((VCircleEvent)currentCircles[vd]).Valid = false; currentCircles.Remove(vd); } var vce = VNode.CircleCheckDataNode(vd, ve.Y); if (vce != null) { pq.Add(vce); pq.Sort(); currentCircles[vd] = vce; } } if (ve is VDataEvent) { var dp = ((VDataEvent)ve).DataPoint; foreach (VCircleEvent vce in currentCircles.Values) { if (Dist(dp[0], dp[1], vce.CenterX, vce.CenterY) < vce.Y - vce.CenterY && Math.Abs(Dist(dp[0], dp[1], vce.CenterX, vce.CenterY) - (vce.Y - vce.CenterY)) > 1e-10) { vce.Valid = false; } } } } VNode.CleanUpTree(rootNode); foreach (var ve in vg.GetEdges().Select(edge => edge as VoronoiEdge)) { if (Edge.IsUnknownVertex(ve.V2)) { ve.AddVertex(Edge.GetInfiniteVertex()); if (Math.Abs(ve.LeftData[1] - ve.RightData[1]) < 1e-10 && ve.LeftData[0] < ve.RightData[0]) { var T = ve.LeftData; ve.LeftData = ve.RightData; ve.RightData = T; } } } var minuteEdges = new ArrayList(); foreach (var ve in vg.GetEdges()) { if (!ve.IsPartlyInfinite && ve.V1.Equals(ve.V2)) { minuteEdges.Add(ve); foreach (var ve2 in vg.GetEdges()) { if (ve2.V1.Equals(ve.V1)) { ve2.V1 = ve.V1; } if (ve2.V2.Equals(ve.V1)) { ve2.V2 = ve.V1; } } } } foreach (VoronoiEdge ve in minuteEdges) { vg.RemoveEdge(ve, false); } return(vg); }
public VoronoiGraph Compute(List<Point> sites, Bounds bbox) { this.Reset(); // Initialize site event queue var siteEvents = sites.Take(sites.Count).ToList(); /*siteEvents.Sort((a, b) => { float r = b.y - a.y; if (r != 0) { return Mathf.CeilToInt(r); } return Mathf.CeilToInt(b.x - a.x); });*/ siteEvents = siteEvents.OrderByDescending(s => s.y).ToList(); // process queue Point site = siteEvents.Last(); siteEvents.Remove(site); int siteid = 0; float xsitex = -Mathf.Infinity; float xsitey = -Mathf.Infinity; // main loop for (; ; ) { // we need to figure whether we handle a site or circle event // for this we find out if there is a site event and it is // 'earlier' than the circle event CircleEvent circle = this.firstCircleEvent; // add beach section if (site && (!circle || site.y < circle.y || (site.y == circle.y && site.x < circle.x))) { // only if site is not a duplicate if (site.x != xsitex || site.y != xsitey) { // first create cell for new site //this.cells[siteid] = new Cell(site); this.cells.Insert(siteid, new Cell(site)); site.id = siteid++; // then create a beachsection for that site this.AddBeachSection(site); // remember last site coords to detect duplicate xsitey = site.y; xsitex = site.x; } site = siteEvents.Count > 0 ? siteEvents.Last() : null; if (siteEvents.Count > 0) siteEvents.Remove(site); } // remove beach section else if (circle) { this.RemoveBeachSection(circle.arc); } // all done, quit else { break; } } // wrapping-up this.ClipEdges(bbox); this.CloseCells(bbox); VoronoiGraph graph = new VoronoiGraph(); graph.sites = sites; graph.cells = this.cells; graph.edges = this.edges; this.Reset(); return graph; }
private void ImproveMapData(VoronoiGraph voronoiMap, bool fix = false) { IFactory fact = new MapItemFactory(); foreach (VoronoiEdge edge in voronoiMap.Edges) { if (fix) { if (!FixPoints(edge)) { continue; } } Corner c1 = fact.CornerFactory(edge.VVertexA[0], edge.VVertexA[1]); Corner c2 = fact.CornerFactory(edge.VVertexB[0], edge.VVertexB[1]); Center cntrLeft = fact.CenterFactory(edge.LeftData[0], edge.LeftData[1]); Center cntrRight = fact.CenterFactory(edge.RightData[0], edge.RightData[1]); if (c1 == null || c2 == null) { } c1.AddAdjacent(c2); c2.AddAdjacent(c1); cntrRight.Corners.Add(c1); cntrRight.Corners.Add(c2); cntrLeft.Corners.Add(c1); cntrLeft.Corners.Add(c2); Edge e = fact.EdgeFactory(c1, c2, cntrLeft, cntrRight); cntrLeft.Borders.Add(e); cntrRight.Borders.Add(e); cntrLeft.Neighbours.Add(cntrRight); cntrRight.Neighbours.Add(cntrLeft); c1.AddProtrudes(e); c2.AddProtrudes(e); c1.AddTouches(cntrLeft); c1.AddTouches(cntrRight); c2.AddTouches(cntrLeft); c2.AddTouches(cntrRight); } foreach (Corner q in App.AppMap.Corners.Values) { if (!q.Border) { var point = new Point(0, 0); foreach (Center c in q.Touches) { point.X += c.Point.X; point.Y += c.Point.Y; } point.X = point.X / q.Touches.Count; point.Y = point.Y / q.Touches.Count; q.Point = point; } } //foreach (var c in App.AppMap.Centers) //{ // c.Value.FixBorders(); // c.SetEdgeAreas(); // c.Value.OrderCorners(); //} IslandHandler.CreateIsland(); }
/// <summary> /// Will return the new root (unchanged except in start-up) /// </summary> public static VNode ProcessDataEvent(VDataEvent e, VNode root, VoronoiGraph vg, double ys, out VDataNode[] circleCheckList) { if (root == null) { root = new VDataNode(e.DataPoint); circleCheckList = new[] { (VDataNode)root }; return(root); } //1. Find the node to be replaced VNode c = FindDataNode(root, ys, e.DataPoint[0]); //2. Create the subtree (ONE Edge, but two VEdgeNodes) var ve = new VoronoiEdge { LeftData = ((VDataNode)c).DataPoint, RightData = e.DataPoint, V1 = Edge.GetUnknownVertex(), V2 = Edge.GetUnknownVertex() }; vg.AddEdge(ve); VNode subRoot; if (Math.Abs(ve.LeftData[1] - ve.RightData[1]) < 1e-10) { if (ve.LeftData[0] < ve.RightData[0]) { subRoot = new VEdgeNode(ve, false) { Left = new VDataNode(ve.LeftData), Right = new VDataNode(ve.RightData) }; } else { subRoot = new VEdgeNode(ve, true) { Left = new VDataNode(ve.RightData), Right = new VDataNode(ve.LeftData) }; } circleCheckList = new[] { (VDataNode)subRoot.Left, (VDataNode)subRoot.Right }; } else { subRoot = new VEdgeNode(ve, false) { Left = new VDataNode(ve.LeftData), Right = new VEdgeNode(ve, true) { Left = new VDataNode(ve.RightData), Right = new VDataNode(ve.LeftData) } }; circleCheckList = new[] { (VDataNode)subRoot.Left, (VDataNode)subRoot.Right.Left, (VDataNode)subRoot.Right.Right }; } //3. Apply subtree if (c.Parent == null) { return(subRoot); } c.Parent.Replace(c, subRoot); return(root); }
/// <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 override List <IActivityData> Process() { IDatasetElement sElement = base.SourceDatasetElement; IFeatureClass sFc = base.SourceFeatureClass; ActivityBase.TargetDatasetElement tElement = base.TargetDatasetElement; IDataset tDs = base.TargetDataset; //IFeatureDatabase tDatabase = base.TargetFeatureDatabase; GeometryDef geomDef = new GeometryDef( geometryType.Polyline, null, false); IFeatureClass tFc = base.CreateTargetFeatureclass(geomDef, sFc.Fields); IFeatureDatabase tDatabase = FeatureDatabase(tFc); Report.featureMax = sFc.CountFeatures; Report.featurePos = 0; ReportProgess("Query Filter: " + SourceData.FilterClause); Nodes nodes = new Nodes(); using (IFeatureCursor cursor = SourceData.GetFeatures(String.Empty)) { if (cursor == null) { return(null); } IFeature feature; while ((feature = cursor.NextFeature) != null) { if (Report.featurePos++ % 100 == 0) { ReportProgess(); } if (feature.Shape is IPoint) { nodes.Add((IPoint)feature.Shape); } } } VoronoiGraph voronoi = new VoronoiGraph(); voronoi.ProgressMessage += new VoronoiGraph.ProgressMessageEventHandler(voronoi_ProgressMessage); voronoi.Progress += new VoronoiGraph.ProgressEventHandler(voronoi_Progress); voronoi.Calc(nodes); List <IPoint> vertices = voronoi.Nodes; Edges edges = voronoi.Edges; ReportProgess("Write Lines"); Report.featurePos = 0; List <IFeature> features = new List <IFeature>(); foreach (Edge edge in edges) { Polyline pLine = new Polyline(); Path path = new Path(); path.AddPoint(vertices[edge.p1]); path.AddPoint(vertices[edge.p2]); pLine.AddPath(path); Feature feature = new Feature(); feature.Shape = pLine; features.Add(feature); Report.featurePos++; if (features.Count >= 100) { if (!tDatabase.Insert(tFc, features)) { throw new Exception(tDatabase.lastErrorMsg); } features.Clear(); ReportProgess(); } } if (features.Count > 0) { ReportProgess(); if (!tDatabase.Insert(tFc, features)) { throw new Exception(tDatabase.lastErrorMsg); } } ReportProgess("Flush Features"); base.FlushFeatureClass(tFc); return(base.ToProcessResult(tFc)); }
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); }
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); }
/// <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; }
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. }
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(); } }
public static VoronoiGraph FortuneAlgo(List<Vector> points) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; for (int i = 0; i < points.Count; ++i) PQ.Push(new VDataEvent(points[i])); while (PQ.Count > 0) { VEvent VE = PQ.Pop() as VEvent; VDataNode[] CircleCheckList; if (VE is VDataEvent) RootNode = ProcessDataEvent(VE as VDataEvent, RootNode, VG, VE.Y, out CircleCheckList); else if (VE is VCircleEvent) { CurrentCircles.Remove(((VCircleEvent)VE).NodeN); if (!((VCircleEvent)VE).Valid) continue; RootNode = ProcessCircleEvent(VE as VCircleEvent, RootNode, VG, VE.Y, out CircleCheckList); } else throw new Exception("Got event of type " + VE.GetType().ToString() + "!"); foreach (VDataNode VD in CircleCheckList) { if (CurrentCircles.ContainsKey(VD)) { ((VCircleEvent)CurrentCircles[VD]).Valid = false; CurrentCircles.Remove(VD); } VCircleEvent VCE = CircleCheckDataNode(VD, VE.Y); if (VCE != null) { PQ.Push(VCE); CurrentCircles[VD] = VCE; } } if (VE is VDataEvent) { Vector DP = ((VDataEvent)VE).DataPoint; foreach (VCircleEvent VCE in CurrentCircles.Values) { if (MathTools.Dist(DP[0], DP[1], VCE.Center[0], VCE.Center[1]) < VCE.Y - VCE.Center[1] && Math.Abs(MathTools.Dist(DP[0], DP[1], VCE.Center[0], VCE.Center[1]) - (VCE.Y - VCE.Center[1])) > 1e-10) VCE.Valid = false; } } } VNode.CleanUpTree(RootNode); foreach (VoronoiEdge VE in VG.Edges) { if (VE.Done) continue; if (VE.VVertexB == Fortune.VVUnkown) { VE.AddVertex(Fortune.VVInfinite); if (Math.Abs(VE.LeftData[1] - VE.RightData[1]) < 1e-10 && VE.LeftData[0] < VE.RightData[0]) { Vector T = VE.LeftData; VE.LeftData = VE.RightData; VE.RightData = T; } } } ArrayList MinuteEdges = new ArrayList(); foreach (VoronoiEdge VE in VG.Edges) { if (!VE.IsPartlyInfinite && VE.VVertexA.Equals(VE.VVertexB)) { MinuteEdges.Add(VE); foreach (VoronoiEdge VE2 in VG.Edges) { if (VE2.VVertexA.Equals(VE.VVertexA)) VE2.VVertexA = VE.VVertexA; if (VE2.VVertexB.Equals(VE.VVertexA)) VE2.VVertexB = VE.VVertexA; } } } foreach (VoronoiEdge VE in MinuteEdges) VG.Edges.Remove(VE); return VG; }
// 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); }
/// <summary> /// The original algorithm simply allows edges that have one defined point and /// another "NAN" point. Simply excluding the not a number coordinates fails /// to preserve the known direction of the ray. We only need to extend this /// long enough to encounter the bounding box, not infinity. /// </summary> /// <param name="graph">The VoronoiGraph with the edge list.</param> /// <param name="bounds">The polygon bounding the datapoints.</param> private static void HandleBoundaries(VoronoiGraph graph, IEnvelope bounds) { List <ILineString> boundSegments = new List <ILineString>(); List <VoronoiEdge> unboundEdges = new List <VoronoiEdge>(); // Identify bound edges for intersection testing foreach (VoronoiEdge edge in graph.Edges) { if (edge.VVertexA.ContainsNan() || edge.VVertexB.ContainsNan()) { unboundEdges.Add(edge); continue; } boundSegments.Add( new LineString(new List <Coordinate> { edge.VVertexA.ToCoordinate(), edge.VVertexB.ToCoordinate() })); } // calculate a length to extend a ray to look for intersections IEnvelope env = bounds; double h = env.Height; double w = env.Width; double len = Math.Sqrt((w * w) + (h * h)); // len is now long enough to pass entirely through the dataset no matter where it starts foreach (VoronoiEdge edge in unboundEdges) { // the unbound line passes thorugh start Coordinate start = (edge.VVertexB.ContainsNan()) ? edge.VVertexA.ToCoordinate() : edge.VVertexB.ToCoordinate(); // the unbound line should have a direction normal to the line joining the left and right source points double dx = edge.LeftData.X - edge.RightData.X; double dy = edge.LeftData.Y - edge.RightData.Y; double l = Math.Sqrt((dx * dx) + (dy * dy)); // the slope of the bisector between left and right double sx = -dy / l; double sy = dx / l; Coordinate center = bounds.Center(); if ((start.X > center.X && start.Y > center.Y) || (start.X < center.X && start.Y < center.Y)) { sx = dy / l; sy = -dx / l; } Coordinate end1 = new Coordinate(start.X + (len * sx), start.Y + (len * sy)); Coordinate end2 = new Coordinate(start.X - (sx * len), start.Y - (sy * len)); Coordinate end = (end1.Distance(center) < end2.Distance(center)) ? end2 : end1; if (bounds.Contains(end)) { end = new Coordinate(start.X - (sx * len), start.Y - (sy * len)); } if (edge.VVertexA.ContainsNan()) { edge.VVertexA = new Vector2(end.ToArray()); } else { edge.VVertexB = new Vector2(end.ToArray()); } } }
private static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { VDataNode a, b, c; VEdgeNode e1, e2; b = e.NodeN; a = VNode.LeftDataNode(b); c = VNode.RightDataNode(b); if (a == null || b.Parent == null || c == null || !a.DataPoint.Equals(e.NodeL.DataPoint) || !c.DataPoint.Equals(e.NodeR.DataPoint)) { CircleCheckList = new VDataNode[] { }; return Root; // повертаємось, бо графік змінився } e1 = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //Створюємо нову вершину Vector VNew = new Vector(e.Center[0], e.Center[1]); VG.Vertizes.Add(VNew); //2. виясняємо, чи а або с знаходяться у віддаленій частині дерева (інший - брат b), і призначаємо нову вершину if (e1.Left == b) // c - брат { e2 = VNode.EdgeToRightDataNode(a); // замінюємо e1 правим нащадком e1.Parent.Replace(e1, e1.Right); } else // a - брат { e2 = VNode.EdgeToRightDataNode(b); // замінюємо e1 лівим нащадком e1.Parent.Replace(e1, e1.Left); } e1.Edge.AddVertex(VNew); e2.Edge.AddVertex(VNew); //Замінюємо e2 новим ребром VoronoiEdge VE = new VoronoiEdge(); VE.LeftData = a.DataPoint; VE.RightData = c.DataPoint; VE.AddVertex(VNew); VG.Edges.Add(VE); VEdgeNode VEN = new VEdgeNode(VE, false); VEN.Left = e2.Left; VEN.Right = e2.Right; if (e2.Parent == null) return VEN; e2.Parent.Replace(e2, VEN); return Root; }
void Compute(List<Point> sites) { this.sites = sites; this.graph = this.voronoi.Compute(sites, this.bounds); }
private static VNode ProcessDataEvent(VDataEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { if (Root == null) { Root = new VDataNode(e.DataPoint); CircleCheckList = new VDataNode[] { (VDataNode)Root }; return Root; } //Знаходимо вузол для заміщення VNode C = VNode.FindDataNode(Root, ys, e.DataPoint[0]); //Створюємо піддерево з одним ребром, але двома VEdgeNodes VoronoiEdge VE = new VoronoiEdge(); VE.LeftData = ((VDataNode)C).DataPoint; VE.RightData = e.DataPoint; VE.VVertexA = Fortune.VVUnkown; VE.VVertexB = Fortune.VVUnkown; VG.Edges.Add(VE); VNode SubRoot; if (Math.Abs(VE.LeftData[1] - VE.RightData[1]) < 1e-10) { if (VE.LeftData[0] < VE.RightData[0]) { SubRoot = new VEdgeNode(VE, false); SubRoot.Left = new VDataNode(VE.LeftData); SubRoot.Right = new VDataNode(VE.RightData); } else { SubRoot = new VEdgeNode(VE, true); SubRoot.Left = new VDataNode(VE.RightData); SubRoot.Right = new VDataNode(VE.LeftData); } CircleCheckList = new VDataNode[] { (VDataNode)SubRoot.Left, (VDataNode)SubRoot.Right }; } else { SubRoot = new VEdgeNode(VE, false); SubRoot.Left = new VDataNode(VE.LeftData); SubRoot.Right = new VEdgeNode(VE, true); SubRoot.Right.Left = new VDataNode(VE.RightData); SubRoot.Right.Right = new VDataNode(VE.LeftData); CircleCheckList = new VDataNode[] { (VDataNode)SubRoot.Left, (VDataNode)SubRoot.Right.Left, (VDataNode)SubRoot.Right.Right }; } //"Застосовуємо" піддерево if (C.Parent == null) return SubRoot; C.Parent.Replace(C, SubRoot); return Root; }
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 FortuneAlgo(List <Vector> points) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; for (int i = 0; i < points.Count; ++i) { PQ.Push(new VDataEvent(points[i])); } while (PQ.Count > 0) { VEvent VE = PQ.Pop() as VEvent; VDataNode[] CircleCheckList; if (VE is VDataEvent) { RootNode = ProcessDataEvent(VE as VDataEvent, RootNode, VG, VE.Y, out CircleCheckList); } else if (VE is VCircleEvent) { CurrentCircles.Remove(((VCircleEvent)VE).NodeN); if (!((VCircleEvent)VE).Valid) { continue; } RootNode = ProcessCircleEvent(VE as VCircleEvent, RootNode, VG, VE.Y, out CircleCheckList); } else { throw new Exception("Got event of type " + VE.GetType().ToString() + "!"); } foreach (VDataNode VD in CircleCheckList) { if (CurrentCircles.ContainsKey(VD)) { ((VCircleEvent)CurrentCircles[VD]).Valid = false; CurrentCircles.Remove(VD); } VCircleEvent VCE = CircleCheckDataNode(VD, VE.Y); if (VCE != null) { PQ.Push(VCE); CurrentCircles[VD] = VCE; } } if (VE is VDataEvent) { Vector DP = ((VDataEvent)VE).DataPoint; foreach (VCircleEvent VCE in CurrentCircles.Values) { if (MathTools.Dist(DP[0], DP[1], VCE.Center[0], VCE.Center[1]) < VCE.Y - VCE.Center[1] && Math.Abs(MathTools.Dist(DP[0], DP[1], VCE.Center[0], VCE.Center[1]) - (VCE.Y - VCE.Center[1])) > 1e-10) { VCE.Valid = false; } } } } VNode.CleanUpTree(RootNode); foreach (VoronoiEdge VE in VG.Edges) { if (VE.Done) { continue; } if (VE.VVertexB == Fortune.VVUnkown) { VE.AddVertex(Fortune.VVInfinite); if (Math.Abs(VE.LeftData[1] - VE.RightData[1]) < 1e-10 && VE.LeftData[0] < VE.RightData[0]) { Vector T = VE.LeftData; VE.LeftData = VE.RightData; VE.RightData = T; } } } ArrayList MinuteEdges = new ArrayList(); foreach (VoronoiEdge VE in VG.Edges) { if (!VE.IsPartlyInfinite && VE.VVertexA.Equals(VE.VVertexB)) { MinuteEdges.Add(VE); foreach (VoronoiEdge VE2 in VG.Edges) { if (VE2.VVertexA.Equals(VE.VVertexA)) { VE2.VVertexA = VE.VVertexA; } if (VE2.VVertexB.Equals(VE.VVertexA)) { VE2.VVertexB = VE.VVertexA; } } } } foreach (VoronoiEdge VE in MinuteEdges) { VG.Edges.Remove(VE); } return(VG); }