Inheritance: ICoord, IComparable
Exemple #1
0
 public Triangle(Site a, Site b, Site c)
 {
     _sites = new List<Site>();
     _sites.Add(a);
     _sites.Add(b);
     _sites.Add(c);
 }
 public static int CompareByYThenX(Site s1, Vector2 s2)
 {
     if (s1.y < s2.y)
         return -1;
     if (s1.y > s2.y)
         return 1;
     if (s1.x < s2.x)
         return -1;
     if (s1.x > s2.x)
         return 1;
     return 0;
 }
		/**
			 * This is the only way to create a new Edge 
			 * @param site0
			 * @param site1
			 * @return 
			 * 
			 */
		public static Edge CreateBisectingEdge (Site site0, Site site1)
		{
			float dx, dy, absdx, absdy;
			float a, b, c;
			
			dx = site1.x - site0.x;
			dy = site1.y - site0.y;
			absdx = dx > 0 ? dx : -dx;
			absdy = dy > 0 ? dy : -dy;
			c = site0.x * dx + site0.y * dy + (dx * dx + dy * dy) * 0.5f;
			if (absdx > absdy) {
				a = 1.0f;
				b = dy / dx;
				c /= dx;
			} else {
				b = 1.0f;
				a = dx / dy;
				c /= dy;
			}
				
			Edge edge = Edge.Create ();
			
			edge.leftSite = site0;
			edge.rightSite = site1;
			site0.AddEdge (edge);
			site1.AddEdge (edge);
				
			edge._leftVertex = null;
			edge._rightVertex = null;
				
			edge.a = a;
			edge.b = b;
			edge.c = c;
			//trace("createBisectingEdge: a ", edge.a, "b", edge.b, "c", edge.c);
				
			return edge;
		}
		public int Add (Site site)
		{
			_sorted = false;
			_sites.Add (site);
			return _sites.Count;
		}
