Fork me on GitHub

source: svn/trunk/Utilities/Fastjet/src/Voronoi.cc@ 701

Last change on this file since 701 was 11, checked in by severine ovyn, 16 years ago

Fastjet added; CDFCones directory has been changed

File size: 27.3 KB
Line 
1//STARTHEADER
2// $Id: Voronoi.cc,v 1.1 2008-11-06 14:32:15 ovyn Exp $
3//
4// Copyright (c) 1994 by AT&T Bell Laboratories (see below)
5//
6//
7//----------------------------------------------------------------------
8// This file is included as part of FastJet but was mostly written by
9// S. Fortune in C, put into C++ with memory management by S
10// O'Sullivan, and with further interface and memory management
11// modifications by Gregory Soyez.
12//
13// Permission to use, copy, modify, and distribute this software for
14// any purpose without fee is hereby granted, provided that this
15// entire notice is included in all copies of any software which is or
16// includes a copy or modification of this software and in all copies
17// of the supporting documentation for such software. THIS SOFTWARE IS
18// BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY.
19// IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY REPRESENTATION
20// OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS
21// SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
22//
23//----------------------------------------------------------------------
24//ENDHEADER
25
26
27/*
28 * The author of this software is Steven Fortune.
29 * Copyright (c) 1994 by AT&T Bell Laboratories.
30 * Permission to use, copy, modify, and distribute this software for any
31 * purpose without fee is hereby granted, provided that this entire notice
32 * is included in all copies of any software which is or includes a copy
33 * or modification of this software and in all copies of the supporting
34 * documentation for such software.
35 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
36 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
37 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
38 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
39 */
40
41/*
42 * This code was originally written by Stephan Fortune in C code. I,
43 * Shane O'Sullivan, have since modified it, encapsulating it in a C++
44 * class and, fixing memory leaks and adding accessors to the Voronoi
45 * Edges. Permission to use, copy, modify, and distribute this
46 * software for any purpose without fee is hereby granted, provided
47 * that this entire notice is included in all copies of any software
48 * which is or includes a copy or modification of this software and in
49 * all copies of the supporting documentation for such software. THIS
50 * SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
51 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
52 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE
53 * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
54 * PURPOSE.
55 */
56
57#include <stdio.h>
58#include "../include/fastjet/internal/Voronoi.hh"
59
60using namespace std;
61
62FASTJET_BEGIN_NAMESPACE
63
64VoronoiDiagramGenerator::VoronoiDiagramGenerator(){
65 siteidx = 0;
66 sites = NULL;
67 parent_sites = NULL;
68
69 allMemoryList = new FreeNodeArrayList;
70 allMemoryList->memory = NULL;
71 allMemoryList->next = NULL;
72 currentMemoryBlock = allMemoryList;
73 allEdges = NULL;
74 iteratorEdges = 0;
75 minDistanceBetweenSites = 0;
76
77 ELhash = NULL;
78 PQhash = NULL;
79}
80
81VoronoiDiagramGenerator::~VoronoiDiagramGenerator(){
82 cleanup();
83 cleanupEdges();
84
85 if (allMemoryList != NULL)
86 delete allMemoryList;
87}
88
89
90
91bool VoronoiDiagramGenerator::generateVoronoi(vector<Point> *_parent_sites,
92 double minX, double maxX,
93 double minY, double maxY,
94 double minDist){
95 cleanup();
96 cleanupEdges();
97 int i;
98 double x, y;
99
100 minDistanceBetweenSites = minDist;
101
102 parent_sites = _parent_sites;
103
104 nsites = n_parent_sites = parent_sites->size();
105 plot = 0;
106 triangulate = 0;
107 debug = 1;
108 sorted = 0;
109 freeinit(&sfl, sizeof (Site));
110
111 //sites = (Site *) myalloc(nsites*sizeof( *sites));
112 sites = (Site *) myalloc(nsites*sizeof( Site));
113 //parent_sites = (Site *) myalloc(nsites*sizeof( Site));
114
115 if (sites == 0)
116 return false;
117
118 xmax = xmin = (*parent_sites)[0].x;
119 ymax = ymin = (*parent_sites)[0].y;
120
121 for(i=0;i<nsites;i++){
122 x = (*parent_sites)[i].x;
123 y = (*parent_sites)[i].y;
124 sites[i].coord.x = x;
125 sites[i].coord.y = y;
126 sites[i].sitenbr = i;
127 sites[i].refcnt = 0;
128
129 if (x<xmin)
130 xmin=x;
131 else if (x>xmax)
132 xmax=x;
133
134 if (y<ymin)
135 ymin=y;
136 else if (y>ymax)
137 ymax=y;
138 }
139
140 qsort(sites, nsites, sizeof (*sites), scomp);
141
142 siteidx = 0;
143 geominit();
144 double temp = 0;
145 if(minX > maxX){
146 temp = minX;
147 minX = maxX;
148 maxX = temp;
149 }
150 if(minY > maxY){
151 temp = minY;
152 minY = maxY;
153 maxY = temp;
154 }
155 borderMinX = minX;
156 borderMinY = minY;
157 borderMaxX = maxX;
158 borderMaxY = maxY;
159
160 siteidx = 0;
161 voronoi(triangulate);
162
163 return true;
164}
165
166bool VoronoiDiagramGenerator::ELinitialize(){
167 int i;
168 freeinit(&hfl, sizeof(Halfedge));
169 ELhashsize = 2 * sqrt_nsites;
170 //ELhash = (Halfedge **) myalloc ( sizeof *ELhash * ELhashsize);
171 ELhash = (Halfedge **) myalloc ( sizeof(Halfedge*)*ELhashsize);
172
173 if(ELhash == 0)
174 return false;
175
176 for(i=0; i<ELhashsize; i +=1) ELhash[i] = (Halfedge *)NULL;
177 ELleftend = HEcreate((Edge*) NULL, 0);
178 ELrightend = HEcreate((Edge*) NULL, 0);
179 ELleftend->ELleft = (Halfedge*) NULL;
180 ELleftend->ELright = ELrightend;
181 ELrightend->ELleft = ELleftend;
182 ELrightend->ELright = (Halfedge*) NULL;
183 ELhash[0] = ELleftend;
184 ELhash[ELhashsize-1] = ELrightend;
185
186 return true;
187}
188
189
190Halfedge* VoronoiDiagramGenerator::HEcreate(Edge *e,int pm){
191 Halfedge *answer;
192 answer = (Halfedge*) getfree(&hfl);
193 answer->ELedge = e;
194 answer->ELpm = pm;
195 answer->PQnext = (Halfedge*) NULL;
196 answer->vertex = (Site*) NULL;
197 answer->ELrefcnt = 0;
198 return answer;
199}
200
201
202void VoronoiDiagramGenerator::ELinsert(Halfedge *lb, Halfedge *newHe)
203{
204 newHe->ELleft = lb;
205 newHe->ELright = lb->ELright;
206 (lb->ELright)->ELleft = newHe;
207 lb->ELright = newHe;
208}
209
210
211/* Get entry from hash table, pruning any deleted nodes */
212Halfedge* VoronoiDiagramGenerator::ELgethash(int b){
213 Halfedge *he;
214
215 if ((b<0) || (b>=ELhashsize))
216 return (Halfedge *) NULL;
217
218 he = ELhash[b];
219 if ((he==(Halfedge*) NULL) || (he->ELedge!=(Edge*) DELETED))
220 return he;
221
222 /* Hash table points to deleted half edge. Patch as necessary. */
223 ELhash[b] = (Halfedge*) NULL;
224 if ((he->ELrefcnt -= 1) == 0)
225 makefree((Freenode*)he, &hfl);
226 return (Halfedge*) NULL;
227}
228
229Halfedge * VoronoiDiagramGenerator::ELleftbnd(Point *p){
230 int i, bucket;
231 Halfedge *he;
232
233 /* Use hash table to get close to desired halfedge */
234 // use the hash function to find the place in the hash map that this
235 // HalfEdge should be
236 bucket = (int)((p->x - xmin)/deltax * ELhashsize);
237
238 // make sure that the bucket position in within the range of the
239 //hash array
240 if (bucket<0) bucket =0;
241 if (bucket>=ELhashsize) bucket = ELhashsize - 1;
242
243 he = ELgethash(bucket);
244
245 // if the HE isn't found, search backwards and forwards in the hash
246 // map for the first non-null entry
247 if (he == (Halfedge*) NULL){
248 for(i=1;1;i++){
249 if ((he=ELgethash(bucket-i)) != (Halfedge*) NULL)
250 break;
251 if ((he=ELgethash(bucket+i)) != (Halfedge*) NULL)
252 break;
253 };
254 totalsearch += i;
255 };
256 ntry += 1;
257 /* Now search linear list of halfedges for the correct one */
258 if ((he==ELleftend) || (he != ELrightend && right_of(he,p))){
259 do{
260 he = he->ELright;
261 } while (he!=ELrightend && right_of(he,p));
262 // keep going right on the list until either the end is reached,
263 // or you find the 1st edge which the point
264 he = he->ELleft; //isn't to the right of
265 } else
266 // if the point is to the left of the HalfEdge, then search left
267 // for the HE just to the left of the point
268 do{
269 he = he->ELleft;
270 } while ((he!=ELleftend )&& (!right_of(he,p)));
271
272 /* Update hash table and reference counts */
273 if ((bucket > 0) && (bucket <ELhashsize-1)){
274 if(ELhash[bucket] != (Halfedge *) NULL){
275 ELhash[bucket]->ELrefcnt -= 1;
276 }
277 ELhash[bucket] = he;
278 ELhash[bucket]->ELrefcnt += 1;
279 };
280
281 return he;
282}
283
284
285/* This delete routine can't reclaim node, since pointers from hash
286 table may be present. */
287void VoronoiDiagramGenerator::ELdelete(Halfedge *he){
288 (he->ELleft)->ELright = he->ELright;
289 (he->ELright)->ELleft = he->ELleft;
290 he->ELedge = (Edge*) DELETED;
291}
292
293
294Halfedge* VoronoiDiagramGenerator::ELright(Halfedge *he){
295 return he->ELright;
296}
297
298
299Halfedge* VoronoiDiagramGenerator::ELleft(Halfedge *he){
300 return he->ELleft;
301}
302
303
304Site * VoronoiDiagramGenerator::leftreg(Halfedge *he){
305 if (he->ELedge == (Edge*) NULL)
306 return(bottomsite);
307 return (he->ELpm == le)
308 ? he->ELedge->reg[le]
309 : he->ELedge->reg[re];
310}
311
312Site * VoronoiDiagramGenerator::rightreg(Halfedge *he){
313 if (he->ELedge == (Edge*) NULL)
314 // if this halfedge has no edge, return the bottom site (whatever
315 // that is)
316 return bottomsite;
317
318 // if the ELpm field is zero, return the site 0 that this edge
319 // bisects, otherwise return site number 1
320 return (he->ELpm == le)
321 ? he->ELedge->reg[re]
322 : he->ELedge->reg[le];
323}
324
325void VoronoiDiagramGenerator::geominit(){
326 double sn;
327
328 freeinit(&efl, sizeof(Edge));
329 nvertices = 0;
330 nedges = 0;
331 sn = (double)nsites+4;
332 sqrt_nsites = (int)sqrt(sn);
333 deltay = ymax - ymin;
334 deltax = xmax - xmin;
335}
336
337
338Edge * VoronoiDiagramGenerator::bisect(Site *s1, Site *s2){
339 double dx,dy,adx,ady;
340 Edge *newedge;
341
342 newedge = (Edge*) getfree(&efl);
343
344 newedge->reg[0] = s1; //store the sites that this edge is bisecting
345 newedge->reg[1] = s2;
346 ref(s1);
347 ref(s2);
348
349 // to begin with, there are no endpoints on the bisector - it goes
350 // to infinity
351 newedge->ep[0] = (Site*) NULL;
352 newedge->ep[1] = (Site*) NULL;
353
354 // get the difference in x dist between the sites
355 dx = s2->coord.x - s1->coord.x;
356 dy = s2->coord.y - s1->coord.y;
357
358 // make sure that the difference is positive
359 adx = dx>0 ? dx : -dx;
360 ady = dy>0 ? dy : -dy;
361
362 // get the slope of the line
363 newedge->c = (double)(s1->coord.x * dx + s1->coord.y * dy
364 + (dx*dx + dy*dy)*0.5);
365
366 if (adx>ady){
367 //set formula of line, with x fixed to 1
368 newedge->a = 1.0; newedge->b = dy/dx; newedge->c /= dx;
369 } else {
370 //set formula of line, with y fixed to 1
371 newedge->b = 1.0; newedge->a = dx/dy; newedge->c /= dy;
372 }
373
374 newedge->edgenbr = nedges;
375 nedges++;
376
377 return newedge;
378}
379
380
381// create a new site where the HalfEdges el1 and el2 intersect - note
382// that the Point in the argument list is not used, don't know why
383// it's there
384Site* VoronoiDiagramGenerator::intersect(Halfedge *el1, Halfedge *el2, Point *p){
385 Edge *e1,*e2, *e;
386 Halfedge *el;
387 double d, xint, yint;
388 int right_of_site;
389 Site *v;
390
391 e1 = el1->ELedge;
392 e2 = el2->ELedge;
393 if ((e1==(Edge*)NULL) || (e2==(Edge*)NULL))
394 return ((Site*) NULL);
395
396 // if the two edges bisect the same parent, return null
397 if (e1->reg[1] == e2->reg[1])
398 return (Site*) NULL;
399
400 d = e1->a * e2->b - e1->b * e2->a;
401 if (-1.0e-10<d && d<1.0e-10)
402 return (Site*) NULL;
403
404 xint = (e1->c*e2->b - e2->c*e1->b)/d;
405 yint = (e2->c*e1->a - e1->c*e2->a)/d;
406
407 volatile double local_y1 = e1->reg[1]->coord.y;
408 volatile double local_y2 = e2->reg[1]->coord.y;
409
410 if( (local_y1 < local_y2) ||
411 ((local_y1 == local_y2) &&
412 (e1->reg[1]->coord.x < e2->reg[1]->coord.x)) ){
413 el = el1;
414 e = e1;
415 } else {
416 el = el2;
417 e = e2;
418 }
419
420 right_of_site = xint >= e->reg[1]->coord.x;
421 if ((right_of_site && el->ELpm == le) || (!right_of_site && el->ELpm == re))
422 return (Site*) NULL;
423
424 // create a new site at the point of intersection - this is a new
425 // vector event waiting to happen
426 v = (Site*) getfree(&sfl);
427 v->refcnt = 0;
428 v->coord.x = xint;
429 v->coord.y = yint;
430 return v;
431}
432
433//HERE
434
435/* returns 1 if p is to right of halfedge e */
436int VoronoiDiagramGenerator::right_of(Halfedge *el,Point *p)
437{
438 Edge *e;
439 Site *topsite;
440 int right_of_site, above, fast;
441 double dxp, dyp, dxs, t1, t2, t3, yl;
442
443 e = el->ELedge;
444 topsite = e->reg[1];
445 right_of_site = p->x > topsite->coord.x;
446 if(right_of_site && el->ELpm == le) return(1);
447 if(!right_of_site && el->ELpm == re) return (0);
448
449 if (e->a == 1.0)
450 { dyp = p->y - topsite->coord.y;
451 dxp = p->x - topsite->coord.x;
452 fast = 0;
453 if ((!right_of_site & (e->b<0.0)) | (right_of_site & (e->b>=0.0)) )
454 { above = dyp>= e->b*dxp;
455 fast = above;
456 }
457 else
458 { above = p->x + p->y*e->b > e-> c;
459 if(e->b<0.0) above = !above;
460 if (!above) fast = 1;
461 };
462 if (!fast)
463 { dxs = topsite->coord.x - (e->reg[0])->coord.x;
464 above = e->b * (dxp*dxp - dyp*dyp) <
465 dxs*dyp*(1.0+2.0*dxp/dxs + e->b*e->b);
466 if(e->b<0.0) above = !above;
467 };
468 }
469 else /*e->b==1.0 */
470 { yl = e->c - e->a*p->x;
471 t1 = p->y - yl;
472 t2 = p->x - topsite->coord.x;
473 t3 = yl - topsite->coord.y;
474 above = t1*t1 > t2*t2 + t3*t3;
475 };
476 return (el->ELpm==le ? above : !above);
477}
478
479
480void VoronoiDiagramGenerator::endpoint(Edge *e,int lr,Site * s)
481{
482 e->ep[lr] = s;
483 ref(s);
484 if(e->ep[re-lr]== (Site *) NULL)
485 return;
486
487 clip_line(e);
488
489 deref(e->reg[le]);
490 deref(e->reg[re]);
491 makefree((Freenode*)e, &efl);
492}
493
494
495double VoronoiDiagramGenerator::dist(Site *s,Site *t)
496{
497 double dx,dy;
498 dx = s->coord.x - t->coord.x;
499 dy = s->coord.y - t->coord.y;
500 return (double)(sqrt(dx*dx + dy*dy));
501}
502
503
504void VoronoiDiagramGenerator::makevertex(Site *v)
505{
506 v->sitenbr = nvertices;
507 nvertices += 1;
508 out_vertex(v);
509}
510
511
512void VoronoiDiagramGenerator::deref(Site *v)
513{
514 v->refcnt -= 1;
515 if (v->refcnt == 0 )
516 makefree((Freenode*)v, &sfl);
517}
518
519void VoronoiDiagramGenerator::ref(Site *v)
520{
521 v->refcnt += 1;
522}
523
524//push the HalfEdge into the ordered linked list of vertices
525void VoronoiDiagramGenerator::PQinsert(Halfedge *he,Site * v, double offset)
526{
527 Halfedge *last, *next;
528
529 he->vertex = v;
530 ref(v);
531 he->ystar = (double)(v->coord.y + offset);
532 last = &PQhash[PQbucket(he)];
533 while ((next = last->PQnext) != (Halfedge *) NULL &&
534 (he->ystar > next->ystar ||
535 (he->ystar == next->ystar && v->coord.x > next->vertex->coord.x)))
536 {
537 last = next;
538 };
539 he->PQnext = last->PQnext;
540 last->PQnext = he;
541 PQcount += 1;
542}
543
544//remove the HalfEdge from the list of vertices
545void VoronoiDiagramGenerator::PQdelete(Halfedge *he)
546{
547 Halfedge *last;
548
549 if(he->vertex != (Site *) NULL)
550 {
551 last = &PQhash[PQbucket(he)];
552 while (last->PQnext != he)
553 last = last->PQnext;
554
555 last->PQnext = he->PQnext;
556 PQcount -= 1;
557 deref(he->vertex);
558 he->vertex = (Site *) NULL;
559 };
560}
561
562int VoronoiDiagramGenerator::PQbucket(Halfedge *he)
563{
564 int bucket;
565
566 bucket = (int)((he->ystar - ymin)/deltay * PQhashsize);
567 if (bucket<0) bucket = 0;
568 if (bucket>=PQhashsize) bucket = PQhashsize-1 ;
569 if (bucket < PQmin) PQmin = bucket;
570 return(bucket);
571}
572
573
574
575int VoronoiDiagramGenerator::PQempty()
576{
577 return(PQcount==0);
578}
579
580
581Point VoronoiDiagramGenerator::PQ_min()
582{
583 Point answer;
584
585 while(PQhash[PQmin].PQnext == (Halfedge *)NULL) {PQmin += 1;};
586 answer.x = PQhash[PQmin].PQnext->vertex->coord.x;
587 answer.y = PQhash[PQmin].PQnext->ystar;
588 return (answer);
589}
590
591Halfedge * VoronoiDiagramGenerator::PQextractmin()
592{
593 Halfedge *curr;
594
595 curr = PQhash[PQmin].PQnext;
596 PQhash[PQmin].PQnext = curr->PQnext;
597 PQcount -= 1;
598 return(curr);
599}
600
601
602bool VoronoiDiagramGenerator::PQinitialize()
603{
604 int i;
605
606 PQcount = 0;
607 PQmin = 0;
608 PQhashsize = 4 * sqrt_nsites;
609 //PQhash = (Halfedge *) myalloc(PQhashsize * sizeof *PQhash);
610 PQhash = (Halfedge *) myalloc(PQhashsize * sizeof(Halfedge));
611
612 if(PQhash == 0)
613 return false;
614
615 for(i=0; i<PQhashsize; i+=1) PQhash[i].PQnext = (Halfedge *)NULL;
616
617 return true;
618}
619
620
621void VoronoiDiagramGenerator::freeinit(Freelist *fl,int size)
622{
623 fl->head = (Freenode *) NULL;
624 fl->nodesize = size;
625}
626
627char * VoronoiDiagramGenerator::getfree(Freelist *fl)
628{
629 int i;
630 Freenode *t;
631
632 if(fl->head == (Freenode *) NULL)
633 {
634 t = (Freenode *) myalloc(sqrt_nsites * fl->nodesize);
635
636 if(t == 0)
637 return 0;
638
639 currentMemoryBlock->next = new FreeNodeArrayList;
640 currentMemoryBlock = currentMemoryBlock->next;
641 currentMemoryBlock->memory = t;
642 currentMemoryBlock->next = 0;
643
644 for(i=0; i<sqrt_nsites; i+=1)
645 makefree((Freenode *)((char *)t+i*fl->nodesize), fl);
646 };
647 t = fl->head;
648 fl->head = (fl->head)->nextfree;
649 return((char *)t);
650}
651
652
653
654void VoronoiDiagramGenerator::makefree(Freenode *curr,Freelist *fl)
655{
656 curr->nextfree = fl->head;
657 fl->head = curr;
658}
659
660void VoronoiDiagramGenerator::cleanup()
661{
662 if(sites != NULL){
663 free(sites);
664 sites = 0;
665 }
666
667 FreeNodeArrayList* current=NULL, *prev=NULL;
668
669 current = prev = allMemoryList;
670
671 while(current->next!=NULL){
672 prev = current;
673 current = current->next;
674 free(prev->memory);
675 delete prev;
676 prev = NULL;
677 }
678
679 if(current!=NULL){
680 if (current->memory!=NULL){
681 free(current->memory);
682 }
683 delete current;
684 }
685
686 allMemoryList = new FreeNodeArrayList;
687 allMemoryList->next = NULL;
688 allMemoryList->memory = NULL;
689 currentMemoryBlock = allMemoryList;
690
691 if (ELhash!=NULL)
692 free(ELhash);
693
694 if (PQhash!=NULL)
695 free(PQhash);
696}
697
698void VoronoiDiagramGenerator::cleanupEdges()
699{
700 GraphEdge* geCurrent = NULL, *gePrev = NULL;
701 geCurrent = gePrev = allEdges;
702
703 while(geCurrent!=NULL){
704 gePrev = geCurrent;
705 geCurrent = geCurrent->next;
706 delete gePrev;
707 }
708
709 allEdges = 0;
710
711}
712
713void VoronoiDiagramGenerator::pushGraphEdge(double x1, double y1, double x2, double y2,
714 Site *s1, Site *s2)
715{
716 GraphEdge* newEdge = new GraphEdge;
717 newEdge->next = allEdges;
718 allEdges = newEdge;
719 newEdge->x1 = x1;
720 newEdge->y1 = y1;
721 newEdge->x2 = x2;
722 newEdge->y2 = y2;
723
724 newEdge->point1 = s1->sitenbr;
725 newEdge->point2 = s2->sitenbr;
726}
727
728
729char * VoronoiDiagramGenerator::myalloc(unsigned n)
730{
731 char *t=0;
732 t=(char*)malloc(n);
733 total_alloc += n;
734 return(t);
735}
736
737
738/* for those who don't have Cherry's plot */
739/* #include <plot.h> */
740void VoronoiDiagramGenerator::openpl(){}
741void VoronoiDiagramGenerator::circle(double x, double y, double radius){}
742void VoronoiDiagramGenerator::range(double minX, double minY, double maxX, double maxY){}
743
744
745
746void VoronoiDiagramGenerator::out_bisector(Edge *e)
747{
748
749
750}
751
752
753void VoronoiDiagramGenerator::out_ep(Edge *e)
754{
755
756
757}
758
759void VoronoiDiagramGenerator::out_vertex(Site *v)
760{
761
762}
763
764
765void VoronoiDiagramGenerator::out_site(Site *s)
766{
767 if(!triangulate & plot & !debug)
768 circle (s->coord.x, s->coord.y, cradius);
769
770}
771
772
773void VoronoiDiagramGenerator::out_triple(Site *s1, Site *s2,Site * s3)
774{
775
776}
777
778
779
780void VoronoiDiagramGenerator::plotinit()
781{
782 double dx,dy,d;
783
784 dy = ymax - ymin;
785 dx = xmax - xmin;
786 d = (double)(( dx > dy ? dx : dy) * 1.1);
787 pxmin = (double)(xmin - (d-dx)/2.0);
788 pxmax = (double)(xmax + (d-dx)/2.0);
789 pymin = (double)(ymin - (d-dy)/2.0);
790 pymax = (double)(ymax + (d-dy)/2.0);
791 cradius = (double)((pxmax - pxmin)/350.0);
792 openpl();
793 range(pxmin, pymin, pxmax, pymax);
794}
795
796
797void VoronoiDiagramGenerator::clip_line(Edge *e)
798{
799 Site *s1, *s2;
800 double x1=0,x2=0,y1=0,y2=0; //, temp = 0;
801
802 x1 = e->reg[0]->coord.x;
803 x2 = e->reg[1]->coord.x;
804 y1 = e->reg[0]->coord.y;
805 y2 = e->reg[1]->coord.y;
806
807 //if the distance between the two points this line was created from is less than
808 //the square root of 2, then ignore it
809 //TODO improve/remove
810 //if(sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) < minDistanceBetweenSites)
811 // {
812 // return;
813 // }
814 pxmin = borderMinX;
815 pxmax = borderMaxX;
816 pymin = borderMinY;
817 pymax = borderMaxY;
818
819 if(e->a == 1.0 && e ->b >= 0.0)
820 {
821 s1 = e->ep[1];
822 s2 = e->ep[0];
823 }
824 else
825 {
826 s1 = e->ep[0];
827 s2 = e->ep[1];
828 };
829
830 if(e->a == 1.0)
831 {
832 y1 = pymin;
833 if (s1!=(Site *)NULL && s1->coord.y > pymin)
834 {
835 y1 = s1->coord.y;
836 }
837 if(y1>pymax)
838 {
839 // printf("\nClipped (1) y1 = %f to %f",y1,pymax);
840 y1 = pymax;
841 //return;
842 }
843 x1 = e->c - e->b * y1;
844 y2 = pymax;
845 if (s2!=(Site *)NULL && s2->coord.y < pymax)
846 y2 = s2->coord.y;
847
848 if(y2<pymin)
849 {
850 //printf("\nClipped (2) y2 = %f to %f",y2,pymin);
851 y2 = pymin;
852 //return;
853 }
854 x2 = (e->c) - (e->b) * y2;
855 if (((x1> pxmax) & (x2>pxmax)) | ((x1<pxmin)&(x2<pxmin)))
856 {
857 //printf("\nClipLine jumping out(3), x1 = %f, pxmin = %f, pxmax = %f",x1,pxmin,pxmax);
858 return;
859 }
860 if(x1> pxmax)
861 { x1 = pxmax; y1 = (e->c - x1)/e->b;};
862 if(x1<pxmin)
863 { x1 = pxmin; y1 = (e->c - x1)/e->b;};
864 if(x2>pxmax)
865 { x2 = pxmax; y2 = (e->c - x2)/e->b;};
866 if(x2<pxmin)
867 { x2 = pxmin; y2 = (e->c - x2)/e->b;};
868 }
869 else
870 {
871 x1 = pxmin;
872 if (s1!=(Site *)NULL && s1->coord.x > pxmin)
873 x1 = s1->coord.x;
874 if(x1>pxmax)
875 {
876 //printf("\nClipped (3) x1 = %f to %f",x1,pxmin);
877 //return;
878 x1 = pxmax;
879 }
880 y1 = e->c - e->a * x1;
881 x2 = pxmax;
882 if (s2!=(Site *)NULL && s2->coord.x < pxmax)
883 x2 = s2->coord.x;
884 if(x2<pxmin)
885 {
886 //printf("\nClipped (4) x2 = %f to %f",x2,pxmin);
887 //return;
888 x2 = pxmin;
889 }
890 y2 = e->c - e->a * x2;
891 if (((y1> pymax) & (y2>pymax)) | ((y1<pymin)&(y2<pymin)))
892 {
893 //printf("\nClipLine jumping out(6), y1 = %f, pymin = %f, pymax = %f",y2,pymin,pymax);
894 return;
895 }
896 if(y1> pymax)
897 { y1 = pymax; x1 = (e->c - y1)/e->a;};
898 if(y1<pymin)
899 { y1 = pymin; x1 = (e->c - y1)/e->a;};
900 if(y2>pymax)
901 { y2 = pymax; x2 = (e->c - y2)/e->a;};
902 if(y2<pymin)
903 { y2 = pymin; x2 = (e->c - y2)/e->a;};
904 };
905
906 //printf("\nPushing line (%f,%f,%f,%f)",x1,y1,x2,y2);
907 //fprintf(stdout, "Line with vertices (%f,%f) and (%f,%f)\n",
908 // e->reg[0]->coord.x, e->reg[1]->coord.x, e->reg[0]->coord.y, e->reg[1]->coord.y);
909 pushGraphEdge(x1,y1,x2,y2,e->reg[0],e->reg[1]);
910}
911
912
913/* implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax,
914 deltax, deltay (can all be estimates).
915 Performance suffers if they are wrong; better to make nsites,
916 deltax, and deltay too big than too small. (?) */
917
918bool VoronoiDiagramGenerator::voronoi(int triangulate)
919{
920 Site *newsite, *bot, *top, *temp, *p;
921 Site *v;
922 Point newintstar;
923 int pm;
924 Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector;
925 Edge *e;
926
927 PQinitialize();
928 bottomsite = nextone();
929 out_site(bottomsite);
930 bool retval = ELinitialize();
931
932 if(!retval)
933 return false;
934
935 newsite = nextone();
936 while(1)
937 {
938
939 if(!PQempty())
940 newintstar = PQ_min();
941
942 //if the lowest site has a smaller y value than the lowest vector intersection, process the site
943 //otherwise process the vector intersection
944 if (newsite != (Site *)NULL){
945 volatile double local_newsite_coord_y = newsite->coord.y;
946 volatile double local_newintstar_y = newintstar.y;
947 if (PQempty() || local_newsite_coord_y < local_newintstar_y
948 || ( local_newsite_coord_y == local_newintstar_y && newsite->coord.x < newintstar.x))
949 {/* new site is smallest - this is a site event*/
950 out_site(newsite); //output the site
951 lbnd = ELleftbnd(&(newsite->coord)); //get the first HalfEdge to the LEFT of the new site
952 rbnd = ELright(lbnd); //get the first HalfEdge to the RIGHT of the new site
953 bot = rightreg(lbnd); //if this halfedge has no edge, , bot = bottom site (whatever that is)
954 e = bisect(bot, newsite); //create a new edge that bisects
955 bisector = HEcreate(e, le); //create a new HalfEdge, setting its ELpm field to 0
956 ELinsert(lbnd, bisector); //insert this new bisector edge between the left and right vectors in a linked list
957
958 if ((p = intersect(lbnd, bisector)) != (Site *) NULL) //if the new bisector intersects with the left edge, remove the left edge's vertex, and put in the new one
959 {
960 PQdelete(lbnd);
961 PQinsert(lbnd, p, dist(p,newsite));
962 };
963 lbnd = bisector;
964 bisector = HEcreate(e, re); //create a new HalfEdge, setting its ELpm field to 1
965 ELinsert(lbnd, bisector); //insert the new HE to the right of the original bisector earlier in the IF stmt
966
967 if ((p = intersect(bisector, rbnd)) != (Site *) NULL) //if this new bisector intersects with the
968 {
969 PQinsert(bisector, p, dist(p,newsite)); //push the HE into the ordered linked list of vertices
970 };
971 newsite = nextone();
972 }
973 else if (!PQempty()) /* intersection is smallest - this is a vector event */
974 {
975 lbnd = PQextractmin(); //pop the HalfEdge with the lowest vector off the ordered list of vectors
976 llbnd = ELleft(lbnd); //get the HalfEdge to the left of the above HE
977 rbnd = ELright(lbnd); //get the HalfEdge to the right of the above HE
978 rrbnd = ELright(rbnd); //get the HalfEdge to the right of the HE to the right of the lowest HE
979 bot = leftreg(lbnd); //get the Site to the left of the left HE which it bisects
980 top = rightreg(rbnd); //get the Site to the right of the right HE which it bisects
981
982 out_triple(bot, top, rightreg(lbnd)); //output the triple of sites, stating that a circle goes through them
983
984 v = lbnd->vertex; //get the vertex that caused this event
985 makevertex(v); //set the vertex number - couldn't do this earlier since we didn't know when it would be processed
986 endpoint(lbnd->ELedge,lbnd->ELpm,v); //set the endpoint of the left HalfEdge to be this vector
987 endpoint(rbnd->ELedge,rbnd->ELpm,v); //set the endpoint of the right HalfEdge to be this vector
988 ELdelete(lbnd); //mark the lowest HE for deletion - can't delete yet because there might be pointers to it in Hash Map
989 PQdelete(rbnd); //remove all vertex events to do with the right HE
990 ELdelete(rbnd); //mark the right HE for deletion - can't delete yet because there might be pointers to it in Hash Map
991 pm = le; //set the pm variable to zero
992
993 if (bot->coord.y > top->coord.y) //if the site to the left of the event is higher than the Site
994 { //to the right of it, then swap them and set the 'pm' variable to 1
995 temp = bot;
996 bot = top;
997 top = temp;
998 pm = re;
999 }
1000 e = bisect(bot, top); //create an Edge (or line) that is between the two Sites. This creates
1001 //the formula of the line, and assigns a line number to it
1002 bisector = HEcreate(e, pm); //create a HE from the Edge 'e', and make it point to that edge with its ELedge field
1003 ELinsert(llbnd, bisector); //insert the new bisector to the right of the left HE
1004 endpoint(e, re-pm, v); //set one endpoint to the new edge to be the vector point 'v'.
1005 //If the site to the left of this bisector is higher than the right
1006 //Site, then this endpoint is put in position 0; otherwise in pos 1
1007 deref(v); //delete the vector 'v'
1008
1009 //if left HE and the new bisector don't intersect, then delete the left HE, and reinsert it
1010 if((p = intersect(llbnd, bisector)) != (Site *) NULL)
1011 {
1012 PQdelete(llbnd);
1013 PQinsert(llbnd, p, dist(p,bot));
1014 };
1015
1016 //if right HE and the new bisector don't intersect, then reinsert it
1017 if ((p = intersect(bisector, rrbnd)) != (Site *) NULL)
1018 {
1019 PQinsert(bisector, p, dist(p,bot));
1020 };
1021 }
1022 } else break;
1023 };
1024
1025
1026
1027
1028 for(lbnd=ELright(ELleftend); lbnd != ELrightend; lbnd=ELright(lbnd))
1029 {
1030 e = lbnd->ELedge;
1031
1032 clip_line(e);
1033 };
1034
1035 //cleanup();
1036
1037 return true;
1038
1039}
1040
1041
1042int scomp(const void *p1,const void *p2)
1043{
1044 Point *s1 = (Point*)p1, *s2=(Point*)p2;
1045 if(s1->y < s2->y) return(-1);
1046 if(s1->y > s2->y) return(1);
1047 if(s1->x < s2->x) return(-1);
1048 if(s1->x > s2->x) return(1);
1049 return(0);
1050}
1051
1052/* return a single in-storage site */
1053Site * VoronoiDiagramGenerator::nextone()
1054{
1055 Site *s;
1056 if(siteidx < nsites)
1057 {
1058 s = &sites[siteidx];
1059 siteidx += 1;
1060 return(s);
1061 }
1062 else
1063 return( (Site *)NULL);
1064}
1065
1066FASTJET_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.