2 * The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T
\r
4 * Permission to use, copy, modify, and distribute this software for any
\r
5 * purpose without fee is hereby granted, provided that this entire notice
\r
6 * is included in all copies of any software which is or includes a copy
\r
7 * or modification of this software and in all copies of the supporting
\r
8 * documentation for such software.
\r
9 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
\r
10 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
\r
11 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
\r
12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
\r
16 * This code was originally written by Stephan Fortune in C code. I, Shane O'Sullivan,
\r
17 * have since modified it, encapsulating it in a C++ class and, fixing memory leaks and
\r
18 * adding accessors to the Voronoi Edges.
\r
19 * Permission to use, copy, modify, and distribute this software for any
\r
20 * purpose without fee is hereby granted, provided that this entire notice
\r
21 * is included in all copies of any software which is or includes a copy
\r
22 * or modification of this software and in all copies of the supporting
\r
23 * documentation for such software.
\r
24 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
\r
25 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
\r
26 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
\r
27 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
\r
30 #include "VoronoiDiagramGenerator.h"
\r
32 #include <sys/mman.h>
\r
34 VoronoiDiagramGenerator::VoronoiDiagramGenerator()
\r
39 allMemoryList = new FreeNodeArrayList;
\r
40 allMemoryList->memory = 0;
\r
41 allMemoryList->next = 0;
\r
42 currentMemoryBlock = allMemoryList;
\r
45 minDistanceBetweenSites = 0;
\r
48 VoronoiDiagramGenerator::~VoronoiDiagramGenerator()
\r
53 if(allMemoryList != 0)
\r
54 delete allMemoryList;
\r
57 bool VoronoiDiagramGenerator::generateVoronoi(struct SourcePoint* srcPoints, int numPoints, float minX, float maxX, float minY, float maxY, float minDist)
\r
63 minDistanceBetweenSites = minDist;
\r
70 freeinit(&sfl, sizeof (Site));
\r
72 sites = (struct Site *) myalloc(nsites * sizeof(*sites));
\r
73 polygons = (struct Polygon *) myalloc(nsites * sizeof(*polygons));
\r
75 if(sites == 0) return false;
\r
77 xmin = srcPoints[0].x;
\r
78 ymin = srcPoints[0].y;
\r
79 xmax = srcPoints[0].x;
\r
80 ymax = srcPoints[0].y;
\r
82 for(i = 0; i < nsites; i++)
\r
84 sites[i].coord.x = srcPoints[i].x;
\r
85 sites[i].coord.y = srcPoints[i].y;
\r
86 sites[i].weight = srcPoints[i].weight;
\r
87 sites[i].sitenbr = i;
\r
88 sites[i].refcnt = 0; // prevent reuse?
\r
90 if(sites[i].coord.x < xmin)
\r
91 xmin = sites[i].coord.x;
\r
92 else if(sites[i].coord.x > xmax)
\r
93 xmax = sites[i].coord.x;
\r
95 if(sites[i].coord.y < ymin)
\r
96 ymin = sites[i].coord.y;
\r
97 else if(sites[i].coord.y > ymax)
\r
98 ymax = sites[i].coord.y;
\r
100 polygons[i].coord.x = sites[i].coord.x;
\r
101 polygons[i].coord.y = sites[i].coord.y;
\r
102 polygons[i].numpoints = 0;
\r
103 polygons[i].pointlist = NULL;
\r
104 polygons[i].boundary = 0;
\r
106 //printf("\n%lf %lf\n", sites[i].coord.x, sites[i].coord.y);
\r
109 qsort(sites, nsites, sizeof (*sites), scomp);
\r
131 corners[0].x = borderMinX;
\r
132 corners[0].y = borderMinY;
\r
133 corners[1].x = borderMinX;
\r
134 corners[1].y = borderMaxY;
\r
135 corners[2].x = borderMaxX;
\r
136 corners[2].y = borderMaxY;
\r
137 corners[3].x = borderMaxX;
\r
138 corners[3].y = borderMinY;
\r
141 voronoi(triangulate);
\r
146 bool VoronoiDiagramGenerator::ELinitialize()
\r
149 freeinit(&hfl, sizeof **ELhash);
\r
150 ELhashsize = 2 * sqrt_nsites;
\r
151 ELhash = (struct Halfedge **) myalloc ( sizeof *ELhash * ELhashsize);
\r
156 for(i=0; i<ELhashsize; i +=1) ELhash[i] = (struct Halfedge *)NULL;
\r
157 ELleftend = HEcreate( (struct Edge *)NULL, 0);
\r
158 ELrightend = HEcreate( (struct Edge *)NULL, 0);
\r
159 ELleftend -> ELleft = (struct Halfedge *)NULL;
\r
160 ELleftend -> ELright = ELrightend;
\r
161 ELrightend -> ELleft = ELleftend;
\r
162 ELrightend -> ELright = (struct Halfedge *)NULL;
\r
163 ELhash[0] = ELleftend;
\r
164 ELhash[ELhashsize-1] = ELrightend;
\r
170 struct Halfedge* VoronoiDiagramGenerator::HEcreate(struct Edge *e,int pm)
\r
172 struct Halfedge *answer;
\r
173 answer = (struct Halfedge *) getfree(&hfl);
\r
174 answer -> ELedge = e;
\r
175 answer -> ELpm = pm;
\r
176 answer -> PQnext = (struct Halfedge *) NULL;
\r
177 answer -> vertex = (struct Site *) NULL;
\r
178 answer -> ELrefcnt = 0;
\r
183 void VoronoiDiagramGenerator::ELinsert(struct Halfedge *lb, struct Halfedge *newHe)
\r
185 newHe -> ELleft = lb;
\r
186 newHe -> ELright = lb -> ELright;
\r
187 (lb -> ELright) -> ELleft = newHe;
\r
188 lb -> ELright = newHe;
\r
191 /* Get entry from hash table, pruning any deleted nodes */
\r
192 struct Halfedge * VoronoiDiagramGenerator::ELgethash(int b)
\r
194 struct Halfedge *he;
\r
196 if(b<0 || b>=ELhashsize)
\r
197 return((struct Halfedge *) NULL);
\r
199 if (he == (struct Halfedge *) NULL || he->ELedge != (struct Edge *) DELETED )
\r
202 /* Hash table points to deleted half edge. Patch as necessary. */
\r
203 ELhash[b] = (struct Halfedge *) NULL;
\r
204 if ((he -> ELrefcnt -= 1) == 0)
\r
205 makefree((Freenode*)he, &hfl);
\r
206 return ((struct Halfedge *) NULL);
\r
209 struct Halfedge * VoronoiDiagramGenerator::ELleftbnd(struct Point *p)
\r
212 struct Halfedge *he;
\r
214 /* Use hash table to get close to desired halfedge */
\r
215 bucket = (int)((p->x - xmin)/deltax * ELhashsize); //use the hash function to find the place in the hash map that this HalfEdge should be
\r
217 if(bucket<0) bucket =0; //make sure that the bucket position in within the range of the hash array
\r
218 if(bucket>=ELhashsize) bucket = ELhashsize - 1;
\r
220 he = ELgethash(bucket);
\r
221 if(he == (struct Halfedge *) NULL) //if the HE isn't found, search backwards and forwards in the hash map for the first non-null entry
\r
223 for(i=1; 1 ; i += 1)
\r
225 if ((he=ELgethash(bucket-i)) != (struct Halfedge *) NULL)
\r
227 if ((he=ELgethash(bucket+i)) != (struct Halfedge *) NULL)
\r
233 /* Now search linear list of halfedges for the correct one */
\r
234 if (he==ELleftend || (he != ELrightend && right_of(he,p)))
\r
238 he = he -> ELright;
\r
239 } while (he!=ELrightend && right_of(he,p)); //keep going right on the list until either the end is reached, or you find the 1st edge which the point
\r
240 he = he -> ELleft; //isn't to the right of
\r
242 else //if the point is to the left of the HalfEdge, then search left for the HE just to the left of the point
\r
246 } while (he!=ELleftend && !right_of(he,p));
\r
248 /* Update hash table and reference counts */
\r
249 if(bucket > 0 && bucket <ELhashsize-1)
\r
251 if(ELhash[bucket] != (struct Halfedge *) NULL)
\r
253 ELhash[bucket] -> ELrefcnt -= 1;
\r
255 ELhash[bucket] = he;
\r
256 ELhash[bucket] -> ELrefcnt += 1;
\r
262 /* This delete routine can't reclaim node, since pointers from hash
\r
263 table may be present. */
\r
264 void VoronoiDiagramGenerator::ELdelete(struct Halfedge *he)
\r
266 (he -> ELleft) -> ELright = he -> ELright;
\r
267 (he -> ELright) -> ELleft = he -> ELleft;
\r
268 he -> ELedge = (struct Edge *)DELETED;
\r
272 struct Halfedge * VoronoiDiagramGenerator::ELright(struct Halfedge *he)
\r
274 return (he -> ELright);
\r
277 struct Halfedge * VoronoiDiagramGenerator::ELleft(struct Halfedge *he)
\r
279 return (he -> ELleft);
\r
283 struct Site * VoronoiDiagramGenerator::leftreg(struct Halfedge *he)
\r
285 if(he -> ELedge == (struct Edge *)NULL)
\r
286 return(bottomsite);
\r
287 return( he -> ELpm == le ?
\r
288 he -> ELedge -> reg[le] : he -> ELedge -> reg[re]);
\r
291 struct Site * VoronoiDiagramGenerator::rightreg(struct Halfedge *he)
\r
293 if(he -> ELedge == (struct Edge *)NULL) //if this halfedge has no edge, return the bottom site (whatever that is)
\r
294 return(bottomsite);
\r
296 //if the ELpm field is zero, return the site 0 that this edge bisects, otherwise return site number 1
\r
297 return( he -> ELpm == le ? he -> ELedge -> reg[re] : he -> ELedge -> reg[le]);
\r
300 void VoronoiDiagramGenerator::geominit()
\r
304 freeinit(&efl, sizeof(Edge));
\r
307 sn = (float)nsites+4;
\r
308 sqrt_nsites = (int)sqrt(sn);
\r
309 deltay = ymax - ymin;
\r
310 deltax = xmax - xmin;
\r
314 struct Edge * VoronoiDiagramGenerator::bisect(struct Site *s1,struct Site *s2)
\r
316 float dx,dy,adx,ady;
\r
317 struct Edge *newedge;
\r
319 newedge = (struct Edge *) getfree(&efl);
\r
321 newedge -> reg[0] = s1; //store the sites that this edge is bisecting
\r
322 newedge -> reg[1] = s2;
\r
325 newedge -> ep[0] = (struct Site *) NULL; //to begin with, there are no endpoints on the bisector - it goes to infinity
\r
326 newedge -> ep[1] = (struct Site *) NULL;
\r
328 dx = s2->coord.x - s1->coord.x; //get the difference in x dist between the sites
\r
329 dy = s2->coord.y - s1->coord.y;
\r
330 adx = dx>0 ? dx : -dx; //make sure that the difference in positive
\r
331 ady = dy>0 ? dy : -dy;
\r
332 newedge -> c = (float)(s1->coord.x * dx + s1->coord.y * dy + (dx*dx + dy*dy)*0.5);//get the slope of the line
\r
336 newedge -> a = 1.0; newedge -> b = dy/dx; newedge -> c /= dx;//set formula of line, with x fixed to 1
\r
340 newedge -> b = 1.0; newedge -> a = dx/dy; newedge -> c /= dy;//set formula of line, with y fixed to 1
\r
343 newedge -> edgenbr = nedges;
\r
345 //printf("\nbisect(%d) ((%f,%f) and (%f,%f)",nedges,s1->coord.x,s1->coord.y,s2->coord.x,s2->coord.y);
\r
351 //create a new site where the HalfEdges el1 and el2 intersect - note that the Point in the argument list is not used, don't know why it's there
\r
352 struct Site * VoronoiDiagramGenerator::intersect(struct Halfedge *el1, struct Halfedge *el2, struct Point *p)
\r
354 struct Edge *e1,*e2, *e;
\r
355 struct Halfedge *el;
\r
356 float d, xint, yint;
\r
360 e1 = el1 -> ELedge;
\r
361 e2 = el2 -> ELedge;
\r
362 if(e1 == (struct Edge*)NULL || e2 == (struct Edge*)NULL)
\r
363 return ((struct Site *) NULL);
\r
365 //if the two edges bisect the same parent, return null
\r
366 if (e1->reg[1] == e2->reg[1])
\r
367 return ((struct Site *) NULL);
\r
369 d = e1->a * e2->b - e1->b * e2->a;
\r
370 if (-1.0e-10<d && d<1.0e-10)
\r
371 return ((struct Site *) NULL);
\r
373 xint = (e1->c*e2->b - e2->c*e1->b)/d;
\r
374 yint = (e2->c*e1->a - e1->c*e2->a)/d;
\r
376 if( (e1->reg[1]->coord.y < e2->reg[1]->coord.y) ||
\r
377 (e1->reg[1]->coord.y == e2->reg[1]->coord.y &&
\r
378 e1->reg[1]->coord.x < e2->reg[1]->coord.x) )
\r
389 right_of_site = xint >= e -> reg[1] -> coord.x;
\r
390 if ((right_of_site && el -> ELpm == le) || (!right_of_site && el -> ELpm == re))
\r
391 return ((struct Site *) NULL);
\r
393 //create a new site at the point of intersection - this is a new vector event waiting to happen
\r
394 v = (struct Site *) getfree(&sfl);
\r
396 v -> coord.x = xint;
\r
397 v -> coord.y = yint;
\r
401 /* returns 1 if p is to right of halfedge e */
\r
402 int VoronoiDiagramGenerator::right_of(struct Halfedge *el,struct Point *p)
\r
405 struct Site *topsite;
\r
406 int right_of_site, above, fast;
\r
407 float dxp, dyp, dxs, t1, t2, t3, yl;
\r
410 topsite = e -> reg[1];
\r
411 right_of_site = p -> x > topsite -> coord.x;
\r
412 if(right_of_site && el -> ELpm == le) return(1);
\r
413 if(!right_of_site && el -> ELpm == re) return (0);
\r
416 dyp = p->y - topsite->coord.y;
\r
417 dxp = p->x - topsite->coord.x;
\r
419 if ((!right_of_site & (e->b<0.0)) | (right_of_site & (e->b>=0.0)) )
\r
421 above = dyp>= e->b*dxp;
\r
426 above = p->x + p->y*e->b > e-> c;
\r
427 if(e->b<0.0) above = !above;
\r
428 if (!above) fast = 1;
\r
433 dxs = topsite->coord.x - (e->reg[0])->coord.x;
\r
434 above = e->b * (dxp*dxp - dyp*dyp) <
\r
435 dxs*dyp*(1.0+2.0*dxp/dxs + e->b*e->b);
\r
436 if(e->b<0.0) above = !above;
\r
439 else /*e->b==1.0 */
\r
441 yl = e->c - e->a*p->x;
\r
443 t2 = p->x - topsite->coord.x;
\r
444 t3 = yl - topsite->coord.y;
\r
445 above = t1*t1 > t2*t2 + t3*t3;
\r
447 return (el->ELpm==le ? above : !above);
\r
451 void VoronoiDiagramGenerator::endpoint(struct Edge *e,int lr,struct Site * s)
\r
457 if(e -> ep[re-lr]== (struct Site *) NULL)
\r
464 makefree((Freenode*)e, &efl);
\r
467 void VoronoiDiagramGenerator::endpoint(struct Edge *e1,int lr,struct Site * s, struct Edge *e2, struct Edge *e3)
\r
472 s->coordout.x = s->coord.x;
\r
473 s->coordout.y = s->coord.y;
\r
475 if(e1 -> ep[le] != (struct Site *) NULL && e1 -> ep[re] != (struct Site *) NULL)
\r
478 deref(e1->reg[le]);
\r
479 deref(e1->reg[re]);
\r
480 makefree((Freenode*)e1, &efl);
\r
483 if(e2 -> ep[le] != (struct Site *) NULL && e2 -> ep[re] != (struct Site *) NULL)
\r
486 deref(e2->reg[le]);
\r
487 deref(e2->reg[re]);
\r
488 makefree((Freenode*)e2, &efl);
\r
491 if(e3 -> ep[le] != (struct Site *) NULL && e3 -> ep[re] != (struct Site *) NULL)
\r
494 deref(e3->reg[le]);
\r
495 deref(e3->reg[re]);
\r
496 makefree((Freenode*)e3, &efl);
\r
503 float VoronoiDiagramGenerator::dist(struct Site *s,struct Site *t)
\r
506 dx = s->coord.x - t->coord.x;
\r
507 dy = s->coord.y - t->coord.y;
\r
508 return (float)(sqrt(dx*dx + dy*dy));
\r
512 void VoronoiDiagramGenerator::makevertex(struct Site *v)
\r
514 v -> sitenbr = nvertices;
\r
520 void VoronoiDiagramGenerator::deref(struct Site *v)
\r
523 if (v -> refcnt == 0 )
\r
524 makefree((Freenode*)v, &sfl);
\r
527 void VoronoiDiagramGenerator::ref(struct Site *v)
\r
532 //push the HalfEdge into the ordered linked list of vertices
\r
533 void VoronoiDiagramGenerator::PQinsert(struct Halfedge *he,struct Site * v, float offset)
\r
535 struct Halfedge *last, *next;
\r
539 he -> ystar = (float)(v -> coord.y + offset);
\r
540 last = &PQhash[PQbucket(he)];
\r
541 while ((next = last -> PQnext) != (struct Halfedge *) NULL &&
\r
542 (he -> ystar > next -> ystar ||
\r
543 (he -> ystar == next -> ystar && v -> coord.x > next->vertex->coord.x)))
\r
547 he -> PQnext = last -> PQnext;
\r
548 last -> PQnext = he;
\r
552 //remove the HalfEdge from the list of vertices
\r
553 void VoronoiDiagramGenerator::PQdelete(struct Halfedge *he)
\r
555 struct Halfedge *last;
\r
557 if(he -> vertex != (struct Site *) NULL)
\r
559 last = &PQhash[PQbucket(he)];
\r
560 while (last -> PQnext != he)
\r
561 last = last -> PQnext;
\r
563 last -> PQnext = he -> PQnext;
\r
565 deref(he -> vertex);
\r
566 he -> vertex = (struct Site *) NULL;
\r
570 int VoronoiDiagramGenerator::PQbucket(struct Halfedge *he)
\r
574 bucket = (int)((he->ystar - ymin)/deltay * PQhashsize);
\r
575 if (bucket<0) bucket = 0;
\r
576 if (bucket>=PQhashsize) bucket = PQhashsize-1 ;
\r
577 if (bucket < PQmin) PQmin = bucket;
\r
581 int VoronoiDiagramGenerator::PQempty()
\r
583 return(PQcount==0);
\r
587 struct Point VoronoiDiagramGenerator::PQ_min()
\r
589 struct Point answer;
\r
591 while(PQhash[PQmin].PQnext == (struct Halfedge *)NULL) {PQmin += 1;};
\r
592 answer.x = PQhash[PQmin].PQnext -> vertex -> coord.x;
\r
593 answer.y = PQhash[PQmin].PQnext -> ystar;
\r
597 struct Halfedge * VoronoiDiagramGenerator::PQextractmin()
\r
599 struct Halfedge *curr;
\r
601 curr = PQhash[PQmin].PQnext;
\r
602 PQhash[PQmin].PQnext = curr -> PQnext;
\r
608 bool VoronoiDiagramGenerator::PQinitialize()
\r
614 PQhashsize = 4 * sqrt_nsites;
\r
615 PQhash = (struct Halfedge *) myalloc(PQhashsize * sizeof *PQhash);
\r
620 for(i=0; i<PQhashsize; i+=1) PQhash[i].PQnext = (struct Halfedge *)NULL;
\r
626 void VoronoiDiagramGenerator::freeinit(struct Freelist *fl,int size)
\r
628 fl -> head = (struct Freenode *) NULL;
\r
629 fl -> nodesize = size;
\r
632 char * VoronoiDiagramGenerator::getfree(struct Freelist *fl)
\r
635 struct Freenode *t;
\r
637 if(fl->head == (struct Freenode *) NULL)
\r
639 t = (struct Freenode *) myalloc(sqrt_nsites * fl->nodesize);
\r
644 currentMemoryBlock->next = new FreeNodeArrayList;
\r
645 currentMemoryBlock = currentMemoryBlock->next;
\r
646 currentMemoryBlock->memory = t;
\r
647 currentMemoryBlock->next = 0;
\r
649 for(i=0; i<sqrt_nsites; i+=1)
\r
650 makefree((struct Freenode *)((char *)t+i*fl->nodesize), fl);
\r
653 fl -> head = (fl -> head) -> nextfree;
\r
659 void VoronoiDiagramGenerator::makefree(struct Freenode *curr,struct Freelist *fl)
\r
661 curr -> nextfree = fl -> head;
\r
665 void VoronoiDiagramGenerator::cleanup()
\r
673 FreeNodeArrayList* current=0, *prev = 0;
\r
675 current = prev = allMemoryList;
\r
677 while(current->next != 0)
\r
680 current = current->next;
\r
681 free(prev->memory);
\r
686 if(current != 0 && current->memory != 0)
\r
688 free(current->memory);
\r
692 allMemoryList = new FreeNodeArrayList;
\r
693 allMemoryList->next = 0;
\r
694 allMemoryList->memory = 0;
\r
695 currentMemoryBlock = allMemoryList;
\r
698 void VoronoiDiagramGenerator::cleanupEdges()
\r
700 GraphEdge* geCurrent = 0, *gePrev = 0;
\r
701 geCurrent = gePrev = allEdges;
\r
703 while(geCurrent != 0 && geCurrent->next != 0)
\r
705 gePrev = geCurrent;
\r
706 geCurrent = geCurrent->next;
\r
714 void VoronoiDiagramGenerator::pushGraphEdge(float x1, float y1, float x2, float y2)
\r
716 GraphEdge* newEdge = new GraphEdge;
\r
717 newEdge->next = allEdges;
\r
718 allEdges = newEdge;
\r
726 char * VoronoiDiagramGenerator::myalloc(unsigned n)
\r
729 t=(char*)malloc(n);
\r
735 /* for those who don't have Cherry's plot */
\r
736 /* #include <plot.h> */
\r
737 void VoronoiDiagramGenerator::openpl(){}
\r
738 void VoronoiDiagramGenerator::line(float x1, float y1, float x2, float y2)
\r
740 pushGraphEdge(x1,y1,x2,y2);
\r
743 void VoronoiDiagramGenerator::circle(float x, float y, float radius){}
\r
744 void VoronoiDiagramGenerator::range(float minX, float minY, float maxX, float maxY){}
\r
748 void VoronoiDiagramGenerator::out_bisector(struct Edge *e)
\r
754 void VoronoiDiagramGenerator::out_ep(struct Edge *e)
\r
759 void VoronoiDiagramGenerator::out_vertex(struct Site *v)
\r
765 void VoronoiDiagramGenerator::out_site(struct Site *s)
\r
767 if(!triangulate & plot & !debug)
\r
768 circle (s->coord.x, s->coord.y, cradius);
\r
772 void VoronoiDiagramGenerator::out_triple(struct Site *s1, struct Site *s2,struct Site * s3)
\r
779 void VoronoiDiagramGenerator::plotinit()
\r
785 d = (float)(( dx > dy ? dx : dy) * 1.1);
\r
786 pxmin = (float)(xmin - (d-dx)/2.0);
\r
787 pxmax = (float)(xmax + (d-dx)/2.0);
\r
788 pymin = (float)(ymin - (d-dy)/2.0);
\r
789 pymax = (float)(ymax + (d-dy)/2.0);
\r
790 cradius = (float)((pxmax - pxmin)/350.0);
\r
792 range(pxmin, pymin, pxmax, pymax);
\r
795 void VoronoiDiagramGenerator::pushpoint(int sitenbr, double x, double y, int boundary)
\r
799 s = &polygons[sitenbr];
\r
801 if (s->numpoints == 0)
\r
803 s->pointlist = (PolygonPoint *)malloc(sizeof(struct PolygonPoint)*(s->numpoints+10));
\r
806 printf("Out of mem\n");
\r
809 else if (s->numpoints % 10 == 0)
\r
811 s->pointlist = (PolygonPoint *)realloc(s->pointlist, sizeof(struct PolygonPoint)*(s->numpoints+10));
\r
814 printf("Out of remem\n");
\r
817 s->pointlist[s->numpoints].coord.x = x;
\r
818 s->pointlist[s->numpoints].coord.y = y;
\r
819 s->pointlist[s->numpoints].angle = atan2f(x-s->coord.x, y-s->coord.y);
\r
820 s->pointlist[s->numpoints].boundary = boundary;
\r
822 if (boundary) s->boundary = 1;
\r
824 //printf("point #%d in %d (%lf, %lf) [%d] (%lf, %lf): %lf\n", s->numpoints, sitenbr, s->coord.x, s->coord.y, boundary, x, y, (s->pointlist[s->numpoints].angle/M_PI)*180);
\r
829 int VoronoiDiagramGenerator::ccw( Point p0, Point p1, Point p2 )
\r
831 double dx1, dx2, dy1, dy2;
\r
833 dx1 = p1.x - p0.x; dy1 = p1.y - p0.y;
\r
834 dx2 = p2.x - p0.x; dy2 = p2.y - p0.y;
\r
836 if (dx1*dy2 > dy1*dx2)
\r
838 if (dx1*dy2 < dy1*dx2)
\r
840 if ((dx1*dx2 < 0) || (dy1*dy2 < 0))
\r
842 if ((dx1*dx1 + dy1*dy1) < (dx2*dx2 + dy2*dy2))
\r
847 void VoronoiDiagramGenerator::getSitePoints(int sitenbr, int* numpoints, PolygonPoint** pS)
\r
849 int i, j, c, any, centrevalue, cornerinpolygon[4];
\r
851 if (polygons[sitenbr].numpoints == 0)
\r
853 for(c = 0; c < 4; c++)
\r
855 pushpoint(sitenbr, corners[c].x, corners[c].y, 0);
\r
859 qsort(polygons[sitenbr].pointlist, polygons[sitenbr].numpoints, sizeof(PolygonPoint), anglecomp);
\r
861 if (polygons[sitenbr].boundary)
\r
863 // printf("\nsite %d is boundary intersection\n", sitenbr);
\r
865 for(c = 0; c < 4; c++) cornerinpolygon[c] = 1;
\r
867 for(i = 0; i < polygons[sitenbr].numpoints; i++)
\r
869 // printf("Point (%lf,%lf) %d\n", polygons[sitenbr].pointlist[i].coord.x,polygons[sitenbr].pointlist[i].coord.y,polygons[sitenbr].pointlist[i].boundary);
\r
870 j = i > 0?i-1:polygons[sitenbr].numpoints-1;
\r
871 if ( (!polygons[sitenbr].pointlist[i].boundary || !polygons[sitenbr].pointlist[j].boundary) &&
\r
872 (polygons[sitenbr].pointlist[i].coord.x != polygons[sitenbr].pointlist[j].coord.x ||
\r
873 polygons[sitenbr].pointlist[i].coord.y != polygons[sitenbr].pointlist[j].coord.y))
\r
875 // printf("line side test (%lf,%lf) => (%lf,%lf)\n",polygons[sitenbr].pointlist[i].coord.x,polygons[sitenbr].pointlist[i].coord.y,polygons[sitenbr].pointlist[j].coord.x,polygons[sitenbr].pointlist[j].coord.y);
\r
877 centrevalue = ccw(polygons[sitenbr].pointlist[i].coord, polygons[sitenbr].pointlist[j].coord, polygons[sitenbr].coord);
\r
878 //printf(" test against centre (%lf,%lf) %d\n", polygons[sitenbr].coord.x, polygons[sitenbr].coord.y, centrevalue);
\r
879 for(c = 0; c < 4; c++)
\r
881 if (cornerinpolygon[c])
\r
884 //printf(" test against corner (%lf,%lf) %d\n", corners[c].x, corners[c].y, ccw(polygons[sitenbr].pointlist[i].coord, polygons[sitenbr].pointlist[j].coord, corners[c]));
\r
886 if (centrevalue == ccw(polygons[sitenbr].pointlist[i].coord, polygons[sitenbr].pointlist[j].coord, corners[c]))
\r
892 cornerinpolygon[c] = 0;
\r
901 for(c = 0; c < 4; c++)
\r
903 if (cornerinpolygon[c])
\r
905 // printf("adding corger (%lf,%lf) to %d\n", corners[c].x, corners[c].y, sitenbr);
\r
906 pushpoint(sitenbr, corners[c].x, corners[c].y, 0);
\r
910 qsort(polygons[sitenbr].pointlist, polygons[sitenbr].numpoints, sizeof(PolygonPoint), anglecomp);
\r
912 polygons[sitenbr].boundary = 0;
\r
915 *numpoints = polygons[sitenbr].numpoints;
\r
916 *pS = polygons[sitenbr].pointlist;
\r
920 void VoronoiDiagramGenerator::clip_line(struct Edge *e)
\r
922 struct Site *s1, *s2, *ts1, *ts2;
\r
923 float x1=0,x2=0,y1=0,y2=0, temp = 0;
\r
924 int boundary1 = 0, boundary2 = 0;
\r
927 x1 = e->reg[0]->coord.x;
\r
928 x2 = e->reg[1]->coord.x;
\r
929 y1 = e->reg[0]->coord.y;
\r
930 y2 = e->reg[1]->coord.y;
\r
932 if(sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) == 0)
\r
937 pxmin = borderMinX;
\r
938 pxmax = borderMaxX;
\r
939 pymin = borderMinY;
\r
940 pymax = borderMaxY;
\r
942 if(e -> a == 1.0 && e ->b >= 0.0)
\r
962 if ( s1!=(struct Site *)NULL
\r
963 && s1->coordout.y > pymin && s1->coordout.y < pymax
\r
964 && s1->coordout.x > pxmin && s1->coordout.x < pxmax)
\r
966 x1 = s1->coordout.x;
\r
967 y1 = s1->coordout.y;
\r
973 if (s1!=(struct Site *)NULL && s1->coord.y > pymin)
\r
981 x1 = e -> c - e -> b * y1;
\r
984 if ( s2!=(struct Site *)NULL
\r
985 && s2->coordout.y > pymin && s2->coordout.y < pymax
\r
986 && s2->coordout.x > pxmin && s2->coordout.x < pxmax)
\r
988 x2 = s2->coordout.x;
\r
989 y2 = s2->coordout.y;
\r
995 if (s2!=(struct Site *)NULL && s2->coord.y < pymax)
\r
1001 x2 = (e->c) - (e->b) * y2;
\r
1004 if (((x1> pxmax) & (x2>pxmax)) | ((x1<pxmin)&(x2<pxmin)))
\r
1006 // Line completely outside clipbox
\r
1007 //printf("\nClipLine jumping out(3), x1 = %f, pxmin = %f, pxmax = %f",x1,pxmin,pxmax);
\r
1013 y1 = (e -> c - x1)/e -> b;
\r
1018 y1 = (e -> c - x1)/e -> b;
\r
1023 y2 = (e -> c - x2)/e -> b;
\r
1028 y2 = (e -> c - x2)/e -> b;
\r
1033 if ( s1!=(struct Site *)NULL
\r
1034 && s1->coordout.y > pymin && s1->coordout.y < pymax
\r
1035 && s1->coordout.x > pxmin && s1->coordout.x < pxmax)
\r
1037 x1 = s1->coordout.x;
\r
1038 y1 = s1->coordout.y;
\r
1044 if (s1!=(struct Site *)NULL && s1->coord.x > pxmin)
\r
1048 //printf("\nClipped (3) x1 = %f to %f",x1,pxmin);
\r
1052 y1 = e -> c - e -> a * x1;
\r
1055 if ( s2!=(struct Site *)NULL
\r
1056 && s2->coordout.y > pymin && s2->coordout.y < pymax
\r
1057 && s2->coordout.x > pxmin && s2->coordout.x < pxmax)
\r
1059 x2 = s2->coordout.x;
\r
1060 y2 = s2->coordout.y;
\r
1066 if (s2!=(struct Site *)NULL && s2->coord.x < pxmax)
\r
1070 //printf("\nClipped (4) x2 = %f to %f",x2,pxmin);
\r
1074 y2 = e -> c - e -> a * x2;
\r
1077 if (((y1> pymax) & (y2>pymax)) | ((y1<pymin)&(y2<pymin)))
\r
1079 //printf("\nClipLine jumping out(6), y1 = %f, pymin = %f, pymax = %f",y2,pymin,pymax);
\r
1083 { y1 = pymax; x1 = (e -> c - y1)/e -> a;};
\r
1085 { y1 = pymin; x1 = (e -> c - y1)/e -> a;};
\r
1087 { y2 = pymax; x2 = (e -> c - y2)/e -> a;};
\r
1089 { y2 = pymin; x2 = (e -> c - y2)/e -> a;};
\r
1092 if(sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) == 0)
\r
1097 pushpoint(ts1->sitenbr, x1, y1, boundary1);
\r
1098 pushpoint(ts2->sitenbr, x2, y2, boundary2);
\r
1099 pushpoint(ts1->sitenbr, x2, y2, boundary2);
\r
1100 pushpoint(ts2->sitenbr, x1, y1, boundary1);
\r
1104 /* implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
\r
1105 deltax, deltay (can all be estimates).
\r
1106 Performance suffers if they are wrong; better to make nsites,
\r
1107 deltax, and deltay too big than too small. (?) */
\r
1109 bool VoronoiDiagramGenerator::voronoi(int triangulate)
\r
1111 struct Site *newsite, *bot, *top, *temp, *p;
\r
1113 struct Point newintstar;
\r
1115 struct Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
\r
1116 struct Edge *e, *e2, *e3;
\r
1119 bottomsite = nextone();
\r
1120 out_site(bottomsite);
\r
1121 bool retval = ELinitialize();
\r
1126 newsite = nextone();
\r
1131 newintstar = PQ_min();
\r
1133 //if the lowest site has a smaller y value than the lowest vector intersection, process the site
\r
1134 //otherwise process the vector intersection
\r
1136 if (newsite != (struct Site *)NULL && (PQempty() || newsite -> coord.y < newintstar.y
\r
1137 || (newsite->coord.y == newintstar.y && newsite->coord.x < newintstar.x)))
\r
1138 {/* new site is smallest - this is a site event*/
\r
1139 out_site(newsite); //output the site
\r
1140 lbnd = ELleftbnd(&(newsite->coord)); //get the first HalfEdge to the LEFT of the new site
\r
1141 rbnd = ELright(lbnd); //get the first HalfEdge to the RIGHT of the new site
\r
1142 bot = rightreg(lbnd); //if this halfedge has no edge, , bot = bottom site (whatever that is)
\r
1143 e = bisect(bot, newsite); //create a new edge that bisects
\r
1144 bisector = HEcreate(e, le); //create a new HalfEdge, setting its ELpm field to 0
\r
1145 ELinsert(lbnd, bisector); //insert this new bisector edge between the left and right vectors in a linked list
\r
1147 if ((p = intersect(lbnd, bisector)) != (struct Site *) NULL) //if the new bisector intersects with the left edge, remove the left edge's vertex, and put in the new one
\r
1150 PQinsert(lbnd, p, dist(p,newsite));
\r
1153 bisector = HEcreate(e, re); //create a new HalfEdge, setting its ELpm field to 1
\r
1154 ELinsert(lbnd, bisector); //insert the new HE to the right of the original bisector earlier in the IF stmt
\r
1156 if ((p = intersect(bisector, rbnd)) != (struct Site *) NULL) //if this new bisector intersects with the
\r
1158 PQinsert(bisector, p, dist(p,newsite)); //push the HE into the ordered linked list of vertices
\r
1160 newsite = nextone();
\r
1162 else if (!PQempty()) /* intersection is smallest - this is a vector event */
\r
1164 lbnd = PQextractmin(); //pop the HalfEdge with the lowest vector off the ordered list of vectors
\r
1165 llbnd = ELleft(lbnd); //get the HalfEdge to the left of the above HE
\r
1166 rbnd = ELright(lbnd); //get the HalfEdge to the right of the above HE
\r
1167 rrbnd = ELright(rbnd); //get the HalfEdge to the right of the HE to the right of the lowest HE
\r
1168 bot = leftreg(lbnd); //get the Site to the left of the left HE which it bisects
\r
1169 top = rightreg(rbnd); //get the Site to the right of the right HE which it bisects
\r
1171 out_triple(bot, top, rightreg(lbnd)); //output the triple of sites, stating that a circle goes through them
\r
1173 v = lbnd->vertex; //get the vertex that caused this event
\r
1174 makevertex(v); //set the vertex number - couldn't do this earlier since we didn't know when it would be processed
\r
1175 e2 = lbnd->ELedge;
\r
1176 e3 = rbnd->ELedge;
\r
1177 endpoint(lbnd->ELedge,lbnd->ELpm,v); //set the endpoint of the left HalfEdge to be this vector
\r
1178 endpoint(rbnd->ELedge,rbnd->ELpm,v); //set the endpoint of the right HalfEdge to be this vector
\r
1179 ELdelete(lbnd); //mark the lowest HE for deletion - can't delete yet because there might be pointers to it in Hash Map
\r
1180 PQdelete(rbnd); //remove all vertex events to do with the right HE
\r
1181 ELdelete(rbnd); //mark the right HE for deletion - can't delete yet because there might be pointers to it in Hash Map
\r
1182 pm = le; //set the pm variable to zero
\r
1184 if (bot->coord.y > top->coord.y) //if the site to the left of the event is higher than the Site
\r
1185 { //to the right of it, then swap them and set the 'pm' variable to 1
\r
1191 e = bisect(bot, top); //create an Edge (or line) that is between the two Sites. This creates
\r
1192 //the formula of the line, and assigns a line number to it
\r
1193 bisector = HEcreate(e, pm); //create a HE from the Edge 'e', and make it point to that edge with its ELedge field
\r
1194 ELinsert(llbnd, bisector); //insert the new bisector to the right of the left HE
\r
1195 endpoint(e, re-pm, v, e2, e3); //set one endpoint to the new edge to be the vector point 'v'.
\r
1196 //If the site to the left of this bisector is higher than the right
\r
1197 //Site, then this endpoint is put in position 0; otherwise in pos 1
\r
1198 deref(v); //delete the vector 'v'
\r
1200 //if left HE and the new bisector don't intersect, then delete the left HE, and reinsert it
\r
1201 if((p = intersect(llbnd, bisector)) != (struct Site *) NULL)
\r
1204 PQinsert(llbnd, p, dist(p,bot));
\r
1207 //if right HE and the new bisector don't intersect, then reinsert it
\r
1208 if ((p = intersect(bisector, rrbnd)) != (struct Site *) NULL)
\r
1210 PQinsert(bisector, p, dist(p,bot));
\r
1216 for(lbnd=ELright(ELleftend); lbnd != ELrightend; lbnd=ELright(lbnd))
\r
1218 e = lbnd -> ELedge;
\r
1229 int scomp(const void *p1,const void *p2)
\r
1231 struct Point *s1 = (Point*)p1, *s2=(Point*)p2;
\r
1232 if(s1 -> y < s2 -> y) return(-1);
\r
1233 if(s1 -> y > s2 -> y) return(1);
\r
1234 if(s1 -> x < s2 -> x) return(-1);
\r
1235 if(s1 -> x > s2 -> x) return(1);
\r
1239 int spcomp(const void *p1,const void *p2)
\r
1241 struct SourcePoint *s1 = (SourcePoint*)p1, *s2=(SourcePoint*)p2;
\r
1242 if(s1 -> y < s2 -> y) return(-1);
\r
1243 if(s1 -> y > s2 -> y) return(1);
\r
1244 if(s1 -> x < s2 -> x) return(-1);
\r
1245 if(s1 -> x > s2 -> x) return(1);
\r
1249 int anglecomp(const void * p1, const void * p2)
\r
1251 PolygonPoint * s1 = (PolygonPoint *)p1 ;
\r
1252 PolygonPoint * s2 = (PolygonPoint *)p2 ;
\r
1254 if (s1->angle < s2->angle) {
\r
1257 if (s1->angle > s2->angle) {
\r
1263 /* return a single in-storage site */
\r
1264 struct Site * VoronoiDiagramGenerator::nextone()
\r
1267 if(siteidx < nsites)
\r
1269 s = &sites[siteidx];
\r
1274 return( (struct Site *)NULL);
\r