Client LuaCsForBarotrauma
Voronoi.cs
1 /*
2  * Created by SharpDevelop.
3  * User: Burhan
4  * Date: 17/06/2014
5  * Time: 11:30 م
6  *
7  * To change this template use Tools | Options | Coding | Edit Standard Headers.
8  */
9 
10 /*
11 * The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T
12 * Bell Laboratories.
13 * Permission to use, copy, modify, and distribute this software for any
14 * purpose without fee is hereby granted, provided that this entire notice
15 * is included in all copies of any software which is or includes a copy
16 * or modification of this software and in all copies of the supporting
17 * documentation for such software.
18 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
19 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
20 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
21 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
22 */
23 
24 /*
25  * This code was originally written by Stephan Fortune in C code. I, Shane O'Sullivan,
26  * have since modified it, encapsulating it in a C++ class and, fixing memory leaks and
27  * adding accessors to the Voronoi Edges.
28  * Permission to use, copy, modify, and distribute this software for any
29  * purpose without fee is hereby granted, provided that this entire notice
30  * is included in all copies of any software which is or includes a copy
31  * or modification of this software and in all copies of the supporting
32  * documentation for such software.
33  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
34  * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
35  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
36  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
37  */
38 
39 /*
40  * Java Version by Zhenyu Pan
41  * Permission to use, copy, modify, and distribute this software for any
42  * purpose without fee is hereby granted, provided that this entire notice
43  * is included in all copies of any software which is or includes a copy
44  * or modification of this software and in all copies of the supporting
45  * documentation for such software.
46  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
47  * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
48  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
49  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
50  */
51 
52 /*
53 * C# Version by Burhan Joukhadar
54 *
55 * Permission to use, copy, modify, and distribute this software for any
56 * purpose without fee is hereby granted, provided that this entire notice
57 * is included in all copies of any software which is or includes a copy
58 * or modification of this software and in all copies of the supporting
59 * documentation for such software.
60 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
61 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
62 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
63 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
64 */
65 
66 using Microsoft.Xna.Framework;
67 using System;
68 using System.Collections.Generic;
69 
70 namespace Voronoi2
71 {
75  public class Voronoi
76  {
77  // ************* Private members ******************
78  double borderMinX, borderMaxX, borderMinY, borderMaxY;
79  int siteidx;
80  double xmin, xmax, ymin, ymax, deltax, deltay;
81  int nvertices;
82  int nedges;
83  int nsites;
84  Site[] sites;
85  Site bottomsite;
86  int sqrt_nsites;
87  double minDistanceBetweenSites;
88  int PQcount;
89  int PQmin;
90  int PQhashsize;
91  Halfedge[] PQhash;
92 
93  const int LE = 0;
94  const int RE = 1;
95 
96  int ELhashsize;
97  Halfedge[] ELhash;
98  Halfedge ELleftend, ELrightend;
99  List<GraphEdge> allEdges;
100 
101 
102  // ************* Public methods ******************
103  // ******************************************
104 
105  // constructor
106  public Voronoi ( double minDistanceBetweenSites )
107  {
108  siteidx = 0;
109  sites = null;
110 
111  allEdges = null;
112  this.minDistanceBetweenSites = minDistanceBetweenSites;
113  }
114 
125  // تستدعى هذه العملية لإنشاء مخطط فورونوي
126  public List<GraphEdge> generateVoronoi ( double[] xValuesIn, double[] yValuesIn, double minX, double maxX, double minY, double maxY )
127  {
128  sort(xValuesIn, yValuesIn, xValuesIn.Length);
129 
130  // Check bounding box inputs - if mins are bigger than maxes, swap them
131  double temp = 0;
132  if ( minX > maxX )
133  {
134  temp = minX;
135  minX = maxX;
136  maxX = temp;
137  }
138  if ( minY > maxY )
139  {
140  temp = minY;
141  minY = maxY;
142  maxY = temp;
143  }
144 
145  borderMinX = minX;
146  borderMinY = minY;
147  borderMaxX = maxX;
148  borderMaxY = maxY;
149 
150  siteidx = 0;
151  voronoi_bd ();
152  return allEdges;
153  }
154 
155 
156  /*********************************************************
157  * Private methods - implementation details
158  ********************************************************/
159 
160  private void sort ( double[] xValuesIn, double[] yValuesIn, int count )
161  {
162  sites = null;
163  allEdges = new List<GraphEdge>();
164 
165  nsites = count;
166  nvertices = 0;
167  nedges = 0;
168 
169  double sn = (double)nsites + 4;
170  sqrt_nsites = (int) Math.Sqrt ( sn );
171 
172  // Copy the inputs so we don't modify the originals
173  double[] xValues = new double[count];
174  double[] yValues = new double[count];
175  for (int i = 0; i < count; i++)
176  {
177  xValues[i] = xValuesIn[i];
178  yValues[i] = yValuesIn[i];
179  }
180  sortNode ( xValues, yValues, count );
181  }
182 
183  private void qsort ( Site[] sites )
184  {
185  List<Site> listSites = new List<Site>( sites.Length );
186  for ( int i = 0; i < sites.Length; i++ )
187  {
188  listSites.Add ( sites[i] );
189  }
190 
191  listSites.Sort ( new SiteSorterYX () );
192 
193  // Copy back into the array
194  for (int i=0; i < sites.Length; i++)
195  {
196  sites[i] = listSites[i];
197  }
198  }
199 
200  private void sortNode ( double[] xValues, double[] yValues, int numPoints )
201  {
202  nsites = numPoints;
203  sites = new Site[nsites];
204  xmin = xValues[0];
205  ymin = yValues[0];
206  xmax = xValues[0];
207  ymax = yValues[0];
208 
209  for ( int i = 0; i < nsites; i++ )
210  {
211  sites[i] = new Site();
212  sites[i].Coord.SetPoint ( xValues[i], yValues[i] );
213  sites[i].SiteNbr = i;
214 
215  if ( xValues[i] < xmin )
216  xmin = xValues[i];
217  else if ( xValues[i] > xmax )
218  xmax = xValues[i];
219 
220  if ( yValues[i] < ymin )
221  ymin = yValues[i];
222  else if ( yValues[i] > ymax )
223  ymax = yValues[i];
224  }
225 
226  qsort ( sites );
227  deltax = xmax - xmin;
228  deltay = ymax - ymin;
229  }
230 
231  private Site nextone ()
232  {
233  Site s;
234  if ( siteidx < nsites )
235  {
236  s = sites[siteidx];
237  siteidx++;
238  return s;
239  }
240  return null;
241  }
242 
243  private Edge bisect ( Site s1, Site s2 )
244  {
245  double dx, dy, adx, ady;
246  Edge newedge;
247 
248  newedge = new Edge();
249 
250  newedge.reg[0] = s1;
251  newedge.reg[1] = s2;
252 
253  newedge.ep [0] = null;
254  newedge.ep[1] = null;
255 
256  dx = s2.Coord.X - s1.Coord.X;
257  dy = s2.Coord.Y - s1.Coord.Y;
258 
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);
262 
263  if ( adx > ady )
264  {
265  newedge.a = 1.0;
266  newedge.b = dy / dx;
267  newedge.c /= dx;
268  }
269  else
270  {
271  newedge.a = dx / dy;
272  newedge.b = 1.0;
273  newedge.c /= dy;
274  }
275 
276  newedge.edgenbr = nedges;
277  nedges++;
278 
279  return newedge;
280  }
281 
282  private void makevertex ( Site v )
283  {
284  v.SiteNbr = nvertices;
285  nvertices++;
286  }
287 
288  private bool PQinitialize ()
289  {
290  PQcount = 0;
291  PQmin = 0;
292  PQhashsize = 4 * sqrt_nsites;
293  PQhash = new Halfedge[ PQhashsize ];
294 
295  for ( int i = 0; i < PQhashsize; i++ )
296  {
297  PQhash [i] = new Halfedge();
298  }
299  return true;
300  }
301 
302  private int PQbucket ( Halfedge he )
303  {
304  int bucket;
305 
306  bucket = (int) ((he.ystar - ymin) / deltay * PQhashsize);
307  if ( bucket < 0 )
308  bucket = 0;
309  if ( bucket >= PQhashsize )
310  bucket = PQhashsize - 1;
311  if ( bucket < PQmin )
312  PQmin = bucket;
313 
314  return bucket;
315  }
316 
317  // push the HalfEdge into the ordered linked list of vertices
318  private void PQinsert ( Halfedge he, Site v, double offset )
319  {
320  Halfedge last, next;
321 
322  he.vertex = v;
323  he.ystar = (double)(v.Coord.Y + offset);
324  last = PQhash [ PQbucket (he) ];
325 
326  while
327  (
328  (next = last.PQnext) != null
329  &&
330  (he.ystar > next.ystar || (he.ystar == next.ystar && v.Coord.X > next.vertex.Coord.X))
331  )
332  {
333  last = next;
334  }
335 
336  he.PQnext = last.PQnext;
337  last.PQnext = he;
338  PQcount++;
339  }
340 
341  // remove the HalfEdge from the list of vertices
342  private void PQdelete ( Halfedge he )
343  {
344  Halfedge last;
345 
346  if (he.vertex != null)
347  {
348  last = PQhash [ PQbucket (he) ];
349  while ( last.PQnext != he )
350  {
351  last = last.PQnext;
352  }
353 
354  last.PQnext = he.PQnext;
355  PQcount--;
356  he.vertex = null;
357  }
358  }
359 
360  private bool PQempty ()
361  {
362  return ( PQcount == 0 );
363  }
364 
365  private DoubleVector2 PQ_min ()
366  {
367  DoubleVector2 answer = new DoubleVector2 ();
368 
369  while ( PQhash[PQmin].PQnext == null )
370  {
371  PQmin++;
372  }
373 
374  answer.X = PQhash[PQmin].PQnext.vertex.Coord.X;
375  answer.Y = PQhash[PQmin].PQnext.ystar;
376  return answer;
377  }
378 
379  private Halfedge PQextractmin ()
380  {
381  Halfedge curr;
382 
383  curr = PQhash[PQmin].PQnext;
384  PQhash[PQmin].PQnext = curr.PQnext;
385  PQcount--;
386 
387  return curr;
388  }
389 
390  private Halfedge HEcreate(Edge e, int pm)
391  {
392  Halfedge answer = new Halfedge();
393  answer.ELedge = e;
394  answer.ELpm = pm;
395  answer.PQnext = null;
396  answer.vertex = null;
397 
398  return answer;
399  }
400 
401  private bool ELinitialize()
402  {
403  ELhashsize = 2 * sqrt_nsites;
404  ELhash = new Halfedge[ELhashsize];
405 
406  for (int i = 0; i < ELhashsize; i++)
407  {
408  ELhash[i] = null;
409  }
410 
411  ELleftend = HEcreate ( null, 0 );
412  ELrightend = HEcreate ( null, 0 );
413  ELleftend.ELleft = null;
414  ELleftend.ELright = ELrightend;
415  ELrightend.ELleft = ELleftend;
416  ELrightend.ELright = null;
417  ELhash[0] = ELleftend;
418  ELhash[ELhashsize - 1] = ELrightend;
419 
420  return true;
421  }
422 
423  private Halfedge ELright( Halfedge he )
424  {
425  return he.ELright;
426  }
427 
428  private Halfedge ELleft( Halfedge he )
429  {
430  return he.ELleft;
431  }
432 
433  private Site leftreg( Halfedge he )
434  {
435  if (he.ELedge == null)
436  {
437  return bottomsite;
438  }
439  return (he.ELpm == LE ? he.ELedge.reg[LE] : he.ELedge.reg[RE]);
440  }
441 
442  private void ELinsert( Halfedge lb, Halfedge newHe )
443  {
444  newHe.ELleft = lb;
445  newHe.ELright = lb.ELright;
446  (lb.ELright).ELleft = newHe;
447  lb.ELright = newHe;
448  }
449 
450  /*
451  * This delete routine can't reclaim node, since pointers from hash table
452  * may be present.
453  */
454  private void ELdelete( Halfedge he )
455  {
456  (he.ELleft).ELright = he.ELright;
457  (he.ELright).ELleft = he.ELleft;
458  he.deleted = true;
459  }
460 
461  /* Get entry from hash table, pruning any deleted nodes */
462  private Halfedge ELgethash( int b )
463  {
464  Halfedge he;
465  if (b < 0 || b >= ELhashsize)
466  return null;
467 
468  he = ELhash[b];
469  if (he == null || !he.deleted )
470  return he;
471 
472  /* Hash table points to deleted half edge. Patch as necessary. */
473  ELhash[b] = null;
474  return null;
475  }
476 
477  private Halfedge ELleftbnd( DoubleVector2 p )
478  {
479  int bucket;
480  Halfedge he;
481 
482  /* Use hash table to get close to desired halfedge */
483  // use the hash function to find the place in the hash map that this
484  // HalfEdge should be
485  bucket = (int) ((p.X - xmin) / deltax * ELhashsize);
486 
487  // make sure that the bucket position is within the range of the hash
488  // array
489  if ( bucket < 0 ) bucket = 0;
490  if ( bucket >= ELhashsize ) bucket = ELhashsize - 1;
491 
492  he = ELgethash ( bucket );
493 
494  // if the HE isn't found, search backwards and forwards in the hash map
495  // for the first non-null entry
496  if ( he == null )
497  {
498  for ( int i = 1; i < ELhashsize; i++ )
499  {
500  if ( (he = ELgethash ( bucket - i ) ) != null )
501  break;
502  if ( (he = ELgethash ( bucket + i ) ) != null )
503  break;
504  }
505  }
506 
507  /* Now search linear list of halfedges for the correct one */
508  if ( he == ELleftend || ( he != ELrightend && right_of (he, p) ) )
509  {
510  // keep going right on the list until either the end is reached, or
511  // you find the 1st edge which the point isn't to the right of
512  do
513  {
514  he = he.ELright;
515  }
516  while ( he != ELrightend && right_of(he, p) );
517  he = he.ELleft;
518  }
519  else
520  // if the point is to the left of the HalfEdge, then search left for
521  // the HE just to the left of the point
522  {
523  do
524  {
525  he = he.ELleft;
526  }
527  while ( he != ELleftend && !right_of(he, p) );
528  }
529 
530  /* Update hash table and reference counts */
531  if ( bucket > 0 && bucket < ELhashsize - 1)
532  {
533  ELhash[bucket] = he;
534  }
535 
536  return he;
537  }
538 
539  private void pushGraphEdge( Site leftSite, Site rightSite, Vector2 point1, Vector2 point2 )
540  {
541  GraphEdge newEdge = new GraphEdge(point1, point2);
542  allEdges.Add ( newEdge );
543 
544  newEdge.Site1 = leftSite;
545  newEdge.Site2 = rightSite;
546  }
547 
548  private void clip_line( Edge e )
549  {
550  double pxmin, pxmax, pymin, pymax;
551  Site s1, s2;
552 
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;
557  double x = x2- x1;
558  double y = y2 - y1;
559 
560  // if the distance between the two points this line was created from is
561  // less than the square root of 2 عن جد؟, then ignore it
562  if ( Math.Sqrt ( (x*x) + (y*y) ) < minDistanceBetweenSites )
563  {
564  return;
565  }
566  pxmin = borderMinX;
567  pymin = borderMinY;
568  pxmax = borderMaxX;
569  pymax = borderMaxY;
570 
571  if ( e.a == 1.0 && e.b >= 0.0 )
572  {
573  s1 = e.ep[1];
574  s2 = e.ep[0];
575  }
576  else
577  {
578  s1 = e.ep[0];
579  s2 = e.ep[1];
580  }
581 
582  if ( e.a == 1.0 )
583  {
584  y1 = pymin;
585 
586  if ( s1 != null && s1.Coord.Y > pymin )
587  y1 = s1.Coord.Y;
588  if ( y1 > pymax )
589  y1 = pymax;
590  x1 = e.c - e.b * y1;
591  y2 = pymax;
592 
593  if ( s2 != null && s2.Coord.Y < pymax )
594  y2 = s2.Coord.Y;
595  if ( y2 < pymin )
596  y2 = pymin;
597  x2 = e.c - e.b * y2;
598  if ( ( (x1 > pxmax) & (x2 > pxmax) ) | ( (x1 < pxmin) & (x2 < pxmin) ) )
599  return;
600 
601  if ( x1 > pxmax )
602  {
603  x1 = pxmax;
604  y1 = ( e.c - x1 ) / e.b;
605  }
606  if ( x1 < pxmin )
607  {
608  x1 = pxmin;
609  y1 = ( e.c - x1 ) / e.b;
610  }
611  if ( x2 > pxmax )
612  {
613  x2 = pxmax;
614  y2 = ( e.c - x2 ) / e.b;
615  }
616  if ( x2 < pxmin )
617  {
618  x2 = pxmin;
619  y2 = ( e.c - x2 ) / e.b;
620  }
621 
622  }
623  else
624  {
625  x1 = pxmin;
626  if ( s1 != null && s1.Coord.X > pxmin )
627  x1 = s1.Coord.X;
628  if ( x1 > pxmax )
629  x1 = pxmax;
630  y1 = e.c - e.a * x1;
631 
632  x2 = pxmax;
633  if ( s2 != null && s2.Coord.X < pxmax )
634  x2 = s2.Coord.X;
635  if ( x2 < pxmin )
636  x2 = pxmin;
637  y2 = e.c - e.a * x2;
638 
639  if (((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin)))
640  return;
641 
642  if ( y1 > pymax )
643  {
644  y1 = pymax;
645  x1 = ( e.c - y1 ) / e.a;
646  }
647  if ( y1 < pymin )
648  {
649  y1 = pymin;
650  x1 = ( e.c - y1 ) / e.a;
651  }
652  if ( y2 > pymax )
653  {
654  y2 = pymax;
655  x2 = ( e.c - y2 ) / e.a;
656  }
657  if ( y2 < pymin )
658  {
659  y2 = pymin;
660  x2 = ( e.c - y2 ) / e.a;
661  }
662  }
663 
664  pushGraphEdge(e.reg[0], e.reg[1], new Vector2((float)x1, (float)y1), new Vector2((float)x2, (float)y2));
665  }
666 
667  private void endpoint( Edge e, int lr, Site s )
668  {
669  e.ep[lr] = s;
670  if ( e.ep[RE - lr] == null )
671  return;
672  clip_line ( e );
673  }
674 
675  /* returns true if p is to right of halfedge e */
676  private bool right_of(Halfedge el, DoubleVector2 p)
677  {
678  Edge e;
679  Site topsite;
680  bool right_of_site;
681  bool above, fast;
682  double dxp, dyp, dxs, t1, t2, t3, yl;
683 
684  e = el.ELedge;
685  topsite = e.reg[1];
686 
687  if ( p.X > topsite.Coord.X )
688  right_of_site = true;
689  else
690  right_of_site = false;
691 
692  if ( right_of_site && el.ELpm == LE )
693  return true;
694  if (!right_of_site && el.ELpm == RE )
695  return false;
696 
697  if ( e.a == 1.0 )
698  {
699  dxp = p.X - topsite.Coord.X;
700  dyp = p.Y - topsite.Coord.Y;
701  fast = false;
702 
703  if ( (!right_of_site & (e.b < 0.0)) | (right_of_site & (e.b >= 0.0)) )
704  {
705  above = dyp >= e.b * dxp;
706  fast = above;
707  }
708  else
709  {
710  above = p.X + p.Y * e.b > e.c;
711  if ( e.b < 0.0 )
712  above = !above;
713  if ( !above )
714  fast = true;
715  }
716  if ( !fast )
717  {
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);
721 
722  if ( e.b < 0 )
723  above = !above;
724  }
725  }
726  else // e.b == 1.0
727  {
728  yl = e.c - e.a * p.X;
729  t1 = p.Y - yl;
730  t2 = p.X - topsite.Coord.X;
731  t3 = yl - topsite.Coord.Y;
732  above = t1 * t1 > t2 * t2 + t3 * t3;
733  }
734  return ( el.ELpm == LE ? above : !above );
735  }
736 
737  private Site rightreg(Halfedge he)
738  {
739  if (he.ELedge == (Edge) null)
740  // if this halfedge has no edge, return the bottom site (whatever
741  // that is)
742  {
743  return (bottomsite);
744  }
745 
746  // if the ELpm field is zero, return the site 0 that this edge bisects,
747  // otherwise return site number 1
748  return (he.ELpm == LE ? he.ELedge.reg[RE] : he.ELedge.reg[LE]);
749  }
750 
751  private double dist( Site s, Site t )
752  {
753  double dx, dy;
754  dx = s.Coord.X - t.Coord.X;
755  dy = s.Coord.Y - t.Coord.Y;
756  return Math.Sqrt ( dx * dx + dy * dy );
757  }
758 
759  // create a new site where the HalfEdges el1 and el2 intersect - note that
760  // the Point in the argument list is not used, don't know why it's there
761  private Site intersect( Halfedge el1, Halfedge el2 )
762  {
763  Edge e1, e2, e;
764  Halfedge el;
765  double d, xint, yint;
766  bool right_of_site;
767  Site v; // vertex
768 
769  e1 = el1.ELedge;
770  e2 = el2.ELedge;
771 
772  if ( e1 == null || e2 == null )
773  return null;
774 
775  // if the two edges bisect the same parent, return null
776  if ( e1.reg[1] == e2.reg[1] )
777  return null;
778 
779  d = e1.a * e2.b - e1.b * e2.a;
780  if ( -1.0e-10 < d && d < 1.0e-10 )
781  return null;
782 
783  xint = ( e1.c * e2.b - e2.c * e1.b ) / d;
784  yint = ( e2.c * e1.a - e1.c * e2.a ) / d;
785 
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) )
788  {
789  el = el1;
790  e = e1;
791  }
792  else
793  {
794  el = el2;
795  e = e2;
796  }
797 
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))
801  return null;
802 
803  // create a new site at the point of intersection - this is a new vector
804  // event waiting to happen
805  v = new Site();
806  v.Coord.X = xint;
807  v.Coord.Y = yint;
808  return v;
809  }
810 
811  /*
812  * implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax, deltax,
813  * deltay (can all be estimates). Performance suffers if they are wrong;
814  * better to make nsites, deltax, and deltay too big than too small. (?)
815  */
816  private bool voronoi_bd()
817  {
818  Site newsite, bot, top, temp, p;
819  Site v;
820  DoubleVector2 newintstar = null;
821  int pm;
822  Halfedge lbnd, rbnd, llbnd, rrbnd, bisector;
823  Edge e;
824 
825  PQinitialize();
826  ELinitialize();
827 
828  bottomsite = nextone();
829  newsite = nextone();
830  while (true)
831  {
832  if (!PQempty())
833  {
834  newintstar = PQ_min();
835  }
836  // if the lowest site has a smaller y value than the lowest vector
837  // intersection,
838  // process the site otherwise process the vector intersection
839 
840  if (newsite != null && (PQempty()
841  || newsite.Coord.Y < newintstar.Y
842  || (newsite.Coord.Y == newintstar.Y
843  && newsite.Coord.X < newintstar.X)))
844  {
845  /* new site is smallest -this is a site event */
846  // get the first HalfEdge to the LEFT of the new site
847  lbnd = ELleftbnd((newsite.Coord));
848  // get the first HalfEdge to the RIGHT of the new site
849  rbnd = ELright(lbnd);
850  // if this halfedge has no edge,bot =bottom site (whatever that
851  // is)
852  bot = rightreg(lbnd);
853  // create a new edge that bisects
854  e = bisect(bot, newsite);
855 
856  // create a new HalfEdge, setting its ELpm field to 0
857  bisector = HEcreate(e, LE);
858  // insert this new bisector edge between the left and right
859  // vectors in a linked list
860  ELinsert(lbnd, bisector);
861 
862  // if the new bisector intersects with the left edge,
863  // remove the left edge's vertex, and put in the new one
864  if ((p = intersect(lbnd, bisector)) != null)
865  {
866  PQdelete(lbnd);
867  PQinsert(lbnd, p, dist(p, newsite));
868  }
869  lbnd = bisector;
870  // create a new HalfEdge, setting its ELpm field to 1
871  bisector = HEcreate(e, RE);
872  // insert the new HE to the right of the original bisector
873  // earlier in the IF stmt
874  ELinsert(lbnd, bisector);
875 
876  // if this new bisector intersects with the new HalfEdge
877  if ((p = intersect(bisector, rbnd)) != null)
878  {
879  // push the HE into the ordered linked list of vertices
880  PQinsert(bisector, p, dist(p, newsite));
881  }
882  newsite = nextone();
883  } else if (!PQempty())
884  /* intersection is smallest - this is a vector event */
885  {
886  // pop the HalfEdge with the lowest vector off the ordered list
887  // of vectors
888  lbnd = PQextractmin();
889  // get the HalfEdge to the left of the above HE
890  llbnd = ELleft(lbnd);
891  // get the HalfEdge to the right of the above HE
892  rbnd = ELright(lbnd);
893  // get the HalfEdge to the right of the HE to the right of the
894  // lowest HE
895  rrbnd = ELright(rbnd);
896  // get the Site to the left of the left HE which it bisects
897  bot = leftreg(lbnd);
898  // get the Site to the right of the right HE which it bisects
899  top = rightreg(rbnd);
900 
901  v = lbnd.vertex; // get the vertex that caused this event
902  makevertex(v); // set the vertex number - couldn't do this
903  // earlier since we didn't know when it would be processed
904  endpoint(lbnd.ELedge, lbnd.ELpm, v);
905  // set the endpoint of
906  // the left HalfEdge to be this vector
907  endpoint(rbnd.ELedge, rbnd.ELpm, v);
908  // set the endpoint of the right HalfEdge to
909  // be this vector
910  ELdelete(lbnd); // mark the lowest HE for
911  // deletion - can't delete yet because there might be pointers
912  // to it in Hash Map
913  PQdelete(rbnd);
914  // remove all vertex events to do with the right HE
915  ELdelete(rbnd); // mark the right HE for
916  // deletion - can't delete yet because there might be pointers
917  // to it in Hash Map
918  pm = LE; // set the pm variable to zero
919 
920  if (bot.Coord.Y > top.Coord.Y)
921  // if the site to the left of the event is higher than the
922  // Site
923  { // to the right of it, then swap them and set the 'pm'
924  // variable to 1
925  temp = bot;
926  bot = top;
927  top = temp;
928  pm = RE;
929  }
930  e = bisect(bot, top); // create an Edge (or line)
931  // that is between the two Sites. This creates the formula of
932  // the line, and assigns a line number to it
933  bisector = HEcreate(e, pm); // create a HE from the Edge 'e',
934  // and make it point to that edge
935  // with its ELedge field
936  ELinsert(llbnd, bisector); // insert the new bisector to the
937  // right of the left HE
938  endpoint(e, RE - pm, v); // set one endpoint to the new edge
939  // to be the vector point 'v'.
940  // If the site to the left of this bisector is higher than the
941  // right Site, then this endpoint
942  // is put in position 0; otherwise in pos 1
943 
944  // if left HE and the new bisector intersect, then delete
945  // the left HE, and reinsert it
946  if ((p = intersect(llbnd, bisector)) != null)
947  {
948  PQdelete(llbnd);
949  PQinsert(llbnd, p, dist(p, bot));
950  }
951 
952  // if right HE and the new bisector intersect, then
953  // reinsert it
954  if ((p = intersect(bisector, rrbnd)) != null)
955  {
956  PQinsert(bisector, p, dist(p, bot));
957  }
958  } else
959  {
960  break;
961  }
962  }
963 
964  for (lbnd = ELright(ELleftend); lbnd != ELrightend; lbnd = ELright(lbnd))
965  {
966  e = lbnd.ELedge;
967  clip_line(e);
968  }
969 
970  return true;
971  }
972 
973  public List<GraphEdge> MakeVoronoiGraph(List<Vector2> sites, int width, int height)
974  {
975  double[] xVal = new double[sites.Count];
976  double[] yVal = new double[sites.Count];
977  for (int i = 0; i < sites.Count; i++)
978  {
979  xVal[i] = sites[i].X;
980  yVal[i] = sites[i].Y;
981  }
982  return generateVoronoi(xVal, yVal, 0, width, 0, height);
983  }
984 
985  public List<GraphEdge> MakeVoronoiGraph(double[] xVal, double[] yVal, int width, int height)
986  {
987  return generateVoronoi(xVal, yVal, 0, width, 0, height);
988  }
989 
990  public List<GraphEdge> MakeVoronoiGraph(double[] xVal, double[] yVal, Rectangle area)
991  {
992  for (int i = 0; i<xVal.Length;i++)
993  {
994  xVal[i] -= area.X;
995  yVal[i] -= area.Y;
996  }
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)
1000  {
1001  graphEdge.Point1 += area.Location.ToVector2();
1002  graphEdge.Point2 += area.Location.ToVector2();
1003  sites.Add(graphEdge.Site1);
1004  sites.Add(graphEdge.Site2);
1005  }
1006  foreach (Site site in sites)
1007  {
1008  site.Coord = new DoubleVector2(site.Coord.X + area.Location.X, site.Coord.Y + area.Location.Y);
1009  }
1010  return graphEdges;
1011  }
1012 
1013  } // Voronoi Class End
1014 } // namespace Voronoi2 End
DoubleVector2 Coord
Description of Voronoi.
Definition: Voronoi.cs:76
Voronoi(double minDistanceBetweenSites)
Definition: Voronoi.cs:106
List< GraphEdge > generateVoronoi(double[] xValuesIn, double[] yValuesIn, double minX, double maxX, double minY, double maxY)
Definition: Voronoi.cs:126
List< GraphEdge > MakeVoronoiGraph(double[] xVal, double[] yVal, Rectangle area)
Definition: Voronoi.cs:990
List< GraphEdge > MakeVoronoiGraph(double[] xVal, double[] yVal, int width, int height)
Definition: Voronoi.cs:985
List< GraphEdge > MakeVoronoiGraph(List< Vector2 > sites, int width, int height)
Definition: Voronoi.cs:973