/// <summary> /// Visualization of 2D Voronoi map. /// </summary> /// <param name="weight">Weight of result image.</param> /// <param name="height">Height of result image.</param> /// <param name="Datapoints">Array of data points.</param> /// <returns>Result bitmap.</returns> public static Bitmap GetVoronoyMap(int weight, int height, IEnumerable Datapoints) { Bitmap bmp = new Bitmap(weight, height); VoronoiGraph graph = Fortune.ComputeVoronoiGraph(Datapoints); Graphics g = Graphics.FromImage(bmp); foreach (object o in graph.Vertizes) { Vector3 v = (Vector3)o; g.DrawEllipse(Pens.Black, (int)v[0] - 2, (int)v[1] - 2, 4, 4); } foreach (object o in Datapoints) { Vector3 v = (Vector3)o; g.DrawEllipse(Pens.Red, (int)v[0] - 1, (int)v[1] - 1, 2, 2); } foreach (object o in graph.Edges) { VoronoiEdge edge = (VoronoiEdge)o; try { g.DrawLine(Pens.Brown, (int)edge.VVertexA[0], (int)edge.VVertexA[1], (int)edge.VVertexB[0], (int)edge.VVertexB[1]); } catch { } } return(bmp); }
/// <summary> /// Will return the new root (unchanged except in start-up) /// </summary> public static VNode ProcessDataEvent(VDataEvent e, VNode Root, VoronoiGraph VG, float ys, out VDataNode[] CircleCheckList) { if (Root == null) { Root = new VDataNode(e.DataPoint); CircleCheckList = new VDataNode[] { (VDataNode)Root }; return(Root); } //1. Find the node to be replaced VNode C = VNode.FindDataNode(Root, ys, e.DataPoint[0]); //2. Create the subtree (ONE Edge, but two 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 }; } //3. Apply subtree if (C.Parent == null) { return(SubRoot); } C.Parent.Replace(C, SubRoot); return(Root); }
/// <summary> /// Visualization of Delaunay Triangulation /// </summary> /// <param name="weight">Weight of result image.</param> /// <param name="height">Height of result image.</param> /// <param name="Datapoints">Result bitmap.</param> /// <returns></returns> public static List <Triangle> GetDelaunayTriangulation(IEnumerable Datapoints) { System.Collections.Generic.List <Triangle> list = new System.Collections.Generic.List <Triangle>(); VoronoiGraph voronoiGraph = Fortune.ComputeVoronoiGraph(Datapoints); //Graphics g = Graphics.FromImage(bmp); List <Triangle> triangles = new List <Triangle>(); for (int i = voronoiGraph.Edges.Count - 1; i >= 0; i--) { VoronoiEdge edge1 = voronoiGraph.Edges[i]; for (int j = 0; j < i; j++) { VoronoiEdge edge2 = voronoiGraph.Edges[j]; //if (edge1.LeftData.Index == edge2.LeftData.Index) //{ // triangles.Add(new Triangle(edge1.LeftData.Index, edge1.RightData.Index, edge2.RightData.Index)); //} //if (edge1.RightData.Index == edge2.RightData.Index) //{ // triangles.Add(new Triangle(edge1.LeftData.Index, edge1.RightData.Index, edge2.LeftData.Index)); //} //if (edge1.RightData.Index == edge2.LeftData.Index) //{ // triangles.Add(new Triangle(edge1.LeftData.Index, edge1.RightData.Index, edge2.RightData.Index)); //} //if (edge1.LeftData.Index == edge2.RightData.Index) //{ // triangles.Add(new Triangle(edge1.LeftData.Index, edge1.RightData.Index, edge2.LeftData.Index)); //} } //if ((edge.LeftData[0] == v[0]) & (edge.LeftData[1] == v[1])) //{ // g.DrawLine(Pens.Black, (int)edge.LeftData[0], (int)edge.LeftData[1], (int)edge.RightData[0], (int)edge.RightData[1]); //} } ////Graphics g = Graphics.FromImage(bmp); //foreach (object o in Datapoints) //{ // Vector3 v = (Vector3)o; // //g.DrawEllipse(Pens.Red, (int)v[0] - 1, (int)v[1] - 1, 2, 2); // foreach (object obj in voronoiGraph.Edges) // { // VoronoiEdge edge = (VoronoiEdge)obj; // if ((edge.LeftData[0] == v[0]) & (edge.LeftData[1] == v[1])) // { // g.DrawLine(Pens.Black, (int)edge.LeftData[0], (int)edge.LeftData[1], (int)edge.RightData[0], (int)edge.RightData[1]); // } // } //} return(triangles); }
public VEdgeNode(VoronoiEdge E, bool Flipped) { this.Edge = E; this.Flipped = Flipped; }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, float ys, out VDataNode[] CircleCheckList) { VDataNode a, b, c; VEdgeNode eu, eo; 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); // Abbruch da sich der Graph verändert hat } eu = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //1. Create the new Vertex Vector3 VNew = new Vector3(e.Center[0], e.Center[1], 0); // 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 = VNode.EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu, eu.Right); } else // a is sibling { eo = VNode.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); }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode root, VoronoiGraph vg, double ys, out VDataNode[] circleCheckList) { VEdgeNode eo; var b = e.NodeN; var a = LeftDataNode(b); var c = RightDataNode(b); if (a == null || b.Parent == null || c == null || a.DataPoint != e.NodeL.DataPoint || c.DataPoint != e.NodeR.DataPoint) { circleCheckList = new VDataNode[] { }; return(root); // Abbruch da sich der Graph verändert hat } var eu = (VEdgeNode)b.Parent; circleCheckList = new[] { a, c }; //1. Create the new Vertex var 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 = EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu, eu.Right); } else // a is sibling { eo = EdgeToRightDataNode(b); // replace eu by eu's Left eu.Parent.Replace(eu, eu.Left); } eu.Edge.AddVertex(vNew); // ///////////////////// uncertain // if(eo==eu) // return Root; // ///////////////////// //complete & cleanup eo eo.Edge.AddVertex(vNew); //while(eo.Edge.VVertexB == Fortune.VVUnkown) //{ // eo.Flipped = !eo.Flipped; // eo.Edge.AddVertex(Fortune.VVInfinite); //} //if(eo.Flipped) //{ // Vector T = eo.Edge.LeftData; // eo.Edge.LeftData = eo.Edge.RightData; // eo.Edge.RightData = T; //} //2. Replace eo by new Edge var ve = new VoronoiEdge { LeftData = a.DataPoint, RightData = c.DataPoint }; ve.AddVertex(vNew); vg.Edges.Add(ve); var ven = new VEdgeNode(ve, false) { Left = eo.Left, Right = eo.Right }; if (eo.Parent == null) { return(ven); } eo.Parent.Replace(eo, ven); return(root); }
/// <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, VVertexA = Fortune.VvUnkown, 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) { 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> /// 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[] {(VDataNode)Root}; return Root; } //1. Find the node to be replaced VNode C = VNode.FindDataNode(Root, ys, e.DataPoint.X); //2. Create the subtree (ONE Edge, but two 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.Y-VE.RightData.Y)<1e-10) { if(VE.LeftData.X<VE.RightData.X) { 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}; } //3. Apply subtree if(C.Parent == null) return SubRoot; C.Parent.Replace(C,SubRoot); return Root; }
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 = 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; // Abbruch da sich der Graph verändert hat } eu = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] {a,c}; //1. Create the new Vertex Point VNew = new Point(e.Center.X,e.Center.Y); // VNew.X = Fortune.ParabolicCut(a.DataPoint.X,a.DataPoint.Y,c.DataPoint.X,c.DataPoint.Y,ys); // VNew.Y = (ys + a.DataPoint.Y)/2 - 1/(2*(ys-a.DataPoint.Y))*(VNew.X-a.DataPoint.X)*(VNew.X-a.DataPoint.X); 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 = VNode.EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu,eu.Right); } else // a is sibling { eo = VNode.EdgeToRightDataNode(b); // replace eu by eu's Left eu.Parent.Replace(eu,eu.Left); } eu.Edge.AddVertex(VNew); // ///////////////////// uncertain // if(eo==eu) // return Root; // ///////////////////// //complete & cleanup eo eo.Edge.AddVertex(VNew); //while(eo.Edge.VVertexB == Fortune.VVUnkown) //{ // eo.Flipped = !eo.Flipped; // eo.Edge.AddVertex(Fortune.VVInfinite); //} //if(eo.Flipped) //{ // Vector T = eo.Edge.LeftData; // eo.Edge.LeftData = eo.Edge.RightData; // eo.Edge.RightData = T; //} //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 Start() { var meshFilter = gameObject.AddComponent<MeshFilter>(); var edges = CellData.Edges.Select(e => { var vA = e.VVertexA; var vB = e.VVertexB; var dA = vA - CellData.Site; var dB = vB - CellData.Site; var atanA = Mathf.Atan2((float)dA.Y, (float)dA.X); var atanB = Mathf.Atan2((float)dB.Y, (float)dB.X); VoronoiEdge edge; if (atanA > 0f) { if (atanA < atanB) { edge = new VoronoiEdge { VVertexA = vB - CellData.Site, VVertexB = vA - CellData.Site }; } else { if (atanA - atanB > Mathf.PI) { edge = new VoronoiEdge { VVertexA = vB - CellData.Site, VVertexB = vA - CellData.Site }; } else { edge = new VoronoiEdge { VVertexA = vA - CellData.Site, VVertexB = vB - CellData.Site }; } } } else { if (atanA > atanB) { edge = new VoronoiEdge { VVertexA = vA - CellData.Site, VVertexB = vB - CellData.Site }; } else { if (atanB - atanA > Mathf.PI) { edge = new VoronoiEdge { VVertexA = vA - CellData.Site, VVertexB = vB - CellData.Site }; } else { edge = new VoronoiEdge { VVertexA = vB - CellData.Site, VVertexB = vA - CellData.Site }; } } } return edge; }).ToArray(); var maxDistFromCenter = edges.Max(e => Mathf.Max((float)e.VVertexA.Length, (float)e.VVertexB.Length)); if (edges[0].VVertexA.Length > maxDistFromCenter) { maxDistFromCenter = (float)edges[0].VVertexA.Length; } maxDistFromCenter *= 2; // To make sure that UV coords will be in [-0.5; 0.5] range Mesh mesh = new Mesh(); mesh.name = "cellMesh"; var cellCorners = new Vector3[edges.Length * 2 + 1]; var triangles = new int[edges.Length * 3]; var uvs = new Vector2[edges.Length * 2 + 1]; cellCorners[0] = Vector3.zero; // Placing Cell Center at Origin of new GameObjects //verts [1] = new Vector3 (edges [0].Start.x, edges [0].Start.y, 0f); var shift = new Vector2(0.5f, 0.5f); // Shifting texture coords origin uvs[0] = shift; uvs[1] = new Vector2(((float)edges[0].VVertexA.X + shift.x) / maxDistFromCenter, ((float)edges[0].VVertexA.Y + shift.y) / maxDistFromCenter); for (int i = 0; i < edges.Length; i++) { var edge = edges[i]; cellCorners[2 * i + 1] = new Vector3((float)edges[i].VVertexA.X, (float)edges[i].VVertexA.Y, 0f); cellCorners[2 * i + 2] = new Vector3((float)edges[i].VVertexB.X, (float)edges[i].VVertexB.Y, 0f); var uvStart = shift + new Vector2((float)edge.VVertexA.X / maxDistFromCenter, (float)edge.VVertexA.Y / maxDistFromCenter); var uvEnd = shift + new Vector2((float)edge.VVertexB.X / maxDistFromCenter, (float)edge.VVertexB.Y / maxDistFromCenter); uvs[2 * i + 1] = new Vector3(uvStart.x, uvStart.y, 0f); uvs[2 * i + 2] = new Vector3(uvEnd.x, uvEnd.y, 0f); triangles[3 * i] = 0; triangles[3 * i + 1] = 2 * i + 1; triangles[3 * i + 2] = 2 * i + 2; } mesh.vertices = cellCorners; mesh.uv = uvs; mesh.triangles = triangles; mesh.RecalculateNormals(); mesh.RecalculateBounds(); mesh.Optimize(); mesh.RecalculateTangents(); meshFilter.sharedMesh = mesh; var meshRenderer = gameObject.AddComponent<MeshRenderer>(); if (MeshMaterial == null) { meshRenderer.material.color = Color.green; } else { meshRenderer.material = MeshMaterial; } var polyCollider = gameObject.AddComponent<EdgeCollider2D>(); polyCollider.points = cellCorners.Skip(1).Select(c => new Vector2(c.x, c.y)).ToArray(); }
public VEdgeNode(VoronoiEdge e, bool flipped) { Edge = e; Flipped = flipped; }
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 = 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); // Abbruch da sich der Graph verändert hat } eu = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //1. Create the new Vertex Point VNew = new Point(e.Center.X, e.Center.Y); // VNew.X = Fortune.ParabolicCut(a.DataPoint.X,a.DataPoint.Y,c.DataPoint.X,c.DataPoint.Y,ys); // VNew.Y = (ys + a.DataPoint.Y)/2 - 1/(2*(ys-a.DataPoint.Y))*(VNew.X-a.DataPoint.X)*(VNew.X-a.DataPoint.X); 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 = VNode.EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu, eu.Right); } else // a is sibling { eo = VNode.EdgeToRightDataNode(b); // replace eu by eu's Left eu.Parent.Replace(eu, eu.Left); } eu.Edge.AddVertex(VNew); // ///////////////////// uncertain // if(eo==eu) // return Root; // ///////////////////// //complete & cleanup eo eo.Edge.AddVertex(VNew); //while(eo.Edge.VVertexB == Fortune.VVUnkown) //{ // eo.Flipped = !eo.Flipped; // eo.Edge.AddVertex(Fortune.VVInfinite); //} //if(eo.Flipped) //{ // Vector T = eo.Edge.LeftData; // eo.Edge.LeftData = eo.Edge.RightData; // eo.Edge.RightData = T; //} //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); }