Exemple #5
0
		private void FortunesAlgorithm ()
		{
			Site newSite, bottomSite, topSite, tempSite;
			Vertex v, vertex;
			Vector2 newintstar = Vector2.zero; //Because the compiler doesn't know that it will have a value - Julian
			Side leftRight;
			Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
			Edge edge;
			
			Rect dataBounds = _sites.GetSitesBounds ();
			
			int sqrt_nsites = (int)(Mathf.Sqrt (_sites.Count + 4));
			HalfedgePriorityQueue heap = new HalfedgePriorityQueue (dataBounds.y, dataBounds.height, sqrt_nsites);
			EdgeList edgeList = new EdgeList (dataBounds.x, dataBounds.width, sqrt_nsites);
			List<Halfedge> halfEdges = new List<Halfedge> ();
			List<Vertex> vertices = new List<Vertex> ();
			
			fortunesAlgorithm_bottomMostSite = _sites.Next ();
			newSite = _sites.Next ();
			
			for (;;) {
				if (heap.Empty () == false) {
					newintstar = heap.Min ();
				}
			
				if (newSite != null 
					&& (heap.Empty () || CompareByYThenX (newSite, newintstar) < 0)) {
					/* new site is smallest */
					//trace("smallest: new site " + newSite);
					
					// Step 8:
					lbnd = edgeList.EdgeListLeftNeighbor (newSite.Coord);	// the Halfedge just to the left of newSite
					//trace("lbnd: " + lbnd);
					rbnd = lbnd.edgeListRightNeighbor;		// the Halfedge just to the right
					//trace("rbnd: " + rbnd);
					bottomSite = FortunesAlgorithm_rightRegion (lbnd);		// this is the same as leftRegion(rbnd)
					// this Site determines the region containing the new site
					//trace("new Site is in region of existing site: " + bottomSite);
					
					// Step 9:
					edge = Edge.CreateBisectingEdge (bottomSite, newSite);
					//trace("new edge: " + edge);
					_edges.Add (edge);
					
					bisector = Halfedge.Create (edge, Side.LEFT);
					halfEdges.Add (bisector);
					// inserting two Halfedges into edgeList constitutes Step 10:
					// insert bisector to the right of lbnd:
					edgeList.Insert (lbnd, bisector);
					
					// first half of Step 11:
					if ((vertex = Vertex.Intersect (lbnd, bisector)) != null) {
						vertices.Add (vertex);
						heap.Remove (lbnd);
						lbnd.vertex = vertex;
						lbnd.ystar = vertex.y + newSite.Dist (vertex);
						heap.Insert (lbnd);
					}
					
					lbnd = bisector;
					bisector = Halfedge.Create (edge, Side.RIGHT);
					halfEdges.Add (bisector);
					// second Halfedge for Step 10:
					// insert bisector to the right of lbnd:
					edgeList.Insert (lbnd, bisector);
					
					// second half of Step 11:
					if ((vertex = Vertex.Intersect (bisector, rbnd)) != null) {
						vertices.Add (vertex);
						bisector.vertex = vertex;
						bisector.ystar = vertex.y + newSite.Dist (vertex);
						heap.Insert (bisector);	
					}
					
					newSite = _sites.Next ();	
				} else if (heap.Empty () == false) {
					/* intersection is smallest */
					lbnd = heap.ExtractMin ();
					llbnd = lbnd.edgeListLeftNeighbor;
					rbnd = lbnd.edgeListRightNeighbor;
					rrbnd = rbnd.edgeListRightNeighbor;
					bottomSite = FortunesAlgorithm_leftRegion (lbnd);
					topSite = FortunesAlgorithm_rightRegion (rbnd);
					// these three sites define a Delaunay triangle
					// (not actually using these for anything...)
					//_triangles.push(new Triangle(bottomSite, topSite, rightRegion(lbnd)));
					
					v = lbnd.vertex;
					v.SetIndex ();
					lbnd.edge.SetVertex ((Side)lbnd.leftRight, v);
					rbnd.edge.SetVertex ((Side)rbnd.leftRight, v);
					edgeList.Remove (lbnd); 
					heap.Remove (rbnd);
					edgeList.Remove (rbnd); 
					leftRight = Side.LEFT;
					if (bottomSite.y > topSite.y) {
						tempSite = bottomSite;
						bottomSite = topSite;
						topSite = tempSite;
						leftRight = Side.RIGHT;
					}
					edge = Edge.CreateBisectingEdge (bottomSite, topSite);
					_edges.Add (edge);
					bisector = Halfedge.Create (edge, leftRight);
					halfEdges.Add (bisector);
					edgeList.Insert (llbnd, bisector);
					edge.SetVertex (SideHelper.Other (leftRight), v);
					if ((vertex = Vertex.Intersect (llbnd, bisector)) != null) {
						vertices.Add (vertex);
						heap.Remove (llbnd);
						llbnd.vertex = vertex;
						llbnd.ystar = vertex.y + bottomSite.Dist (vertex);
						heap.Insert (llbnd);
					}
					if ((vertex = Vertex.Intersect (bisector, rrbnd)) != null) {
						vertices.Add (vertex);
						bisector.vertex = vertex;
						bisector.ystar = vertex.y + bottomSite.Dist (vertex);
						heap.Insert (bisector);
					}
				} else {
					break;
				}
			}
			
			// heap should be empty now
			heap.Dispose ();
			edgeList.Dispose ();
			
			for (int hIndex = 0; hIndex<halfEdges.Count; hIndex++) {
				Halfedge halfEdge = halfEdges [hIndex];
				halfEdge.ReallyDispose ();
			}
			halfEdges.Clear ();
			
			// we need the vertices to clip the edges
			for (int eIndex = 0; eIndex<_edges.Count; eIndex++) {
				edge = _edges [eIndex];
				edge.ClipVertices (_plotBounds);
			}
			// but we don't actually ever use them again!
			for (int vIndex = 0; vIndex<vertices.Count; vIndex++) {
				vertex = vertices [vIndex];
				vertex.Dispose ();
			}
			vertices.Clear ();
		}
