77 * @returns polygons [[[x1, y1], [x2, y2], …], …]
88 */
99voronoi = function ( vertices ) {
10- var polygons = vertices . map ( function ( ) { return [ ] ; } ) ,
11- opposite = { "l" : "r" , "r" : "l" } ;
10+ var polygons = vertices . map ( function ( ) { return [ ] ; } ) ;
1211
1312 // Note: we expect the caller to clip the polygons, if needed.
14- var Canvas = {
15- plotEdge : function ( e ) {
16- var s1 ,
17- s2 ,
18- x1 ,
19- x2 ,
20- y1 ,
21- y2 ;
22- if ( e . a == 1 && e . b >= 0 ) {
23- s1 = e . ep [ "r" ] ;
24- s2 = e . ep [ "l" ] ;
25- } else {
26- s1 = e . ep [ "l" ] ;
27- s2 = e . ep [ "r" ] ;
28- }
29- if ( e . a == 1 ) {
30- y1 = s1 ? s1 . y : - 1e6 ;
31- x1 = e . c - e . b * y1 ;
32- y2 = s2 ? s2 . y : 1e6 ;
33- x2 = e . c - e . b * y2 ;
34- } else {
35- x1 = s1 ? s1 . x : - 1e6 ;
36- y1 = e . c - e . a * x1 ;
37- x2 = s2 ? s2 . x : 1e6 ;
38- y2 = e . c - e . a * x2 ;
39- }
40- var v1 = [ x1 , y1 ] ,
41- v2 = [ x2 , y2 ] ;
42- polygons [ e . region [ "l" ] . index ] . push ( v1 , v2 ) ;
43- polygons [ e . region [ "r" ] . index ] . push ( v1 , v2 ) ;
13+ voronoi_tessellate ( vertices , function ( e ) {
14+ var s1 ,
15+ s2 ,
16+ x1 ,
17+ x2 ,
18+ y1 ,
19+ y2 ;
20+ if ( e . a == 1 && e . b >= 0 ) {
21+ s1 = e . ep [ "r" ] ;
22+ s2 = e . ep [ "l" ] ;
23+ } else {
24+ s1 = e . ep [ "l" ] ;
25+ s2 = e . ep [ "r" ] ;
4426 }
45- } ;
27+ if ( e . a == 1 ) {
28+ y1 = s1 ? s1 . y : - 1e6 ;
29+ x1 = e . c - e . b * y1 ;
30+ y2 = s2 ? s2 . y : 1e6 ;
31+ x2 = e . c - e . b * y2 ;
32+ } else {
33+ x1 = s1 ? s1 . x : - 1e6 ;
34+ y1 = e . c - e . a * x1 ;
35+ x2 = s2 ? s2 . x : 1e6 ;
36+ y2 = e . c - e . a * x2 ;
37+ }
38+ var v1 = [ x1 , y1 ] ,
39+ v2 = [ x2 , y2 ] ;
40+ polygons [ e . region [ "l" ] . index ] . push ( v1 , v2 ) ;
41+ polygons [ e . region [ "r" ] . index ] . push ( v1 , v2 ) ;
42+ } ) ;
43+
44+ // Reconnect the polygon segments into counterclockwise loops.
45+ return polygons . map ( function ( polygon , i ) {
46+ var cx = vertices [ i ] [ 0 ] ,
47+ cy = vertices [ i ] [ 1 ] ;
48+ polygon . forEach ( function ( v ) {
49+ v . angle = Math . atan2 ( v [ 0 ] - cx , v [ 1 ] - cy ) ;
50+ } ) ;
51+ return polygon . sort ( function ( a , b ) {
52+ return a . angle - b . angle ;
53+ } ) . filter ( function ( d , i ) {
54+ return ! i || ( d . angle - polygon [ i - 1 ] . angle > 1e-10 ) ;
55+ } ) ;
56+ } ) ;
57+ } ;
58+
59+ /**
60+ * @param vertices [[x1, y1], [x2, y2], …]
61+ * @returns triangles [[[x1, y1], [x2, y2], [x3, y3]], …]
62+ */
63+ delaunay = function ( vertices ) {
64+ var edges = vertices . map ( function ( ) { return [ ] ; } ) ,
65+ triangles = [ ] ;
66+
67+ // Use the Voronoi tessellation to determine Delaunay edges.
68+ voronoi_tessellate ( vertices , function ( e ) {
69+ edges [ e . region [ "l" ] . index ] . push ( vertices [ e . region [ "r" ] . index ] ) ;
70+ } ) ;
71+
72+ // Reconnect the edges into counterclockwise triangles.
73+ edges . forEach ( function ( edge , i ) {
74+ var v = vertices [ i ] ,
75+ cx = v [ 0 ] ,
76+ cy = v [ 1 ] ;
77+ edge . forEach ( function ( v ) {
78+ v . angle = Math . atan2 ( v [ 0 ] - cx , v [ 1 ] - cy ) ;
79+ } ) ;
80+ edge . sort ( function ( a , b ) {
81+ return a . angle - b . angle ;
82+ } ) ;
83+ for ( var j = 0 , m = edge . length - 1 ; j < m ; j ++ ) {
84+ triangles . push ( [ v , edge [ j ] , edge [ j + 1 ] ] ) ;
85+ }
86+ } ) ;
87+
88+ return triangles ;
89+ } ;
90+
91+ var voronoi_opposite = { "l" : "r" , "r" : "l" } ;
92+
93+ function voronoi_tessellate ( vertices , callback ) {
4694
4795 var Sites = {
4896 list : vertices
@@ -125,7 +173,7 @@ voronoi = function(vertices) {
125173 rightRegion : function ( he ) {
126174 return he . edge == null
127175 ? Sites . bottomSite
128- : he . edge . region [ opposite [ he . side ] ] ;
176+ : he . edge . region [ voronoi_opposite [ he . side ] ] ;
129177 }
130178 } ;
131179
@@ -244,8 +292,8 @@ voronoi = function(vertices) {
244292
245293 endPoint : function ( edge , side , site ) {
246294 edge . ep [ side ] = site ;
247- if ( ! edge . ep [ opposite [ side ] ] ) return ;
248- Canvas . plotEdge ( edge ) ;
295+ if ( ! edge . ep [ voronoi_opposite [ side ] ] ) return ;
296+ callback ( edge ) ;
249297 } ,
250298
251299 distance : function ( s , t ) {
@@ -359,7 +407,7 @@ voronoi = function(vertices) {
359407 e = Geom . bisect ( bot , top ) ;
360408 bisector = EdgeList . createHalfEdge ( e , pm ) ;
361409 EdgeList . insert ( llbnd , bisector ) ;
362- Geom . endPoint ( e , opposite [ pm ] , v ) ;
410+ Geom . endPoint ( e , voronoi_opposite [ pm ] , v ) ;
363411 p = Geom . intersect ( llbnd , bisector ) ;
364412 if ( p ) {
365413 EventQueue . del ( llbnd ) ;
@@ -377,20 +425,6 @@ voronoi = function(vertices) {
377425 for ( lbnd = EdgeList . right ( EdgeList . leftEnd ) ;
378426 lbnd != EdgeList . rightEnd ;
379427 lbnd = EdgeList . right ( lbnd ) ) {
380- Canvas . plotEdge ( lbnd . edge ) ;
428+ callback ( lbnd . edge ) ;
381429 }
382-
383- // Reconnect the polygon segments into counterclockwise loops.
384- return polygons . map ( function ( polygon , i ) {
385- var cx = vertices [ i ] [ 0 ] ,
386- cy = vertices [ i ] [ 1 ] ;
387- polygon . forEach ( function ( v ) {
388- v . angle = Math . atan2 ( v [ 0 ] - cx , v [ 1 ] - cy ) ;
389- } ) ;
390- return polygon . sort ( function ( a , b ) {
391- return a . angle - b . angle ;
392- } ) . filter ( function ( d , i ) {
393- return ! i || ( d . angle - polygon [ i - 1 ] . angle > 1e-10 ) ;
394- } ) ;
395- } ) ;
396- } ;
430+ }
0 commit comments