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  }