Exemple #6
0
        /**
         * sort sites on y, then x, coord
         * also change each site's _siteIndex to match its new position in the list
         * so the _siteIndex can be used to identify the site for nearest-neighbor queries
         *
         * haha "also" - means more than one responsibility...
         *
         */
        private static float Compare(Site s1, Site s2)
        {
            int returnValue = (int)Voronoi.CompareByYThenX(s1, s2);

            // swap _siteIndex values if necessary to match new ordering:
            int tempIndex;
            if (returnValue == -1)
            {
                if (s1._siteIndex > s2._siteIndex)
                {
                    tempIndex = (int)s1._siteIndex;
                    s1._siteIndex = s2._siteIndex;
                    s2._siteIndex = (uint)tempIndex;
                }
            }
            else if (returnValue == 1)
            {
                if (s2._siteIndex > s1._siteIndex)
                {
                    tempIndex = (int)s2._siteIndex;
                    s2._siteIndex = s1._siteIndex;
                    s1._siteIndex = (uint)tempIndex;
                }

            }

            return returnValue;
        }
		public Triangle (Site a, Site b, Site c)
		{
			_sites = new List<Site> () { a, b, c };
		}
Exemple #8
0
 public uint Push(Site site)
 {
     _sorted = false;
     return (uint)_sites.Push(site);
 }
/**
Stupidly, Unity in 2D mode uses co-ords incompatible with Unity in 3D mode (xy instead of xz).

So we have to provide a boolean to switch between the two modes!
*/
    public static VoronoiDiagram CreateDiagramFromVoronoiOutput(Voronoi voronoiGenerator, bool useUnity2DCoordsNot3D )
    {
      GameObject go = new GameObject("New VoronoiMap");
      GameObject goCellHolder = new GameObject(_cellHolderName);
      goCellHolder.transform.parent = go.transform;
      GameObject goEdgeHolder = new GameObject(_edgeHolderName);
      goEdgeHolder.transform.parent = go.transform;
      GameObject goVertexHolder = new GameObject(_vertexHolderName);
      goVertexHolder.transform.parent = go.transform;
      
      VoronoiDiagram map = go.AddComponent<VoronoiDiagram>();

      System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
      watch.Reset();
      watch.Start();

      Dictionary<Site,VoronoiCell> generatedCells = new Dictionary<Site, VoronoiCell>();
      Dictionary<Vector2,VoronoiCellVertex> generatedVertices = new Dictionary<Vector2, VoronoiCellVertex>();

      int numEdgesCreated = 0;
      foreach (Edge edge in voronoiGenerator.Edges())
      {
        GameObject goEdge = new GameObject("Edge-#" + (numEdgesCreated++));
        goEdge.transform.parent = goEdgeHolder.transform;
                        
        VoronoiCellEdge vEdge = goEdge.AddComponent<VoronoiCellEdge>();
        Debug.Log("Processing edge = "+edge+" with clippedEnds = "+(edge.clippedEnds==null?"null":""+edge.clippedEnds.Count) );
        if( ! edge.visible)
        {
        Debug.Log("...Voronoi algorithm generated a non-existent edge, skipping it...");
        continue;
        }
        Vector2 clippedEndLeft = (Vector2)edge.clippedEnds [Side.LEFT];
        Vector2 clippedEndRight = (Vector2)edge.clippedEnds [Side.RIGHT];
        vEdge.AddVertex(FetchVertexOrAddToObject( clippedEndLeft, generatedVertices, goVertexHolder, useUnity2DCoordsNot3D));
        vEdge.AddVertex(FetchVertexOrAddToObject( clippedEndRight, generatedVertices, goVertexHolder, useUnity2DCoordsNot3D));
        goEdge.transform.localPosition = (vEdge.edgeVertexA.transform.localPosition + vEdge.edgeVertexB.transform.localPosition ) / 2.0f;
                
        Site[] bothSites = new Site[] { edge.leftSite, edge.rightSite };
        foreach (Site site in bothSites)
        {
          /** Re-use or create the Cell */
          VoronoiCell newCell = null; // C# is rubbish. Crashes if Dictionary lacks the key. Very bad design.
          if (generatedCells.ContainsKey(site))
            newCell = generatedCells [site];
          GameObject goCell;
                    
          if (newCell == null)
          {
            goCell = new GameObject("Cell-#" + generatedCells.Count);
            goCell.transform.parent = goCellHolder.transform;
            goCell.transform.localPosition = new Vector3( site.Coord.x, useUnity2DCoordsNot3D? site.Coord.y : 0, useUnity2DCoordsNot3D? 0 : site.Coord.y );
            newCell = goCell.AddComponent<VoronoiCell>();
            generatedCells.Add(site, newCell);
          }
          else
          {
            goCell = newCell.gameObject;
          }
                    
          /** Now that cell is created, attach it to BOTH Vertex's on the new Edge
                    (so that later its easy for us to to find Cells-for-this-Vertex, and also:
                    for a Cell to "trace" around its edges, picking "next edge" from each Vertex
                    by looking at which edges from the vertex border this cell (by checking
                    that BOTH Vertex-ends of the edge are attached to this cell)
                    
                    Also add the edge itself to the cell, and the cell to the edge.
                    */
          vEdge.AddCellWithSideEffects(newCell);
                    
        }
      }
      watch.Stop();
            
      return map;
    }
