[11] | 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 |
|
---|
| 60 | using namespace std;
|
---|
| 61 |
|
---|
| 62 | FASTJET_BEGIN_NAMESPACE
|
---|
| 63 |
|
---|
| 64 | VoronoiDiagramGenerator::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 |
|
---|
| 81 | VoronoiDiagramGenerator::~VoronoiDiagramGenerator(){
|
---|
| 82 | cleanup();
|
---|
| 83 | cleanupEdges();
|
---|
| 84 |
|
---|
| 85 | if (allMemoryList != NULL)
|
---|
| 86 | delete allMemoryList;
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 |
|
---|
| 90 |
|
---|
| 91 | bool 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 |
|
---|
| 166 | bool 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 |
|
---|
| 190 | Halfedge* 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 |
|
---|
| 202 | void 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 */
|
---|
| 212 | Halfedge* 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 |
|
---|
| 229 | Halfedge * 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. */
|
---|
| 287 | void VoronoiDiagramGenerator::ELdelete(Halfedge *he){
|
---|
| 288 | (he->ELleft)->ELright = he->ELright;
|
---|
| 289 | (he->ELright)->ELleft = he->ELleft;
|
---|
| 290 | he->ELedge = (Edge*) DELETED;
|
---|
| 291 | }
|
---|
| 292 |
|
---|
| 293 |
|
---|
| 294 | Halfedge* VoronoiDiagramGenerator::ELright(Halfedge *he){
|
---|
| 295 | return he->ELright;
|
---|
| 296 | }
|
---|
| 297 |
|
---|
| 298 |
|
---|
| 299 | Halfedge* VoronoiDiagramGenerator::ELleft(Halfedge *he){
|
---|
| 300 | return he->ELleft;
|
---|
| 301 | }
|
---|
| 302 |
|
---|
| 303 |
|
---|
| 304 | Site * 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 |
|
---|
| 312 | Site * 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 |
|
---|
| 325 | void 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 |
|
---|
| 338 | Edge * 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
|
---|
| 384 | Site* 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 */
|
---|
| 436 | int 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 |
|
---|
| 480 | void 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 |
|
---|
| 495 | double 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 |
|
---|
| 504 | void VoronoiDiagramGenerator::makevertex(Site *v)
|
---|
| 505 | {
|
---|
| 506 | v->sitenbr = nvertices;
|
---|
| 507 | nvertices += 1;
|
---|
| 508 | out_vertex(v);
|
---|
| 509 | }
|
---|
| 510 |
|
---|
| 511 |
|
---|
| 512 | void VoronoiDiagramGenerator::deref(Site *v)
|
---|
| 513 | {
|
---|
| 514 | v->refcnt -= 1;
|
---|
| 515 | if (v->refcnt == 0 )
|
---|
| 516 | makefree((Freenode*)v, &sfl);
|
---|
| 517 | }
|
---|
| 518 |
|
---|
| 519 | void VoronoiDiagramGenerator::ref(Site *v)
|
---|
| 520 | {
|
---|
| 521 | v->refcnt += 1;
|
---|
| 522 | }
|
---|
| 523 |
|
---|
| 524 | //push the HalfEdge into the ordered linked list of vertices
|
---|
| 525 | void 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
|
---|
| 545 | void 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 |
|
---|
| 562 | int 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 |
|
---|
| 575 | int VoronoiDiagramGenerator::PQempty()
|
---|
| 576 | {
|
---|
| 577 | return(PQcount==0);
|
---|
| 578 | }
|
---|
| 579 |
|
---|
| 580 |
|
---|
| 581 | Point 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 |
|
---|
| 591 | Halfedge * 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 |
|
---|
| 602 | bool 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 |
|
---|
| 621 | void VoronoiDiagramGenerator::freeinit(Freelist *fl,int size)
|
---|
| 622 | {
|
---|
| 623 | fl->head = (Freenode *) NULL;
|
---|
| 624 | fl->nodesize = size;
|
---|
| 625 | }
|
---|
| 626 |
|
---|
| 627 | char * 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 |
|
---|
| 654 | void VoronoiDiagramGenerator::makefree(Freenode *curr,Freelist *fl)
|
---|
| 655 | {
|
---|
| 656 | curr->nextfree = fl->head;
|
---|
| 657 | fl->head = curr;
|
---|
| 658 | }
|
---|
| 659 |
|
---|
| 660 | void 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 |
|
---|
| 698 | void 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 |
|
---|
| 713 | void 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 |
|
---|
| 729 | char * 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> */
|
---|
| 740 | void VoronoiDiagramGenerator::openpl(){}
|
---|
| 741 | void VoronoiDiagramGenerator::circle(double x, double y, double radius){}
|
---|
| 742 | void VoronoiDiagramGenerator::range(double minX, double minY, double maxX, double maxY){}
|
---|
| 743 |
|
---|
| 744 |
|
---|
| 745 |
|
---|
| 746 | void VoronoiDiagramGenerator::out_bisector(Edge *e)
|
---|
| 747 | {
|
---|
| 748 |
|
---|
| 749 |
|
---|
| 750 | }
|
---|
| 751 |
|
---|
| 752 |
|
---|
| 753 | void VoronoiDiagramGenerator::out_ep(Edge *e)
|
---|
| 754 | {
|
---|
| 755 |
|
---|
| 756 |
|
---|
| 757 | }
|
---|
| 758 |
|
---|
| 759 | void VoronoiDiagramGenerator::out_vertex(Site *v)
|
---|
| 760 | {
|
---|
| 761 |
|
---|
| 762 | }
|
---|
| 763 |
|
---|
| 764 |
|
---|
| 765 | void VoronoiDiagramGenerator::out_site(Site *s)
|
---|
| 766 | {
|
---|
| 767 | if(!triangulate & plot & !debug)
|
---|
| 768 | circle (s->coord.x, s->coord.y, cradius);
|
---|
| 769 |
|
---|
| 770 | }
|
---|
| 771 |
|
---|
| 772 |
|
---|
| 773 | void VoronoiDiagramGenerator::out_triple(Site *s1, Site *s2,Site * s3)
|
---|
| 774 | {
|
---|
| 775 |
|
---|
| 776 | }
|
---|
| 777 |
|
---|
| 778 |
|
---|
| 779 |
|
---|
| 780 | void 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 |
|
---|
| 797 | void 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 |
|
---|
| 918 | bool 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 |
|
---|
| 1042 | int 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 */
|
---|
| 1053 | Site * 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 |
|
---|
| 1066 | FASTJET_END_NAMESPACE
|
---|