github.com/joshvarga/voronoi@v0.0.0-20180211004454-2fd26fbdfffb/voronoi.go (about) 1 // MIT License: See https://github.com/pzsz/voronoi/LICENSE.md 2 3 // Author: Przemyslaw Szczepaniak (przeszczep@gmail.com) 4 // Port of Raymond Hill's (rhill@raymondhill.net) javascript implementation 5 // of Steven Forune's algorithm to compute Voronoi diagrams 6 7 package voronoi 8 9 import "math" 10 import "sort" 11 import "fmt" 12 13 type Voronoi struct { 14 cells []*Cell 15 edges []*Edge 16 17 cellsMap map[Vertex]*Cell 18 19 beachline rbTree 20 circleEvents rbTree 21 firstCircleEvent *circleEvent 22 } 23 24 type Diagram struct { 25 Cells []*Cell 26 Edges []*Edge 27 // EdgesVertices map[Vertex]EdgeVertex 28 } 29 30 func (s *Voronoi) getCell(site Vertex) *Cell { 31 ret := s.cellsMap[site] 32 if ret == nil { 33 panic(fmt.Sprintf("Couldn't find cell for site %v", site)) 34 } 35 return ret 36 } 37 38 func (s *Voronoi) createEdge(LeftCell, RightCell *Cell, va, vb Vertex) *Edge { 39 edge := newEdge(LeftCell, RightCell) 40 s.edges = append(s.edges, edge) 41 if va != NO_VERTEX { 42 s.setEdgeStartpoint(edge, LeftCell, RightCell, va) 43 } 44 45 if vb != NO_VERTEX { 46 s.setEdgeEndpoint(edge, LeftCell, RightCell, vb) 47 } 48 49 lCell := LeftCell 50 rCell := RightCell 51 52 lCell.Halfedges = append(lCell.Halfedges, newHalfedge(edge, LeftCell, RightCell)) 53 rCell.Halfedges = append(rCell.Halfedges, newHalfedge(edge, RightCell, LeftCell)) 54 return edge 55 } 56 57 func (s *Voronoi) createBorderEdge(LeftCell *Cell, va, vb Vertex) *Edge { 58 edge := newEdge(LeftCell, nil) 59 edge.Va.Vertex = va 60 edge.Vb.Vertex = vb 61 62 s.edges = append(s.edges, edge) 63 return edge 64 } 65 66 func (s *Voronoi) setEdgeStartpoint(edge *Edge, LeftCell, RightCell *Cell, vertex Vertex) { 67 if edge.Va.Vertex == NO_VERTEX && edge.Vb.Vertex == NO_VERTEX { 68 edge.Va.Vertex = vertex 69 edge.LeftCell = LeftCell 70 edge.RightCell = RightCell 71 } else if edge.LeftCell == RightCell { 72 edge.Vb.Vertex = vertex 73 } else { 74 edge.Va.Vertex = vertex 75 } 76 } 77 78 func (s *Voronoi) setEdgeEndpoint(edge *Edge, LeftCell, RightCell *Cell, vertex Vertex) { 79 s.setEdgeStartpoint(edge, RightCell, LeftCell, vertex) 80 } 81 82 type Beachsection struct { 83 node *rbNode 84 site Vertex 85 circleEvent *circleEvent 86 edge *Edge 87 } 88 89 // rbNodeValue intergface 90 func (s *Beachsection) bindToNode(node *rbNode) { 91 s.node = node 92 } 93 94 // rbNodeValue intergface 95 func (s *Beachsection) getNode() *rbNode { 96 return s.node 97 } 98 99 // Calculate the left break point of a particular beach section, 100 // given a particular sweep line 101 func leftBreakPoint(arc *Beachsection, directrix float64) float64 { 102 site := arc.site 103 rfocx := site.X 104 rfocy := site.Y 105 pby2 := rfocy - directrix 106 // parabola in degenerate case where focus is on directrix 107 if pby2 == 0 { 108 return rfocx 109 } 110 111 lArc := arc.getNode().previous 112 if lArc == nil { 113 return math.Inf(-1) 114 } 115 site = lArc.value.(*Beachsection).site 116 lfocx := site.X 117 lfocy := site.Y 118 plby2 := lfocy - directrix 119 // parabola in degenerate case where focus is on directrix 120 if plby2 == 0 { 121 return lfocx 122 } 123 hl := lfocx - rfocx 124 aby2 := 1/pby2 - 1/plby2 125 b := hl / plby2 126 if aby2 != 0 { 127 return (-b+math.Sqrt(b*b-2*aby2*(hl*hl/(-2*plby2)-lfocy+plby2/2+rfocy-pby2/2)))/aby2 + rfocx 128 } 129 // both parabolas have same distance to directrix, thus break point is midway 130 return (rfocx + lfocx) / 2 131 } 132 133 // calculate the right break point of a particular beach section, 134 // given a particular directrix 135 func rightBreakPoint(arc *Beachsection, directrix float64) float64 { 136 rArc := arc.getNode().next 137 if rArc != nil { 138 return leftBreakPoint(rArc.value.(*Beachsection), directrix) 139 } 140 site := arc.site 141 if site.Y == directrix { 142 return site.X 143 } 144 return math.Inf(1) 145 } 146 147 func (s *Voronoi) detachBeachsection(arc *Beachsection) { 148 s.detachCircleEvent(arc) 149 s.beachline.removeNode(arc.node) 150 } 151 152 type BeachsectionPtrs []*Beachsection 153 154 func (s *BeachsectionPtrs) appendLeft(b *Beachsection) { 155 *s = append(*s, b) 156 for id := len(*s) - 1; id > 0; id-- { 157 (*s)[id] = (*s)[id-1] 158 } 159 (*s)[0] = b 160 } 161 162 func (s *BeachsectionPtrs) appendRight(b *Beachsection) { 163 *s = append(*s, b) 164 } 165 166 func (s *Voronoi) removeBeachsection(beachsection *Beachsection) { 167 circle := beachsection.circleEvent 168 x := circle.x 169 y := circle.ycenter 170 vertex := Vertex{X:x, Y: y} 171 previous := beachsection.node.previous 172 next := beachsection.node.next 173 disappearingTransitions := BeachsectionPtrs{beachsection} 174 175 // remove collapsed beachsection from beachline 176 s.detachBeachsection(beachsection) 177 178 // there could be more than one empty arc at the deletion point, this 179 // happens when more than two edges are linked by the same vertex, 180 // so we will collect all those edges by looking up both sides of 181 // the deletion point. 182 // by the way, there is *always* a predecessor/successor to any collapsed 183 // beach section, it's just impossible to have a collapsing first/last 184 // beach sections on the beachline, since they obviously are unconstrained 185 // on their left/right side. 186 187 // look left 188 lArc := previous.value.(*Beachsection) 189 for lArc.circleEvent != nil && 190 math.Abs(x-lArc.circleEvent.x) < 1e-9 && 191 math.Abs(y-lArc.circleEvent.ycenter) < 1e-9 { 192 193 previous = lArc.node.previous 194 disappearingTransitions.appendLeft(lArc) 195 s.detachBeachsection(lArc) // mark for reuse 196 lArc = previous.value.(*Beachsection) 197 } 198 // even though it is not disappearing, I will also add the beach section 199 // immediately to the left of the left-most collapsed beach section, for 200 // convenience, since we need to refer to it later as this beach section 201 // is the 'left' site of an edge for which a start point is set. 202 disappearingTransitions.appendLeft(lArc) 203 s.detachCircleEvent(lArc) 204 205 // look right 206 var rArc = next.value.(*Beachsection) 207 for rArc.circleEvent != nil && 208 math.Abs(x-rArc.circleEvent.x) < 1e-9 && 209 math.Abs(y-rArc.circleEvent.ycenter) < 1e-9 { 210 next = rArc.node.next 211 disappearingTransitions.appendRight(rArc) 212 s.detachBeachsection(rArc) // mark for reuse 213 rArc = next.value.(*Beachsection) 214 } 215 // we also have to add the beach section immediately to the right of the 216 // right-most collapsed beach section, since there is also a disappearing 217 // transition representing an edge's start point on its left. 218 disappearingTransitions.appendRight(rArc) 219 s.detachCircleEvent(rArc) 220 221 // walk through all the disappearing transitions between beach sections and 222 // set the start point of their (implied) edge. 223 nArcs := len(disappearingTransitions) 224 225 for iArc := 1; iArc < nArcs; iArc++ { 226 rArc = disappearingTransitions[iArc] 227 lArc = disappearingTransitions[iArc-1] 228 229 lSite := s.getCell(lArc.site) 230 rSite := s.getCell(rArc.site) 231 232 s.setEdgeStartpoint(rArc.edge, lSite, rSite, vertex) 233 } 234 235 // create a new edge as we have now a new transition between 236 // two beach sections which were previously not adjacent. 237 // since this edge appears as a new vertex is defined, the vertex 238 // actually define an end point of the edge (relative to the site 239 // on the left) 240 lArc = disappearingTransitions[0] 241 rArc = disappearingTransitions[nArcs-1] 242 lSite := s.getCell(lArc.site) 243 rSite := s.getCell(rArc.site) 244 245 rArc.edge = s.createEdge(lSite, rSite, NO_VERTEX, vertex) 246 247 // create circle events if any for beach sections left in the beachline 248 // adjacent to collapsed sections 249 s.attachCircleEvent(lArc) 250 s.attachCircleEvent(rArc) 251 } 252 253 func (s *Voronoi) addBeachsection(site Vertex) { 254 x := site.X 255 directrix := site.Y 256 257 // find the left and right beach sections which will surround the newly 258 // created beach section. 259 // rhill 2011-06-01: This loop is one of the most often executed, 260 // hence we expand in-place the comparison-against-epsilon calls. 261 var lNode, rNode *rbNode 262 var dxl, dxr float64 263 node := s.beachline.root 264 265 for node != nil { 266 nodeBeachline := node.value.(*Beachsection) 267 dxl = leftBreakPoint(nodeBeachline, directrix) - x 268 // x lessThanWithEpsilon xl => falls somewhere before the left edge of the beachsection 269 if dxl > 1e-9 { 270 // this case should never happen 271 // if (!node.rbLeft) { 272 // rNode = node.rbLeft; 273 // break; 274 // } 275 node = node.left 276 } else { 277 dxr = x - rightBreakPoint(nodeBeachline, directrix) 278 // x greaterThanWithEpsilon xr => falls somewhere after the right edge of the beachsection 279 if dxr > 1e-9 { 280 if node.right == nil { 281 lNode = node 282 break 283 } 284 node = node.right 285 } else { 286 // x equalWithEpsilon xl => falls exactly on the left edge of the beachsection 287 if dxl > -1e-9 { 288 lNode = node.previous 289 rNode = node 290 } else if dxr > -1e-9 { 291 // x equalWithEpsilon xr => falls exactly on the right edge of the beachsection 292 lNode = node 293 rNode = node.next 294 // falls exactly somewhere in the middle of the beachsection 295 } else { 296 lNode = node 297 rNode = node 298 } 299 break 300 } 301 } 302 } 303 304 var lArc, rArc *Beachsection 305 306 if lNode != nil { 307 lArc = lNode.value.(*Beachsection) 308 } 309 if rNode != nil { 310 rArc = rNode.value.(*Beachsection) 311 } 312 313 // at this point, keep in mind that lArc and/or rArc could be 314 // undefined or null. 315 316 // create a new beach section object for the site and add it to RB-tree 317 newArc := &Beachsection{site: site} 318 if lArc == nil { 319 s.beachline.insertSuccessor(nil, newArc) 320 } else { 321 s.beachline.insertSuccessor(lArc.node, newArc) 322 } 323 324 // cases: 325 // 326 327 // [null,null] 328 // least likely case: new beach section is the first beach section on the 329 // beachline. 330 // This case means: 331 // no new transition appears 332 // no collapsing beach section 333 // new beachsection become root of the RB-tree 334 if lArc == nil && rArc == nil { 335 return 336 } 337 338 // [lArc,rArc] where lArc == rArc 339 // most likely case: new beach section split an existing beach 340 // section. 341 // This case means: 342 // one new transition appears 343 // the left and right beach section might be collapsing as a result 344 // two new nodes added to the RB-tree 345 if lArc == rArc { 346 // invalidate circle event of split beach section 347 s.detachCircleEvent(lArc) 348 349 // split the beach section into two separate beach sections 350 rArc = &Beachsection{site: lArc.site} 351 s.beachline.insertSuccessor(newArc.node, rArc) 352 353 // since we have a new transition between two beach sections, 354 // a new edge is born 355 lCell := s.getCell(lArc.site) 356 newCell := s.getCell(newArc.site) 357 newArc.edge = s.createEdge(lCell, newCell, NO_VERTEX, NO_VERTEX) 358 rArc.edge = newArc.edge 359 360 // check whether the left and right beach sections are collapsing 361 // and if so create circle events, to be notified when the point of 362 // collapse is reached. 363 s.attachCircleEvent(lArc) 364 s.attachCircleEvent(rArc) 365 return 366 } 367 368 // [lArc,null] 369 // even less likely case: new beach section is the *last* beach section 370 // on the beachline -- this can happen *only* if *all* the previous beach 371 // sections currently on the beachline share the same y value as 372 // the new beach section. 373 // This case means: 374 // one new transition appears 375 // no collapsing beach section as a result 376 // new beach section become right-most node of the RB-tree 377 if lArc != nil && rArc == nil { 378 lCell := s.getCell(lArc.site) 379 newCell := s.getCell(newArc.site) 380 newArc.edge = s.createEdge(lCell, newCell, NO_VERTEX, NO_VERTEX) 381 return 382 } 383 384 // [null,rArc] 385 // impossible case: because sites are strictly processed from top to bottom, 386 // and left to right, which guarantees that there will always be a beach section 387 // on the left -- except of course when there are no beach section at all on 388 // the beach line, which case was handled above. 389 // rhill 2011-06-02: No point testing in non-debug version 390 //if (!lArc && rArc) { 391 // throw "Voronoi.addBeachsection(): What is this I don't even"; 392 // } 393 394 // [lArc,rArc] where lArc != rArc 395 // somewhat less likely case: new beach section falls *exactly* in between two 396 // existing beach sections 397 // This case means: 398 // one transition disappears 399 // two new transitions appear 400 // the left and right beach section might be collapsing as a result 401 // only one new node added to the RB-tree 402 if lArc != rArc { 403 // invalidate circle events of left and right sites 404 s.detachCircleEvent(lArc) 405 s.detachCircleEvent(rArc) 406 407 // an existing transition disappears, meaning a vertex is defined at 408 // the disappearance point. 409 // since the disappearance is caused by the new beachsection, the 410 // vertex is at the center of the circumscribed circle of the left, 411 // new and right beachsections. 412 // http://mathforum.org/library/drmath/view/55002.html 413 // Except that I bring the origin at A to simplify 414 // calculation 415 LeftSite := lArc.site 416 ax := LeftSite.X 417 ay := LeftSite.Y 418 bx := site.X - ax 419 by := site.Y - ay 420 RightSite := rArc.site 421 cx := RightSite.X - ax 422 cy := RightSite.Y - ay 423 d := 2 * (bx*cy - by*cx) 424 hb := bx*bx + by*by 425 hc := cx*cx + cy*cy 426 vertex := Vertex{X:(cy*hb-by*hc)/d + ax,Y: (bx*hc-cx*hb)/d + ay} 427 428 lCell := s.getCell(LeftSite) 429 cell := s.getCell(site) 430 rCell := s.getCell(RightSite) 431 432 // one transition disappear 433 s.setEdgeStartpoint(rArc.edge, lCell, rCell, vertex) 434 435 // two new transitions appear at the new vertex location 436 newArc.edge = s.createEdge(lCell, cell, NO_VERTEX, vertex) 437 rArc.edge = s.createEdge(cell, rCell, NO_VERTEX, vertex) 438 439 // check whether the left and right beach sections are collapsing 440 // and if so create circle events, to handle the point of collapse. 441 s.attachCircleEvent(lArc) 442 s.attachCircleEvent(rArc) 443 return 444 } 445 } 446 447 type circleEvent struct { 448 node *rbNode 449 site Vertex 450 arc *Beachsection 451 x float64 452 y float64 453 ycenter float64 454 } 455 456 func (s *circleEvent) bindToNode(node *rbNode) { 457 s.node = node 458 } 459 460 func (s *circleEvent) getNode() *rbNode { 461 return s.node 462 } 463 464 func (s *Voronoi) attachCircleEvent(arc *Beachsection) { 465 lArc := arc.node.previous 466 rArc := arc.node.next 467 if lArc == nil || rArc == nil { 468 return // does that ever happen? 469 } 470 LeftSite := lArc.value.(*Beachsection).site 471 cSite := arc.site 472 RightSite := rArc.value.(*Beachsection).site 473 474 // If site of left beachsection is same as site of 475 // right beachsection, there can't be convergence 476 if LeftSite == RightSite { 477 return 478 } 479 480 // Find the circumscribed circle for the three sites associated 481 // with the beachsection triplet. 482 // rhill 2011-05-26: It is more efficient to calculate in-place 483 // rather than getting the resulting circumscribed circle from an 484 // object returned by calling Voronoi.circumcircle() 485 // http://mathforum.org/library/drmath/view/55002.html 486 // Except that I bring the origin at cSite to simplify calculations. 487 // The bottom-most part of the circumcircle is our Fortune 'circle 488 // event', and its center is a vertex potentially part of the final 489 // Voronoi diagram. 490 bx := cSite.X 491 by := cSite.Y 492 ax := LeftSite.X - bx 493 ay := LeftSite.Y - by 494 cx := RightSite.X - bx 495 cy := RightSite.Y - by 496 497 // If points l->c->r are clockwise, then center beach section does not 498 // collapse, hence it can't end up as a vertex (we reuse 'd' here, which 499 // sign is reverse of the orientation, hence we reverse the test. 500 // http://en.wikipedia.org/wiki/Curve_orientation#Orientation_of_a_simple_polygon 501 // rhill 2011-05-21: Nasty finite precision error which caused circumcircle() to 502 // return infinites: 1e-12 seems to fix the problem. 503 d := 2 * (ax*cy - ay*cx) 504 if d >= -2e-12 { 505 return 506 } 507 508 ha := ax*ax + ay*ay 509 hc := cx*cx + cy*cy 510 x := (cy*ha - ay*hc) / d 511 y := (ax*hc - cx*ha) / d 512 ycenter := y + by 513 514 // Important: ybottom should always be under or at sweep, so no need 515 // to waste CPU cycles by checking 516 517 // recycle circle event object if possible 518 circleEventInst := &circleEvent{ 519 arc: arc, 520 site: cSite, 521 x: x + bx, 522 y: ycenter + math.Sqrt(x*x+y*y), 523 ycenter: ycenter, 524 } 525 526 arc.circleEvent = circleEventInst 527 528 // find insertion point in RB-tree: circle events are ordered from 529 // smallest to largest 530 var predecessor *rbNode = nil 531 node := s.circleEvents.root 532 for node != nil { 533 nodeValue := node.value.(*circleEvent) 534 if circleEventInst.y < nodeValue.y || (circleEventInst.y == nodeValue.y && circleEventInst.x <= nodeValue.x) { 535 if node.left != nil { 536 node = node.left 537 } else { 538 predecessor = node.previous 539 break 540 } 541 } else { 542 if node.right != nil { 543 node = node.right 544 } else { 545 predecessor = node 546 break 547 } 548 } 549 } 550 s.circleEvents.insertSuccessor(predecessor, circleEventInst) 551 if predecessor == nil { 552 s.firstCircleEvent = circleEventInst 553 } 554 } 555 556 func (s *Voronoi) detachCircleEvent(arc *Beachsection) { 557 circle := arc.circleEvent 558 if circle != nil { 559 if circle.node.previous == nil { 560 if circle.node.next != nil { 561 s.firstCircleEvent = circle.node.next.value.(*circleEvent) 562 } else { 563 s.firstCircleEvent = nil 564 } 565 } 566 s.circleEvents.removeNode(circle.node) // remove from RB-tree 567 arc.circleEvent = nil 568 } 569 } 570 571 // Bounding Box 572 type BBox struct { 573 Xl, Xr, Yt, Yb float64 574 } 575 576 // Create new Bounding Box 577 func NewBBox(xl, xr, yt, yb float64) BBox { 578 return BBox{xl, xr, yt, yb} 579 } 580 581 // connect dangling edges (not if a cursory test tells us 582 // it is not going to be visible. 583 // return value: 584 // false: the dangling endpoint couldn't be connected 585 // true: the dangling endpoint could be connected 586 func connectEdge(edge *Edge, bbox BBox) bool { 587 // skip if end point already connected 588 vb := edge.Vb.Vertex 589 if vb != NO_VERTEX { 590 return true 591 } 592 593 // make local copy for performance purpose 594 va := edge.Va.Vertex 595 xl := bbox.Xl 596 xr := bbox.Xr 597 yt := bbox.Yt 598 yb := bbox.Yb 599 LeftSite := edge.LeftCell.Site 600 RightSite := edge.RightCell.Site 601 lx := LeftSite.X 602 ly := LeftSite.Y 603 rx := RightSite.X 604 ry := RightSite.Y 605 fx := (lx + rx) / 2 606 fy := (ly + ry) / 2 607 608 var fm, fb float64 609 610 // get the line equation of the bisector if line is not vertical 611 if !equalWithEpsilon(ry, ly) { 612 fm = (lx - rx) / (ry - ly) 613 fb = fy - fm*fx 614 } 615 616 // remember, direction of line (relative to left site): 617 // upward: left.X < right.X 618 // downward: left.X > right.X 619 // horizontal: left.X == right.X 620 // upward: left.X < right.X 621 // rightward: left.Y < right.Y 622 // leftward: left.Y > right.Y 623 // vertical: left.Y == right.Y 624 625 // depending on the direction, find the best side of the 626 // bounding box to use to determine a reasonable start point 627 628 // special case: vertical line 629 if equalWithEpsilon(ry, ly) { 630 // doesn't intersect with viewport 631 if fx < xl || fx >= xr { 632 return false 633 } 634 // downward 635 if lx > rx { 636 if va == NO_VERTEX { 637 va = Vertex{X:fx,Y: yt} 638 } else if va.Y >= yb { 639 return false 640 } 641 vb = Vertex{X:fx, Y:yb} 642 // upward 643 } else { 644 if va == NO_VERTEX { 645 va = Vertex{X:fx, Y:yb} 646 } else if va.Y < yt { 647 return false 648 } 649 vb = Vertex{X:fx, Y:yt} 650 } 651 // closer to vertical than horizontal, connect start point to the 652 // top or bottom side of the bounding box 653 } else if fm < -1 || fm > 1 { 654 // downward 655 if lx > rx { 656 if va == NO_VERTEX { 657 va = Vertex{X:(yt - fb) / fm, Y: yt} 658 } else if va.Y >= yb { 659 return false 660 } 661 vb = Vertex{X:(yb - fb) / fm, Y:yb} 662 // upward 663 } else { 664 if va == NO_VERTEX { 665 va = Vertex{X:(yb - fb) / fm, Y: yb} 666 } else if va.Y < yt { 667 return false 668 } 669 vb = Vertex{X:(yt - fb) / fm, Y: yt} 670 } 671 // closer to horizontal than vertical, connect start point to the 672 // left or right side of the bounding box 673 } else { 674 // rightward 675 if ly < ry { 676 if va == NO_VERTEX { 677 va = Vertex{X:xl, Y: fm*xl + fb} 678 } else if va.X >= xr { 679 return false 680 } 681 vb = Vertex{X:xr, Y:fm*xr + fb} 682 // leftward 683 } else { 684 if va == NO_VERTEX { 685 va = Vertex{X:xr, Y: fm*xr + fb} 686 } else if va.X < xl { 687 return false 688 } 689 vb = Vertex{X:xl,Y: fm*xl + fb} 690 } 691 } 692 edge.Va.Vertex = va 693 edge.Vb.Vertex = vb 694 return true 695 } 696 697 // line-clipping code taken from: 698 // Liang-Barsky function by Daniel White 699 // http://www.skytopia.com/project/articles/compsci/clipping.html 700 // Thanks! 701 // A bit modified to minimize code paths 702 func clipEdge(edge *Edge, bbox BBox) bool { 703 ax := edge.Va.X 704 ay := edge.Va.Y 705 bx := edge.Vb.X 706 by := edge.Vb.Y 707 t0 := float64(0) 708 t1 := float64(1) 709 dx := bx - ax 710 dy := by - ay 711 712 // left 713 q := ax - bbox.Xl 714 if dx == 0 && q < 0 { 715 return false 716 } 717 r := -q / dx 718 if dx < 0 { 719 if r < t0 { 720 return false 721 } else if r < t1 { 722 t1 = r 723 } 724 } else if dx > 0 { 725 if r > t1 { 726 return false 727 } else if r > t0 { 728 t0 = r 729 } 730 } 731 // right 732 q = bbox.Xr - ax 733 if dx == 0 && q < 0 { 734 return false 735 } 736 r = q / dx 737 if dx < 0 { 738 if r > t1 { 739 return false 740 } else if r > t0 { 741 t0 = r 742 } 743 } else if dx > 0 { 744 if r < t0 { 745 return false 746 } else if r < t1 { 747 t1 = r 748 } 749 } 750 751 // top 752 q = ay - bbox.Yt 753 if dy == 0 && q < 0 { 754 return false 755 } 756 r = -q / dy 757 if dy < 0 { 758 if r < t0 { 759 return false 760 } else if r < t1 { 761 t1 = r 762 } 763 } else if dy > 0 { 764 if r > t1 { 765 return false 766 } else if r > t0 { 767 t0 = r 768 } 769 } 770 // bottom 771 q = bbox.Yb - ay 772 if dy == 0 && q < 0 { 773 return false 774 } 775 r = q / dy 776 if dy < 0 { 777 if r > t1 { 778 return false 779 } else if r > t0 { 780 t0 = r 781 } 782 } else if dy > 0 { 783 if r < t0 { 784 return false 785 } else if r < t1 { 786 t1 = r 787 } 788 } 789 790 // if we reach this point, Voronoi edge is within bbox 791 792 // if t0 > 0, va needs to change 793 // rhill 2011-06-03: we need to create a new vertex rather 794 // than modifying the existing one, since the existing 795 // one is likely shared with at least another edge 796 if t0 > 0 { 797 edge.Va.Vertex = Vertex{X:ax + t0*dx,Y: ay + t0*dy} 798 } 799 800 // if t1 < 1, vb needs to change 801 // rhill 2011-06-03: we need to create a new vertex rather 802 // than modifying the existing one, since the existing 803 // one is likely shared with at least another edge 804 if t1 < 1 { 805 edge.Vb.Vertex = Vertex{X:ax + t1*dx,Y: ay + t1*dy} 806 } 807 808 return true 809 } 810 811 func equalWithEpsilon(a, b float64) bool { 812 return math.Abs(a-b) < 1e-9 813 } 814 815 func lessThanWithEpsilon(a, b float64) bool { 816 return b-a > 1e-9 817 } 818 819 func greaterThanWithEpsilon(a, b float64) bool { 820 return a-b > 1e-9 821 } 822 823 // Connect/cut edges at bounding box 824 func (s *Voronoi) clipEdges(bbox BBox) { 825 // connect all dangling edges to bounding box 826 // or get rid of them if it can't be done 827 abs_fn := math.Abs 828 829 // iterate backward so we can splice safely 830 for i := len(s.edges) - 1; i >= 0; i-- { 831 edge := s.edges[i] 832 // edge is removed if: 833 // it is wholly outside the bounding box 834 // it is actually a point rather than a line 835 if !connectEdge(edge, bbox) || !clipEdge(edge, bbox) || (abs_fn(edge.Va.X-edge.Vb.X) < 1e-9 && abs_fn(edge.Va.Y-edge.Vb.Y) < 1e-9) { 836 edge.Va.Vertex = NO_VERTEX 837 edge.Vb.Vertex = NO_VERTEX 838 s.edges[i] = s.edges[len(s.edges)-1] 839 s.edges = s.edges[0 : len(s.edges)-1] 840 } 841 } 842 } 843 844 func (s *Voronoi) closeCells(bbox BBox) { 845 // prune, order halfedges, then add missing ones 846 // required to close cells 847 xl := bbox.Xl 848 xr := bbox.Xr 849 yt := bbox.Yt 850 yb := bbox.Yb 851 cells := s.cells 852 abs_fn := math.Abs 853 854 for _, cell := range cells { 855 // trim non fully-defined halfedges and sort them counterclockwise 856 if cell.prepare() == 0 { 857 continue 858 } 859 860 // close open cells 861 // step 1: find first 'unclosed' point, if any. 862 // an 'unclosed' point will be the end point of a halfedge which 863 // does not match the start point of the following halfedge 864 halfedges := cell.Halfedges 865 nHalfedges := len(halfedges) 866 867 // special case: only one site, in which case, the viewport is the cell 868 // ... 869 // all other cases 870 iLeft := 0 871 for iLeft < nHalfedges { 872 iRight := (iLeft + 1) % nHalfedges 873 endpoint := halfedges[iLeft].GetEndpoint() 874 startpoint := halfedges[iRight].GetStartpoint() 875 // if end point is not equal to start point, we need to add the missing 876 // halfedge(s) to close the cell 877 if abs_fn(endpoint.X-startpoint.X) >= 1e-9 || abs_fn(endpoint.Y-startpoint.Y) >= 1e-9 { 878 // if we reach this point, cell needs to be closed by walking 879 // counterclockwise along the bounding box until it connects 880 // to next halfedge in the list 881 va := endpoint 882 vb := endpoint 883 // walk downward along left side 884 if equalWithEpsilon(endpoint.X, xl) && lessThanWithEpsilon(endpoint.Y, yb) { 885 if equalWithEpsilon(startpoint.X, xl) { 886 vb = Vertex{X:xl,Y: startpoint.Y} 887 } else { 888 vb = Vertex{X:xl, Y:yb} 889 } 890 891 // walk rightward along bottom side 892 } else if equalWithEpsilon(endpoint.Y, yb) && lessThanWithEpsilon(endpoint.X, xr) { 893 if equalWithEpsilon(startpoint.Y, yb) { 894 vb = Vertex{X:startpoint.X, Y: yb} 895 } else { 896 vb = Vertex{X:xr,Y: yb} 897 } 898 // walk upward along right side 899 } else if equalWithEpsilon(endpoint.X, xr) && greaterThanWithEpsilon(endpoint.Y, yt) { 900 if equalWithEpsilon(startpoint.X, xr) { 901 vb = Vertex{X:xr,Y: startpoint.Y} 902 } else { 903 vb = Vertex{X:xr, Y:yt} 904 } 905 // walk leftward along top side 906 } else if equalWithEpsilon(endpoint.Y, yt) && greaterThanWithEpsilon(endpoint.X, xl) { 907 if equalWithEpsilon(startpoint.Y, yt) { 908 vb = Vertex{X:startpoint.X, Y:yt} 909 } else { 910 vb = Vertex{X:xl, Y:yt} 911 } 912 } else { 913 // break 914 } 915 916 // Create new border edge. Slide it into iLeft+1 position 917 edge := s.createBorderEdge(cell, va, vb) 918 cell.Halfedges = append(cell.Halfedges, nil) 919 halfedges = cell.Halfedges 920 nHalfedges = len(halfedges) 921 922 copy(halfedges[iLeft+2:], halfedges[iLeft+1:len(halfedges)-1]) 923 halfedges[iLeft+1] = newHalfedge(edge, cell, nil) 924 925 } 926 iLeft++ 927 } 928 } 929 } 930 931 func (s *Voronoi) gatherVertexEdges() { 932 vertexEdgeMap := make(map[Vertex][]*Edge) 933 934 for _, edge := range s.edges { 935 vertexEdgeMap[edge.Va.Vertex] = append( 936 vertexEdgeMap[edge.Va.Vertex], edge) 937 vertexEdgeMap[edge.Vb.Vertex] = append( 938 vertexEdgeMap[edge.Vb.Vertex], edge) 939 } 940 941 for vertex, edgeSlice := range vertexEdgeMap { 942 for _, edge := range edgeSlice { 943 if vertex == edge.Va.Vertex { 944 edge.Va.Edges = edgeSlice 945 } 946 if vertex == edge.Vb.Vertex { 947 edge.Vb.Edges = edgeSlice 948 } 949 } 950 } 951 } 952 953 // Compute voronoi diagram. If closeCells == true, edges from bounding box will be 954 // included in diagram. 955 func ComputeDiagram(sites []Vertex, bbox BBox, closeCells bool) *Diagram { 956 s := &Voronoi{ 957 cellsMap: make(map[Vertex]*Cell), 958 } 959 960 // Initialize site event queue 961 sort.Sort(VerticesByY{sites}) 962 963 pop := func() *Vertex { 964 if len(sites) == 0 { 965 return nil 966 } 967 968 site := sites[0] 969 sites = sites[1:] 970 return &site 971 } 972 973 site := pop() 974 975 // process queue 976 xsitex := math.SmallestNonzeroFloat64 977 xsitey := math.SmallestNonzeroFloat64 978 var circle *circleEvent 979 980 // main loop 981 for { 982 // we need to figure whether we handle a site or circle event 983 // for this we find out if there is a site event and it is 984 // 'earlier' than the circle event 985 circle = s.firstCircleEvent 986 987 // add beach section 988 if site != nil && (circle == nil || site.Y < circle.y || (site.Y == circle.y && site.X < circle.x)) { 989 // only if site is not a duplicate 990 if site.X != xsitex || site.Y != xsitey { 991 // first create cell for new site 992 nCell := newCell(*site) 993 s.cells = append(s.cells, nCell) 994 s.cellsMap[*site] = nCell 995 // then create a beachsection for that site 996 s.addBeachsection(*site) 997 // remember last site coords to detect duplicate 998 xsitey = site.Y 999 xsitex = site.X 1000 } 1001 site = pop() 1002 // remove beach section 1003 } else if circle != nil { 1004 s.removeBeachsection(circle.arc) 1005 // all done, quit 1006 } else { 1007 break 1008 } 1009 } 1010 1011 // wrapping-up: 1012 // connect dangling edges to bounding box 1013 // cut edges as per bounding box 1014 // discard edges completely outside bounding box 1015 // discard edges which are point-like 1016 s.clipEdges(bbox) 1017 1018 // add missing edges in order to close opened cells 1019 if closeCells { 1020 s.closeCells(bbox) 1021 } else { 1022 for _, cell := range s.cells { 1023 cell.prepare() 1024 } 1025 } 1026 1027 s.gatherVertexEdges() 1028 1029 result := &Diagram{ 1030 Edges: s.edges, 1031 Cells: s.cells, 1032 } 1033 return result 1034 }