66 using Microsoft.Xna.Framework;
68 using System.Collections.Generic;
78 double borderMinX, borderMaxX, borderMinY, borderMaxY;
80 double xmin, xmax, ymin, ymax, deltax, deltay;
87 double minDistanceBetweenSites;
99 List<GraphEdge> allEdges;
106 public Voronoi (
double minDistanceBetweenSites )
112 this.minDistanceBetweenSites = minDistanceBetweenSites;
126 public List<GraphEdge>
generateVoronoi (
double[] xValuesIn,
double[] yValuesIn,
double minX,
double maxX,
double minY,
double maxY )
128 sort(xValuesIn, yValuesIn, xValuesIn.Length);
160 private void sort (
double[] xValuesIn,
double[] yValuesIn,
int count )
163 allEdges =
new List<GraphEdge>();
169 double sn = (double)nsites + 4;
170 sqrt_nsites = (int) Math.Sqrt ( sn );
173 double[] xValues =
new double[count];
174 double[] yValues =
new double[count];
175 for (
int i = 0; i < count; i++)
177 xValues[i] = xValuesIn[i];
178 yValues[i] = yValuesIn[i];
180 sortNode ( xValues, yValues, count );
183 private void qsort ( Site[] sites )
185 List<Site> listSites =
new List<Site>( sites.Length );
186 for (
int i = 0; i < sites.Length; i++ )
188 listSites.Add ( sites[i] );
191 listSites.Sort (
new SiteSorterYX () );
194 for (
int i=0; i < sites.Length; i++)
196 sites[i] = listSites[i];
200 private void sortNode (
double[] xValues,
double[] yValues,
int numPoints )
203 sites =
new Site[nsites];
209 for (
int i = 0; i < nsites; i++ )
211 sites[i] =
new Site();
212 sites[i].Coord.SetPoint ( xValues[i], yValues[i] );
213 sites[i].SiteNbr = i;
215 if ( xValues[i] < xmin )
217 else if ( xValues[i] > xmax )
220 if ( yValues[i] < ymin )
222 else if ( yValues[i] > ymax )
227 deltax = xmax - xmin;
228 deltay = ymax - ymin;
231 private Site nextone ()
234 if ( siteidx < nsites )
243 private Edge bisect ( Site s1, Site s2 )
245 double dx, dy, adx, ady;
248 newedge =
new Edge();
253 newedge.ep [0] =
null;
254 newedge.ep[1] =
null;
256 dx = s2.Coord.X - s1.Coord.X;
257 dy = s2.Coord.Y - s1.Coord.Y;
259 adx = dx > 0 ? dx : -dx;
260 ady = dy > 0 ? dy : -dy;
261 newedge.c = (double)(s1.Coord.X * dx + s1.Coord.Y * dy + (dx * dx + dy* dy) * 0.5);
276 newedge.edgenbr = nedges;
282 private void makevertex ( Site v )
284 v.SiteNbr = nvertices;
288 private bool PQinitialize ()
292 PQhashsize = 4 * sqrt_nsites;
293 PQhash =
new Halfedge[ PQhashsize ];
295 for (
int i = 0; i < PQhashsize; i++ )
297 PQhash [i] =
new Halfedge();
302 private int PQbucket ( Halfedge he )
306 bucket = (int) ((he.ystar - ymin) / deltay * PQhashsize);
309 if ( bucket >= PQhashsize )
310 bucket = PQhashsize - 1;
311 if ( bucket < PQmin )
318 private void PQinsert ( Halfedge he, Site v,
double offset )
323 he.ystar = (double)(v.Coord.Y + offset);
324 last = PQhash [ PQbucket (he) ];
328 (next = last.PQnext) !=
null
330 (he.ystar > next.ystar || (he.ystar == next.ystar && v.Coord.X > next.vertex.Coord.X))
342 private void PQdelete ( Halfedge he )
346 if (he.vertex !=
null)
348 last = PQhash [ PQbucket (he) ];
349 while ( last.PQnext != he )
360 private bool PQempty ()
362 return ( PQcount == 0 );
365 private DoubleVector2 PQ_min ()
367 DoubleVector2 answer =
new DoubleVector2 ();
369 while ( PQhash[PQmin].PQnext ==
null )
379 private Halfedge PQextractmin ()
383 curr = PQhash[PQmin].
PQnext;
390 private Halfedge HEcreate(Edge e,
int pm)
392 Halfedge answer =
new Halfedge();
395 answer.PQnext =
null;
396 answer.vertex =
null;
401 private bool ELinitialize()
403 ELhashsize = 2 * sqrt_nsites;
404 ELhash =
new Halfedge[ELhashsize];
406 for (
int i = 0; i < ELhashsize; i++)
411 ELleftend = HEcreate (
null, 0 );
412 ELrightend = HEcreate (
null, 0 );
414 ELleftend.ELright = ELrightend;
415 ELrightend.
ELleft = ELleftend;
416 ELrightend.ELright =
null;
417 ELhash[0] = ELleftend;
418 ELhash[ELhashsize - 1] = ELrightend;
423 private Halfedge ELright( Halfedge he )
428 private Halfedge ELleft( Halfedge he )
433 private Site leftreg( Halfedge he )
435 if (he.ELedge ==
null)
439 return (he.ELpm == LE ? he.ELedge.reg[LE] : he.ELedge.reg[RE]);
442 private void ELinsert( Halfedge lb, Halfedge newHe )
445 newHe.ELright = lb.ELright;
446 (lb.ELright).ELleft = newHe;
454 private void ELdelete( Halfedge he )
456 (he.ELleft).ELright = he.ELright;
457 (he.ELright).ELleft = he.ELleft;
462 private Halfedge ELgethash(
int b )
465 if (b < 0 || b >= ELhashsize)
469 if (he ==
null || !he.deleted )
477 private Halfedge ELleftbnd( DoubleVector2 p )
485 bucket = (int) ((p.X - xmin) / deltax * ELhashsize);
489 if ( bucket < 0 ) bucket = 0;
490 if ( bucket >= ELhashsize ) bucket = ELhashsize - 1;
492 he = ELgethash ( bucket );
498 for (
int i = 1; i < ELhashsize; i++ )
500 if ( (he = ELgethash ( bucket - i ) ) !=
null )
502 if ( (he = ELgethash ( bucket + i ) ) !=
null )
508 if ( he == ELleftend || ( he != ELrightend && right_of (he, p) ) )
516 while ( he != ELrightend && right_of(he, p) );
527 while ( he != ELleftend && !right_of(he, p) );
531 if ( bucket > 0 && bucket < ELhashsize - 1)
539 private void pushGraphEdge( Site leftSite, Site rightSite, Vector2 point1, Vector2 point2 )
541 GraphEdge newEdge =
new GraphEdge(point1, point2);
542 allEdges.Add ( newEdge );
544 newEdge.Site1 = leftSite;
545 newEdge.Site2 = rightSite;
548 private void clip_line( Edge e )
550 double pxmin, pxmax, pymin, pymax;
553 double x1 = e.reg[0].Coord.X;
554 double y1 = e.reg[0].Coord.Y;
555 double x2 = e.reg[1].Coord.X;
556 double y2 = e.reg[1].Coord.Y;
562 if ( Math.Sqrt ( (x*x) + (y*y) ) < minDistanceBetweenSites )
571 if ( e.a == 1.0 && e.b >= 0.0 )
586 if ( s1 !=
null && s1.Coord.Y > pymin )
593 if ( s2 !=
null && s2.Coord.Y < pymax )
598 if ( ( (x1 > pxmax) & (x2 > pxmax) ) | ( (x1 < pxmin) & (x2 < pxmin) ) )
604 y1 = ( e.c - x1 ) / e.b;
609 y1 = ( e.c - x1 ) / e.b;
614 y2 = ( e.c - x2 ) / e.b;
619 y2 = ( e.c - x2 ) / e.b;
626 if ( s1 !=
null && s1.Coord.X > pxmin )
633 if ( s2 !=
null && s2.Coord.X < pxmax )
639 if (((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin)))
645 x1 = ( e.c - y1 ) / e.a;
650 x1 = ( e.c - y1 ) / e.a;
655 x2 = ( e.c - y2 ) / e.a;
660 x2 = ( e.c - y2 ) / e.a;
664 pushGraphEdge(e.reg[0], e.reg[1],
new Vector2((
float)x1, (
float)y1),
new Vector2((
float)x2, (
float)y2));
667 private void endpoint( Edge e,
int lr, Site s )
670 if ( e.ep[RE - lr] ==
null )
676 private bool right_of(Halfedge el, DoubleVector2 p)
682 double dxp, dyp, dxs, t1, t2, t3, yl;
687 if ( p.X > topsite.Coord.X )
688 right_of_site =
true;
690 right_of_site =
false;
692 if ( right_of_site && el.ELpm == LE )
694 if (!right_of_site && el.ELpm == RE )
699 dxp = p.X - topsite.Coord.X;
700 dyp = p.Y - topsite.Coord.Y;
703 if ( (!right_of_site & (e.b < 0.0)) | (right_of_site & (e.b >= 0.0)) )
705 above = dyp >= e.b * dxp;
710 above = p.X + p.Y * e.b > e.c;
718 dxs = topsite.Coord.X - ( e.reg[0] ).Coord.X;
719 above = e.b * (dxp * dxp - dyp * dyp)
720 < dxs * dyp * (1.0 + 2.0 * dxp / dxs + e.b * e.b);
728 yl = e.c - e.a * p.X;
730 t2 = p.X - topsite.Coord.X;
731 t3 = yl - topsite.Coord.Y;
732 above = t1 * t1 > t2 * t2 + t3 * t3;
734 return ( el.ELpm == LE ? above : !above );
737 private Site rightreg(Halfedge he)
739 if (he.ELedge == (Edge)
null)
748 return (he.ELpm == LE ? he.ELedge.reg[RE] : he.ELedge.reg[LE]);
751 private double dist( Site s, Site t )
754 dx = s.Coord.X - t.Coord.X;
755 dy = s.Coord.Y - t.Coord.Y;
756 return Math.Sqrt ( dx * dx + dy * dy );
761 private Site intersect( Halfedge el1, Halfedge el2 )
765 double d, xint, yint;
772 if ( e1 ==
null || e2 ==
null )
776 if ( e1.reg[1] == e2.reg[1] )
779 d = e1.a * e2.b - e1.b * e2.a;
780 if ( -1.0e-10 < d && d < 1.0e-10 )
783 xint = ( e1.c * e2.b - e2.c * e1.b ) / d;
784 yint = ( e2.c * e1.a - e1.c * e2.a ) / d;
786 if ( (e1.reg[1].Coord.Y < e2.reg[1].Coord.Y)
787 || (e1.reg[1].Coord.Y == e2.reg[1].Coord.Y && e1.reg[1].Coord.X < e2.reg[1].Coord.X) )
798 right_of_site = xint >= e.reg[1].Coord.X;
799 if ((right_of_site && el.ELpm == LE)
800 || (!right_of_site && el.ELpm == RE))
816 private bool voronoi_bd()
818 Site newsite, bot, top, temp, p;
820 DoubleVector2 newintstar =
null;
822 Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
828 bottomsite = nextone();
834 newintstar = PQ_min();
840 if (newsite !=
null && (PQempty()
841 || newsite.Coord.Y < newintstar.Y
842 || (newsite.Coord.Y == newintstar.Y
843 && newsite.Coord.X < newintstar.X)))
847 lbnd = ELleftbnd((newsite.Coord));
849 rbnd = ELright(lbnd);
852 bot = rightreg(lbnd);
854 e = bisect(bot, newsite);
857 bisector = HEcreate(e, LE);
860 ELinsert(lbnd, bisector);
864 if ((p = intersect(lbnd, bisector)) !=
null)
867 PQinsert(lbnd, p, dist(p, newsite));
871 bisector = HEcreate(e, RE);
874 ELinsert(lbnd, bisector);
877 if ((p = intersect(bisector, rbnd)) !=
null)
880 PQinsert(bisector, p, dist(p, newsite));
883 }
else if (!PQempty())
888 lbnd = PQextractmin();
890 llbnd = ELleft(lbnd);
892 rbnd = ELright(lbnd);
895 rrbnd = ELright(rbnd);
899 top = rightreg(rbnd);
904 endpoint(lbnd.ELedge, lbnd.ELpm, v);
907 endpoint(rbnd.ELedge, rbnd.ELpm, v);
920 if (bot.Coord.Y > top.Coord.Y)
930 e = bisect(bot, top);
933 bisector = HEcreate(e, pm);
936 ELinsert(llbnd, bisector);
938 endpoint(e, RE - pm, v);
946 if ((p = intersect(llbnd, bisector)) !=
null)
949 PQinsert(llbnd, p, dist(p, bot));
954 if ((p = intersect(bisector, rrbnd)) !=
null)
956 PQinsert(bisector, p, dist(p, bot));
964 for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd))
975 double[] xVal =
new double[sites.Count];
976 double[] yVal =
new double[sites.Count];
977 for (
int i = 0; i < sites.Count; i++)
979 xVal[i] = sites[i].X;
980 yVal[i] = sites[i].Y;
985 public List<GraphEdge>
MakeVoronoiGraph(
double[] xVal,
double[] yVal,
int width,
int height)
992 for (
int i = 0; i<xVal.Length;i++)
997 var graphEdges =
generateVoronoi(xVal, yVal, 0, area.Width, 0, area.Height);
998 HashSet<Site> sites =
new HashSet<Site>();
999 foreach (var graphEdge
in graphEdges)
1001 graphEdge.Point1 += area.Location.ToVector2();
1002 graphEdge.Point2 += area.Location.ToVector2();
1003 sites.Add(graphEdge.Site1);
1004 sites.Add(graphEdge.Site2);
1006 foreach (
Site site
in sites)
Voronoi(double minDistanceBetweenSites)
List< GraphEdge > generateVoronoi(double[] xValuesIn, double[] yValuesIn, double minX, double maxX, double minY, double maxY)
List< GraphEdge > MakeVoronoiGraph(double[] xVal, double[] yVal, Rectangle area)
List< GraphEdge > MakeVoronoiGraph(double[] xVal, double[] yVal, int width, int height)
List< GraphEdge > MakeVoronoiGraph(List< Vector2 > sites, int width, int height)