Exemple #10
0
 Site RightRegion(Halfedge he, Site bottomMostSite)
 {
     Edge edge = he.edge;
     if (edge == null)
     {
         return bottomMostSite;
     }
     return edge.GetSite(LR.Other(he.leftRight));
 }
Exemple #11
0
 internal static float CompareByYThenX(Site s1, Vector2 s2)
 {
     if (s1.Y < s2.y) return -1;
     if (s1.Y > s2.y) return 1;
     if (s1.X < s2.x) return -1;
     if (s1.X > s2.x) return 1;
     return 0;
 }
Exemple #12
0
 internal static float CompareByYThenX(Site s1, Site s2)
 {
     if (s1.Y < s2.Y) return -1;
     if (s1.Y > s2.Y) return 1;
     if (s1.X < s2.X) return -1;
     if (s1.X > s2.X) return 1;
     return 0;
 }
Exemple #13
0
        private void FortunesAlgorithm()
        {
            Site     newSite, bottomSite, topSite, tempSite;
            Vertex   v, vertex;
            Vector2  newintstar = Vector2.zero;            //Because the compiler doesn't know that it will have a value - Julian
            Side     leftRight;
            Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
            Edge     edge;

            Rect dataBounds = _sites.GetSitesBounds();

            int sqrt_nsites            = (int)(Mathf.Sqrt(_sites.Count + 4));
            HalfedgePriorityQueue heap = new HalfedgePriorityQueue(dataBounds.y, dataBounds.height, sqrt_nsites);
            EdgeList        edgeList   = new EdgeList(dataBounds.x, dataBounds.width, sqrt_nsites);
            List <Halfedge> halfEdges  = new List <Halfedge>();
            List <Vertex>   vertices   = new List <Vertex>();

            fortunesAlgorithm_bottomMostSite = _sites.Next();
            newSite = _sites.Next();

            for (;;)
            {
                if (heap.Empty() == false)
                {
                    newintstar = heap.Min();
                }

                if (newSite != null &&
                    (heap.Empty() || CompareByYThenX(newSite, newintstar) < 0))
                {
                    /* new site is smallest */
                    //trace("smallest: new site " + newSite);

                    // Step 8:
                    lbnd = edgeList.EdgeListLeftNeighbor(newSite.Coord);   // the Halfedge just to the left of newSite
                    //trace("lbnd: " + lbnd);
                    rbnd = lbnd.edgeListRightNeighbor;                     // the Halfedge just to the right
                    //trace("rbnd: " + rbnd);
                    bottomSite = FortunesAlgorithm_rightRegion(lbnd);      // this is the same as leftRegion(rbnd)
                    // this Site determines the region containing the new site
                    //trace("new Site is in region of existing site: " + bottomSite);

                    // Step 9:
                    edge = Edge.CreateBisectingEdge(bottomSite, newSite);
                    //trace("new edge: " + edge);
                    _edges.Add(edge);

                    bisector = Halfedge.Create(edge, Side.LEFT);
                    halfEdges.Add(bisector);
                    // inserting two Halfedges into edgeList constitutes Step 10:
                    // insert bisector to the right of lbnd:
                    edgeList.Insert(lbnd, bisector);

                    // first half of Step 11:
                    if ((vertex = Vertex.Intersect(lbnd, bisector)) != null)
                    {
                        vertices.Add(vertex);
                        heap.Remove(lbnd);
                        lbnd.vertex = vertex;
                        lbnd.ystar  = vertex.y + newSite.Dist(vertex);
                        heap.Insert(lbnd);
                    }

                    lbnd     = bisector;
                    bisector = Halfedge.Create(edge, Side.RIGHT);
                    halfEdges.Add(bisector);
                    // second Halfedge for Step 10:
                    // insert bisector to the right of lbnd:
                    edgeList.Insert(lbnd, bisector);

                    // second half of Step 11:
                    if ((vertex = Vertex.Intersect(bisector, rbnd)) != null)
                    {
                        vertices.Add(vertex);
                        bisector.vertex = vertex;
                        bisector.ystar  = vertex.y + newSite.Dist(vertex);
                        heap.Insert(bisector);
                    }

                    newSite = _sites.Next();
                }
                else if (heap.Empty() == false)
                {
                    /* intersection is smallest */
                    lbnd       = heap.ExtractMin();
                    llbnd      = lbnd.edgeListLeftNeighbor;
                    rbnd       = lbnd.edgeListRightNeighbor;
                    rrbnd      = rbnd.edgeListRightNeighbor;
                    bottomSite = FortunesAlgorithm_leftRegion(lbnd);
                    topSite    = FortunesAlgorithm_rightRegion(rbnd);
                    // these three sites define a Delaunay triangle
                    // (not actually using these for anything...)
                    _triangles.Add(new Triangle(bottomSite, topSite, FortunesAlgorithm_rightRegion(lbnd)));
                    //_triangles.push(new Triangle(bottomSite, topSite, rightRegion(lbnd)));

                    v = lbnd.vertex;
                    v.SetIndex();
                    lbnd.edge.SetVertex((Side)lbnd.leftRight, v);
                    rbnd.edge.SetVertex((Side)rbnd.leftRight, v);
                    edgeList.Remove(lbnd);
                    heap.Remove(rbnd);
                    edgeList.Remove(rbnd);
                    leftRight = Side.LEFT;
                    if (bottomSite.y > topSite.y)
                    {
                        tempSite   = bottomSite;
                        bottomSite = topSite;
                        topSite    = tempSite;
                        leftRight  = Side.RIGHT;
                    }
                    edge = Edge.CreateBisectingEdge(bottomSite, topSite);
                    _edges.Add(edge);
                    bisector = Halfedge.Create(edge, leftRight);
                    halfEdges.Add(bisector);
                    edgeList.Insert(llbnd, bisector);
                    edge.SetVertex(SideHelper.Other(leftRight), v);
                    if ((vertex = Vertex.Intersect(llbnd, bisector)) != null)
                    {
                        vertices.Add(vertex);
                        heap.Remove(llbnd);
                        llbnd.vertex = vertex;
                        llbnd.ystar  = vertex.y + bottomSite.Dist(vertex);
                        heap.Insert(llbnd);
                    }
                    if ((vertex = Vertex.Intersect(bisector, rrbnd)) != null)
                    {
                        vertices.Add(vertex);
                        bisector.vertex = vertex;
                        bisector.ystar  = vertex.y + bottomSite.Dist(vertex);
                        heap.Insert(bisector);
                    }
                }
                else
                {
                    break;
                }
            }

            // heap should be empty now
            heap.Dispose();
            edgeList.Dispose();

            for (int hIndex = 0; hIndex < halfEdges.Count; hIndex++)
            {
                Halfedge halfEdge = halfEdges[hIndex];
                halfEdge.ReallyDispose();
            }
            halfEdges.Clear();

            // we need the vertices to clip the edges
            for (int eIndex = 0; eIndex < _edges.Count; eIndex++)
            {
                edge = _edges[eIndex];
                edge.ClipVertices(_plotBounds);
            }
            // but we don't actually ever use them again!
            for (int vIndex = 0; vIndex < vertices.Count; vIndex++)
            {
                vertex = vertices[vIndex];
                vertex.Dispose();
            }
            vertices.Clear();
        }